Tutorials
Inheritance
Object oriented languages such as Java provide a mechanism for reusing code known as inheritance.
- Inheritance allows you to take an existing class and specialize it.
- The original class is called the super, base, or parent class (these terms are used interchangeably).
- The class that specializes the base class is called the sub, derived, or child class (these terms are used interchangeably).
- Inheritance is useful because it allows us to:
- reuse existing code without modifying the original code
- create a family of related classes
- treat objects from all the related classes in the same way
Object Class
- All classes in Java are descendants of the Object class.
- The Object class defines a number of methods, e.g.,
- equals() which can be used to see if two objects have the same value.
- toString() which returns a String representation of the object.
- Because every class is a descendant of the Object class, all other classes inherit these methods, i.e., it is possible to call toString() on an object from a class you wrote even if you didn't implement the toString() method.
Suppose we have the following class defined:
public class A { }
Even though the class has no methods explicitly implemented, we can still do the following:
A instance = new A(); System.out.println(instance.toString());
Running this code would produce something like this:
packageName.A@82ba41
- Calling toString() on the instance executes the implementation of toString() found in the Object class.
- The string returned specifies the package name and class name, separated by a period, and then the memory address (in hexadecimal) where the object is stored.
- Essentially, the Object class provides generic behavior for the toString() method... no matter what kind of object we have, we can always describe it with a string containing the package name, class name, and memory location where it is stored.
- When we create a specialized class (one that inherits from Object), it may make sense to rewrite the functionality of toString() that was inherited from Object.
- We can do this be overriding the definition of the toString() method like this:
public class A { public String toString() { return "This is an object from the silliest class I have ever seen"; } }
Running the code below results in This is an object from the silliest class I have ever seen.
A instance = new A(); System.out.println(instance.toString());
- Calling toString() now executes the specialized version of the toString() method that has been customized for the subclass.
Class Declaration Syntax
- Java assumes that we are inheriting from the Object class unless told otherwise.
- The extends keyword is used explicitly identify a superclass.
- Consider the following Shape class:
public class Shape { private Color color; private double xCoord; private double yCoord; public Shape() { color = Color.WHITE; xCoord = 0.0; yCoord = 0.0; System.out.println("Shape: constructor"); } public void draw() { System.out.println("Shape: draw"); } public void erase() { System.out.println("Shape: erase"); } public void move() { xCoord += 5.0; yCoord += 5.0; System.out.println("Shape: move"); } public void zoom(double magnification) { System.out.println("Shape: zoom"); } public Color getColor() { System.out.println("Shape: getColor"); return color; } public void setColor(Color color) { this.color = color; System.out.println("Shape: setColor"); } }
- We can inherit from Shape to create a class that describes a particular type of shape. For example,
public class Circle extends Shape { private double radius; public Circle() { super(); radius = 0.0; System.out.println("Circle: constructor"); } public void draw() { System.out.println("Circle: draw"); } public void erase() { super.erase(); System.out.println("Circle: erase"); } public void zoom(double magnification) { radius *= magnification; System.out.println("Circle: zoom"); } public void setRadius(double radius) { this.radius = radius; System.out.println("Circle: setRadius"); } public double getRadius() { System.out.println("Circle: getRadius"); return radius; } }
- By extending Shape, our Circle class inherits the three fields from.
- Because color, xCoord, and yCoord fields are declare as private, they are not visible in the Circle class, even though they exist as part of a Circle object.
- Notice that the Circle constructor calls the Shape constructor by calling super(). If a superclass has multiple constructors, we can specify the desired constructor by passing the correct parameters to super().
- The Circle class does not implement the getColor() and setColor() methods. The implementations provided by the Shape class are inherited, i.e., used, by the Circle class.
- The Circle class does implement its own versions of draw(), erase(), and zoom(). Rewriting the functionality of a superclass's method is called overriding.
- draw() and zoom() provide a completely new implementation for the Circle class
- erase() makes use of the Shape's erase() implementation by calling super.erase() and then adds some additional functionality.
- getRadius() and setRadius() are additional methods that are only available to the Circle class.
Can you figure out what the following program will display?
public static void main(String[] args) { Shape shape = new Shape(); Circle circle = new Circle(); shape.move(); circle.move(); shape.draw(); circle.draw(); shape.zoom(); circle.zoom(); shape.erase(); circle.erase(); circle.getRadius(); }
Note:
- shape.getRadius() would produce a compiler error because getRadius() is not defined in the Shape class.
- A reference to a Shape may point to a Circle object since a circle can do everything that a shape can do.
- A reference to a Circle may not point to a Shape object since a circle can do more than a shape (like setRadius()).
The is-a Lingo
- Often inheritance is discussed using is-a terminology.
- The terminology is used to help identify when it is appropriate to use inheritance in object oriented design.
- When designed correctly, a subclass object is a superclass object.
- In our previous example, it makes sense to say that a Circle is a Shape.
- Using this terminology may clarify the notes above:
- A reference to a Shape may point to a Circle object since a circle is a shape.
- A reference to a Circle may not point to a Shape since a shape isn't necessarily a circle.
Visibility Modifiers
- We've already discussed the private and public visibility modifiers.
- Attributes (fields or methods) that are declared public are accessible to anyone.
- Attributes that are declared private are only accessible to the class.
- Attributes that are declared protected are accessible to the class and any descendent class.
Last modified: Monday, 29-Jul-2024 06:54:43 EDT