660 likes | 760 Views
Lecture H - Inheritance. Unit H1 - Introduction to Inheritance. Inheritance. Inheritance allows us to derive a new class from an existing one The existing class is called the superclass or base-class. derived class is called the subclass or derived-class .
E N D
Lecture H - Inheritance Unit H1 - Introduction to Inheritance
Inheritance • Inheritance allows us to derive a new class from an existing one • The existing class is called the superclass or base-class. • derived class is called the subclass or derived-class. • Instances of the derived class inherit all the properties and functionality that is defined in the base class. • Usually, the derived class adds more functionality and properties.
Example setTime() getSeconds()getMinutes() getHours() secondElapsed() ... Clock AlarmClock AnalogClock getSecondsPointerAngle()getMinutesPointerAngle() getHoursPointerAngle() setAlarm() setAlarmState()
The is a relationship • Inheritance creates an is-a relationship. AnalogClockis aClock, AlarmClockis a Clock. • Everything that can be done with a Clock object can also be done with an AlarmClock object. • An AnalogClock is a special kind of Clock. It has all the functionality of a clock and some more. • The subclass instances are more specific than the instances of the superclass.
What is inherited and why • Properties of the super-class • Fields, methods • Advantage: code reuse • “white-box” reuse has more power than “black-box” reuse • Obligations of the super-class • Its interface • Advantage: polymorphism – other code can treat objects from the subclass as though they belong to the super-class
Example moveForwards(float size) turnLeft(float teta)turnRight(float teta) tailUp() ... Turtle drawPolygon(int n, float size) drawSquare(float size) IntelligentTurtle
IntelligentTurtle /** * A logo turtle that knows how to draw composite * figures such as polygons. */ public class IntelligentTurtle extends Turtle { /** * Draws a perfect polygon. * @param n The number of edges * @param edgeSize The size of each edge */ public void drawPolygon(int n, double edgeSize) { double teta = 360.0 / n; for (int i=0; i<n; i++) { moveForwards(edgeSize); turnLeft(teta); } } }
Using IntelligentTurtle class PerfectPolygon { static final double EDGE_SIZE = 100.0; static final int NUM_EDGES = 10; public static void main(String[] args) { IntelligentTurtle t = new IntelligentTurtle(); t.tailDown(); t.drawPolygon(n, EDGE_SIZE); } }
When to derive a subclass? • Derived class should normally extend the functionality of the super-class • In certain cases, a derived class would change some of the functionality of the super-class • Don’t use inheritance when black-box use is sufficient • Thumb Rule: Subclass only when it is reasonable from the point of view of the abstractions!
Point Employee TextField Pixel Manager PasswordField Examples Frame Dialog FileDialog
Lecture H - Inheritance Unit H2 - What is inherited?
What is Inherited? • When you derive a class from a given base class: • The subclass inherits all the fields of the base class • It inherits all the methods of the base class • You have to declare the constructors of the subclass from scratch • Public fields and methods of the super-class can be used just like the fields and methods of the subclass • Private fields and methods are inherited but cannot be accessed directly from the code of the subclass
Switch Example Switch • Switch(boolean) • boolean isOn() • setOn(boolean) • isOn
Switch Code /** * An electronic switch that can be on/off. */ public class Switch { // Records the state of the switch private boolean isOn; public Switch(boolean isOn){ this.isOn = isOn; } publicboolean isOn() { return isOn; } publicvoid setOn(boolean state) { isOn = state; } }
on off Switch vs. Adjustable Switch an adjustable switch has a “level of current” dial pressing the adjustable switch turns it on/off
Inheriting AdjustableSwitch from Switch • Switch(boolean) • isOn() • setOn(boolean) Switch • AdjustableSwitch(float) • setLevel(float) • getLevel() AdjustableSwitch
AdjustableSwitch public class AdjustableSwitch extends Switch { private float level; public AdjustableSwitch(float level) { super(level != 0); this.level = level; } public void setLevel(float level) { this.level = level; } public float getLevel() { return isOn() ? level : 0; } }
AdjustableSwitch Example AdjustableSwitch • setOn(boolean) • isOn() • AdjustableSwitch(float) • setLevel(float) • getLevel() • isOn • level
Private Fields - Inherited but not Accessible • Notice that an AdjustableSwitch object has a state variable isOn • This variable is inherited from Switch • However, it cannot be accessed directly from the code of AdjustableSwitch because it is defined as private in Switch - i.e., it is encapsulated
Constructors Must Be Redefined • Constructors are not inherited • They must be redefined in the subclass • The constructor of the sub-class will normally need to use the constructor of the super-class • This is done using the super keyword
Calling super(...) • The constructor of a derived class MUST first initialize the state of the object from the point of view of its parent class. • Thus the first line in the constructor must be either: • a call to a constructor of the super-class using super(...). • A call to another constructor of the subclass using this(…). • If you do not call super(...) or this(..) in the first line of the constructor, the compiler automatically places a call to the empty constructor of the super-class. • If there is no empty constructor in the super-classthe code will not compile!
Automatic Default Construction • If we do not declare any constructor in a class then the compiler automatically adds an empty (default) constructor to it. • In addition, the compiler puts in the first line of the empty constructor a call to the empty constructor of the super-class.
Automatic Default Construction // Assume we didn’t include any constructors previously… // ...in class Switch (automatically added) public Switch() { } //and in class AdjustableSwitch(automatically added) public AdjustableSwitch() { super(); }
Inheritance: a Basis for Code Reusability • Fast implementation - we need not write the implementation of AdjustableSwitch from scratch, we just implement the additional functionality. • Ease of use - If someone is already familiar with the base class, then the derived class will be easy to understand. • Less debugging - debugging is restricted to the additional functionality. • Ease of maintenance - if we need to correct/improve the implementation of Switch, AdjustableSwitch is automatically corrected as well. • Compactness - our code is more compact and is easier to understand.
Lecture H - Inheritance Unit H3 - Overriding Methods
Overriding • In certain case, when we derive a class, we want to change some of the functionality defined in the super-class. • Example: We want clients to be able to open a protected file only if it is unlocked • File(String name) • isOpen() • open() • close() • getName() File • RestrictedFile(String name, long key) • isLocked() • lock() • unlock(long key) RestrictedFile
File // Part of a File implementation public class File { private String name; private boolean isOpen; public File(String name) { this.name = name; // … do something } public String getName() { return name; } publicboolean isOpen() { return isOpen; } public void open() { isOpen = true; // … } publicvoid close() {isOpen = false;// … } // other methods/variables... }
RestrictedFile public class RestrictedFile extends File { private long key; private boolean isLocked; public RestrictedFile(String name, long key) { super(name); this.key = key; isLocked = true; } publicboolean isLocked() { return isLocked; } public void lock() { isLocked = true;} public void unlock(long key) { if (this.key == key) isLocked = false; } // redefine open()!!! }
RestrictedFile – redefining open() /** * Open the file. The file will be opened only if it * is unlocked. */ public void open() { if (!isLocked) { super.open(); } }
Overriding in RestrictedFile • RestrictedFile inherits the interface of File, but changes the functionality of the method open(). • We say that RestrictedFileoverrides the method open(). • Notice the call to super.open() - we invoke the method open() of the super-class on this object.
Rules of Overriding • When you derive a class B from a class A, the interface of class B will be a superset of that of class A (except for constructors) • You cannot remove a method from the interface by sub-classing • However, class B can override some of the methods that it inherits and thus change their functionality. • The over-ridden methods of the super-class are no longer accessible from a variable of the sub-class type. • They can be invoked from within the sub-class definition using the super.method(…) syntax. • The contract of a method states what is expected from an overriding implementation of the method.
Lecture H - Inheritance Unit H4 - The Object class
The Object Class • Java defines the class java.lang.Object that is defined as a superclass for all classes. • If a class doesn’t specify explicitly which class it is derived from, then it will be implicitly derived from class Object. • So, in the previous example, RestrictedFile was derived from File which in turn was derived from Object. • We can depict the relationship between this classes in the following diagram, that is called class hierarchy diagram.
Hierarchy Diagram Object File RestrictedFile
The Object Class • The Object class defines a set of methods that are inherited by all classes. • One of these is the toString() method that is used whenever we want to get a String representation of an object. • When you define a new class, you can override the toString() method in order to have a suitable representation of the new type of objects as Strings. • The contract of the toString() method says that you are expected to return a String that represents your object
Point /** * Represents a point on a grid. */ public class Point { // The coordinates of the point private int x,y; /** * Constructs a new point. * @param x,y The coordinates of the point. */ publicPoint(int x, int y) { this.x = x; this.y = y; } public String toString() { return“(“ + x + ”,” + y + ”)”; } }
Point: Example of Overriding toString() // Example of overriding the toString() method class PrintingPointExample { public static void main(String[] args) { Point p = new Point(2,3); System.out.println(p); //System.out.println(p.toString()); } } The output of the program will be: (2,3)
Other methods defined in Object • boolean equals(Object other) • Tests whether this object is equal to the other object • Object clone() • Creates and returns a clone (copy) of this object • void finalize() • Called by the garbage collector before the object is collected • Various synchronization primitives • A few more
Lecture H - Inheritance Unit H5 - Widening and Narrowing
Sub-classes as sub-types • Recall the is-a relationship induced by inheritance: A RestrictedFileis aFile which is anObject. • We can view a RestrictedFile object from 3 different points of views: • As a RestrictedFile. This is the most narrow point of view (the most specific). This point of view ‘sees’ the full functionality of the object. • As a File. This is a wider point of view (a less specific one). We forget about the special characteristics the object has as a RestrictedFile (we can only open and close the file). • As a plain Object.
Variables can reference subclass values • We view an object by using an object reference. • A variable of type ‘reference to File’ can only refer to any object which is aFile. • But a RestrictedFile is also a File, so f can also refer to a RestrictedFile object. • The type of the reference we use determines the point of view we will have on the object. File f = new RestrictedFile(“story.txt”); File f = new RestrictedFile(“visa.dat”);
RestrictedFile point of view • If we refer to a RestrictedFile object using a RestrictedFile reference we have the RestrictedFile point of view - we see all the methods that are defined in RestrictedFile and up the hierarchy tree. RestrictedFile f = new RestrictedFile(“visa.dat”, 12345); f.close(); f.lock(); f.unlock(12345); String s = f.toString();
File point of view • If we refer to a RestrictedFile object using a File reference we have the File point of view - which lets us use only methods that are defined in class File and up the hierarchy tree. File f = new RestricredFile(“visa.dat”, 12345); f.close(); f.lock(); f.unlock(12345); String s = f.toString();
Object point of view • If we refer to a RestrictedFile object using an Object reference we have the Object point of view - which let us see only methods that are defined in class Object. Object f = new RestrictedFile(“visa.dat”, 12345); f.close(); f.lock(); f.unlock(12345); String s = f.toString();
Points of View RestrictedFile • toString() • ... • isOpen() • open() • close() • lock() • unlock(key) • isLocked() • ... • isOpen • isLocked • key
Compile time-type vs. run-time type • A variable of a reference type has a declared type that is known in compile time and never changes. • File f; • A reference variable may hold values of any subclass of its declared type • The type of the values held may change during the running of the algorithm and is not known during compile time • The run-time type is always some subclass of the compile-time type. f = new RestrictedFile(“visa.dat”,12345); f = new File(“visa.dat”);
Widening • Changing our point of view of an object, to a wider one (a less specific one) is called widening. File file; file = new RestrictedFile(“visa.dat”, 1234); RestrictedFile referenceRestrictedFile point of view File referenceFile point of view Widening
Point -- distanceFrom /** * A point on a grid. */ public class Point { // ... The same implementation as before /** * Computes the distance from another point * @param p The given point. */ public double distanceFrom(Point p) { int dx = x-p.x; int dy = y-p.y; return Math.sqrt(dx*dx+dy*dy); } // ... more methods }
Pixel /** * Represents a pixel on a graphical area. */ public class Pixel extends Point { // The color of the pixel private Color color; /** * Constructs a new pixel. * @param x,y The coordinates of the pixel. * @param color The color of the pixel. */ public Pixel(int x, int y, Color color) { super(x,y); this.color = color; } // ... more methods }
Widening parameters • In the following example, the method distanceFrom() expects a ‘reference to Point’ and gets ‘a reference to Pixel’, we are thus widening our point of view of the Pixel object. Point p1; Pixel p2; p1 = new Point(2, 3); p2 = new Pixel(5, 6, Color.red); double d = p1.distanceFrom(p2);