Inheritance
Inheritance
- Allows us to create hierarchies of classes
- Allows one class to reuse code from another class
Classes Rectangle and Circle
- Let's make some classes for shapes: Rectangle and Circle
class Rectangle1{
private String label;
private int length, width;
public Rectangle1(String lab, int len, int wid){
this.label = lab; this.length = len; this.width = wid;
}
public String getLabel(){return this.label;}
public int getLength(){return this.length;}
public int getWidth(){return this.width;}
public double getArea(){return this.length * this.width;}
}
class Circle1{
private String label;
private int radius;
public Circle1(String lab, int rad){
this.label = lab; this.radius = rad;
}
public String getLabel(){return this.label;}
public int getRadius(){return this.radius;}
public double getArea(){return Math.PI * this.radius * this.radius;}
}
class ShapeTester1{
public static void main(String[] args){
Rectangle1 r = new Rectangle1("A", 5, 10);
Circle1 c = new Circle1("B", 20);
System.out.println(r.getArea() + ", " + c.getArea());
}
}
Reusing Code and a Parent Class
- What code is duplicated in Rectangle1 and Circle1?
- ... - right
- ... - right
- ... - right, but we'll talk about it later
- How to avoid duplicated code?
- Create an inheritance hierarchy with parent class
Shape
Class Shape
- Let's write a class for Shapes
class Shape2{
private String label;
public String getLabel(){return this.label;}
}
Children of Class Shape - First Attempt
- Let's rewrite
Rectangle1 and Circle1 to use the code in Shape
class Rectangle2 extends Shape2{
private int length, width;
public Rectangle2(String lab, int len, int wid){
this.label = lab; this.length = len; this.width = wid;
}
public int getLength(){return this.length;}
public int getWidth(){return this.width;}
public double getArea(){return this.length * this.width;}
}
class Circle2 extends Shape2{
private int radius;
public Circle2(String lab, int rad){
this.label = lab; this.radius = rad;
}
public int getRadius(){return this.radius;}
public double getArea(){return Math.PI * this.radius * this.radius;}
}
class ShapeTester2{
public static void main(String[] args){
Rectangle2 r = new Rectangle2("A", 5, 10);
Circle2 c = new Circle2("B", 20);
System.out.println(r.getArea() + ", " + c.getArea());
}
}
The field label and the method getLabel are inherited by
Rectangle2 and Circle2
Terminology and Pictures
- Parent and Child classes
- Superclass and Subclass
- We need a picture
Superclass Constructor and super(...)
- But wait ... - let's try to compile this!
- The label field is private and so the child can't assign it in the constructor
- Solution:
- Create a constructor in Shape to set the label
- Call the Shape constructor from it's children
- Note the special syntax the child uses for calling the constructor in the parent
- The call to
super must be the first statement in the child constructor
Shape3 - With a Constructor
class Shape3{
private String label;
Shape3(String lab){
this.label = lab;
}
public String getLabel(){return this.label;}
}
class Rectangle3 extends Shape3{
private int length, width;
public Rectangle3(String lab, int len, int wid){
super(lab); // Call Shape3 constructor
this.length = len; this.width = wid;
}
public int getLength(){return this.length;}
public int getWidth(){return this.width;}
public double getArea(){return this.length * this.width;}
}
class Circle3 extends Shape3{
private int radius;
public Circle3(String lab, int rad){
super(lab); // Call Shape3 constructor
this.radius = rad;
}
public int getRadius(){return this.radius;}
public double getArea(){return Math.PI * this.radius * this.radius;}
}
class ShapeTester3{
public static void main(String[] args){
Rectangle3 r = new Rectangle3("A", 5, 10);
Circle3 c = new Circle3("B", 20);
System.out.println(r.getArea() + ", " + c.getArea());
}
}
Polymorphism
- A variable of a parent class type can point to an object of a child class
class ShapeTester3a{
public static void main(String[] args){
Shape s = new Rectangle3("A", 5, 10);
System.out.println(s.getLabel());
s = new Circle3("B", 20);
System.out.println(s.getLabel());
}
}
We call this polymorphism from the Greek for many shapes
That seems like an odd thing to do - why do we want this: for arrays of Shapes!
Shape[] a = new Shape[3];
a[0] = new Circle("A", 5);
a[1] = new Rectangle("A", 10, 20);
a[2] = new Rectangle("A", 30, 40);
for (int i = 0; i < a.length; i++){
System.out.println(a[i].getLabel()
}
More Factoring
- Is there any other code that we can factor into the parent class?
class ShapeTester3a{
public static void main(String[] args){
Shape s = new Rectangle3("A", 5, 10);
System.out.println(s.getArea());
s = new Circle3("B", 20);
System.out.println(s.getArea());
}
}
This looks great, but it does not compile:
- The compiler can't guarantee that a Shape object has a getArea
What's the difference between getLabel and getArea
- getLabel is defined in the parent class
Can we define getArea in the parent?
Yes, but what to put into it?
Solution 1: return a dummy value
Solution 2: make getArea abstract
Y
An Abstract Method and an Abstract Class
- A
Shape does not know how to calculate an area
- Solution: Make getArea() an abstract method in class Shape
- All children MUST implement getArea
- Because it has an abstract method, all children must be abstract
abstract class Shape4{
private String label;
Shape4(String lab){
this.label = lab;
}
public String getLabel(){return this.label;}
public abstract String getLabel(); // This method is abstract
}
class Rectangle4 extends Shape4{
private int length, width;
public Rectangle4(String lab, int len, int wid){
super(lab); // Call Shape4 constructor
this.length = len; this.width = wid;
}
public int getLength(){return this.length;}
public int getWidth(){return this.width;}
public double getArea(){return this.length * this.width;}
}
class Circle4 extends Shape4{
private int radius;
public Circle4(String lab, int rad){
super(lab); // Call Shape4 constructor
this.radius = rad;
}
public int getRadius(){return this.radius;}
public double getArea(){return Math.PI * this.radius * this.radius;}
}
class ShapeTester4{
public static void main(String[] args){
Shape[] a = new Shape[3];
a[0] = new Circle("A", 5);
a[1] = new Rectangle("A", 10, 20);
a[2] = new Rectangle("A", 30, 40);
for (int i = 0; i < a.length; i++){
System.out.println(a[i].getArea()
}
}
OO is easy as PIE
The big three concepts in OO
- Polymorphism
- Inheritance
- Encapsulation