540 likes | 706 Views
Chapter 4. Inheritance. Two Relations. is-a relationship Examples: Car is a vehicle, PickUpTruck is a Truck. has a relationship (composed-of) Examples: Car has a wheel. Inheritance. Inheritance Used to model the IS-A relationship Used to reuse code among related classes
E N D
Chapter 4 Inheritance
Two Relations • is-a relationship Examples: Car is a vehicle, PickUpTruck is a Truck. • has a relationship (composed-of) Examples: Car has a wheel
Inheritance Inheritance • Used to model the IS-A relationship • Used to reuse code among related classes Containment • Used to model the has-a relationship
Inheritance Mechanism • class Base • { • int n; • public Base() {n=1;} • } • class Derived extends Base • { • int n; • public Derived() { n=10 ;} • public int getValue() {return n ;} • } • To define a subclass – keyword extends class FullName extends Name • Think about the memory layout with inheritance. • What is the memory layout without “extends Base” statement?
Example 1 : Inheritance • class Base • { • int n; • public Base() {n=1;} • } • class Derived • { • int n; • public Derived() { n=10 ;} • public int getValue() {return n ;} • }
Example 1 : Inheritance • public class TestInheritance { • public static void main(String [] args) • { • Base b = new Base(); • Derived d1 = new Derived(); • System.out.println("base value "+b.n); • System.out.println("derived value "+d1.n); • System.out.println("derived value "+d1.getValue()); • } • }
Example 2 : Inheritance • class Base • { • int n; • public Base() {n=1;} • } • class Derived extends Base • { • int n; • public Derived() { n=10 ;} • public int getValue() {return n ;} • }
Example 2 : Inheritance • public class TestInheritance { • public static void main(String [] args) • { • Base b = new Base(); • Derived d2 = new Derived(); • System.out.println("base value "+b.n); • System.out.println("derived value "+d2.n); • System.out.println("derived value "+d2.getValue()); • } • } • Example 1 and Example 2 has the same output, but the memory layouts of Object d1 and d2 are different.
Example 3 : Inheritance • class Base • { • int n; • public Base() {n=1;} • } • class Derived extends Base • { • int n; • public Derived() { n=10 ;} • public int getValue1() {return n ;} • public int getValue2() {return super.n ;} • } • Super key word allows you to access members of Base class
Example 3 : Inheritance • public class TestInheritance { • public static void main(String [] args) • { • Base b = new Base(); • Derived d = new Derived(); • System.out.println("base value "+b.n); • System.out.println("derived value "+d.n); • System.out.println("derived value "+d.getValue1()); • System.out.println("derived value "+d.getValue2()); • } • } • }
Base Class Initialization: Implicit Method 1 • class Base • { int n; • Base() { n = 1 ; } • } • class Derived extends Base • { • int n; • public Derived() { n=10 ;} • } • The default constructor Base() is called before line 4 is executed. • If the user-defined default constructor Base() is not given, a system-defined default constructor is used.
Base Class Initialization: Implicit Method 2 • class Base • { int n; • Base(int nn) { n = nn ; } • } • class Derived extends Base • { • int n; • public Derived() { n=10 ;} • } • Can you find what is wrong with this example?
Base Class Initialization: Explicit Method • class Base • { int n; • Base() { n = 0 ; } • Base(int n) { this.n = n;} • } • class Derived extends Base • { • int n; • public Derived() { super(-1); n=10 ;} • public int getValue1() {return n ;} • public int getValue2() {return super.n ;} • } • Using super() key word, you can explicit choose which super class constructor you want to use.
class Base • { int n; } • class Derived extends Base • { • int n; • public Derived() { n=10 ;} • public int getValue1() {return n ;} • public int getValue2() {return super.n ;} • } • public class TestInheritance { • public static void main(String [] args) • { • Base b = new Base(); • Derived d = new Derived(); • System.out.println("base value "+b.n); • System.out.println("derived value "+d.n); • System.out.println("derived value "+d.getValue1()); • System.out.println("derived value "+d.getValue2()); • } • }
Liskov’s Substitution Principle If for each object O1 of type S there is an object O2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when O1 is substituted for O2 then S is a subtype of T. - Barbara Liskov, “Data Abstraction and Hierarchy”, SIGPLAN Notices, 23, 5 (May, 1988)
Example : LSP • class Person • { • public void getName() {-----------} • } • class Student extends Person • { • public void getName() { -----------} • public double getGPA() {------------} • } Instead of Person p1 = new Person(); p1.getName(); we can use Person p2 = new Student(); p2.getName();
Binding • Binding is a two step operation • Step 1: Static Overloading/Static Binding • Step 2: Dynamic Binding
Binding: Static • Type (Class) of an object determines which method/action you can take on the object. • This is a compile time decision. • Complex a; • a.add(b); // O.K. • a.add(“Hello”); // Error • Static overloading means that the parameters to a method are always deduced statically, at compile time.
Binding : Static • class Base • {private int n; • public Base(int n) { this.n = n ;} • public void showValue() • { System.out.println("Base Class"); } • } • class Derived extends Base • {private int n; • public Derived(int n) { super(-1); this.n =n ;} • public void showValue() • { System.out.println("Derived Class");} • } • public class TestInheritance { • public static void main(String [] args) • {Base b = new Base(10); • Base d = new Derived(10); • b.showValue(); • d.showValue(); • } • }
Binding : Static • In the previous example, you can have both • b.showValue(); • d.showValue(); • It is because • both b and d are of type Base • Type Base allows showValue() action • Q: Why the output is “Base Class” for b.showValue() and “Derived Class” for d.showValue()? A:
Dynamic Binding • Check what is the run-time type of the object. • The virtual machine walks up the inheritance hierarchy until it finds a method of matching signature. • The first method of the appropriate signature is used.
Example : Dynamic Binding • class Base • { • public void foo(Base x) • {System.out.println("Base:Base");} • public void foo(Derived x) • {System.out.println("Base:Derived");} • } • class Derived extends Base • { • public void foo(Base x) • { System.out.println("Derived:Base"); } • public void foo(Derived x) • { System.out.println("Derived:Derived");} • }
Example : Dynamic Binding • public class TestInheritance • { • public static void main(String [] args) • { • Base b = new Base(); • Base d = new Derived(); • b.foo(b); • b.foo(d); • d.foo(b); • d.foo(d); • } • }
Dynamic Binding All methods and parameters are bound at run time in Java except : • static methods • final methods • private methods
Downcasting • Changing the static type of an expression from a base class to a class farther down in the inheritance hierarchy. • double mygpa ; • Person p1 = new Person(); • Person p2 = new Student(); • mygpa = p2.getGPA(); // Error • mygpa = ((Student) p2).getGPA() ; // O.K.
Overriding Overriding – implementing a method in a subclass that has the same signature as a method in the superclass Overriding is based on Dynamic Binding Don’t confuse with Overloading – methods with same name in a class but with different signatures
Example : Overriding • class Base • {private int n; • public Base(int n) { this.n = n ;} • public int getValue() { return n ;} • } • class Derived extends Base • {private int n; • public Derived(int n) {super(5); this.n =n ;} • public int getValue() {return n ;} • } • public class TestInheritance { • public static void main(String [] args) • { • Base b = new Base(10); • Base d = new Derived(10); • System.out.println("base value "+ b.getValue()); • System.out.println("derived value "+d.getValue()); • } • }
Example : Partial Overriding • Use this programming technique, when you want to make a small change in a base class method. • Super class Worker has a method doWork(), but sub class Workaholic is making a small change • public class Workaholic extends Worker • { • public void doWork() • { • super.doWork(); • drinkCoffee(); • super.doWork(); • } • }
final • final methods can not be overridden. • final methods is a more efficient way of programming. • static binding is used for final methods. • final class can not be extended. • Any attempt to override a final method is a compile time error. • All methods in a final class are final methods.
Polymorphism Polymorphism – the same message can evoke different behavior depending on the receiver A reference to the superclass can also reference instances of any subclass NOTE: The reverse is NOT true
Polymorphism Polymorphism – the same message can evoke different behavior depending on the receiver A reference to the superclass can also reference instances of any subclass NOTE: The reverse is NOT true
The Object class Object is the ultimate super class Every class in Java is directly or indirectly derived from the Object class Some methods provided by Object: • toString() • equals() • clone() • hashcode()
public class Object • { • public native int hashCode(); • public boolean equals(Object obj) • { • return (this == obj); • } • protected native Object clone() throws CloneNotSupportedException; • public String toString() { • return getClass().getName() + "@" + • Integer.toHexString(hashCode()); • } • }
Abstract Class Abstract class • A class which can not be instantiated • A class which must be extended to be used • An abstract class generally contains one or more abstract methods. Such a class must be declared as abstract.
Example : Abstract Class • public abstract class Shape • { • public abstract double area(); • public abstract double perimeter(); • public double semiperimeter() • { • return perimeter()/2; • } • }
Interface Interface • Declares features but provide no implementation. • Can be used to define a set of constants. • Every thing is abstract • Used to implement multiple inheritance (No side effect of multiple inheritance) • A class implements an interface
Example : Interface • interface MyInterface • { • void aMethod(int i); // an abstract method • } • class MyClass implements MyInterface • { • public void aMethod(int i) • { • // implementation details • } • } • aMethod(int i) is always public static.
Example : Interface • public interface Constants{ • int ONE=1 ; • public static final int TWO=2; • public static final int THREE=3; • } • The constants ONE, TWO, THREE can be used anywhere in the class implementing Constants. • Constants defined inside interface becomes automatically public static final. System.out.println(Constants.ONE); // O.K.
Example : Interface Find an error in the following declaration of Constants interface. • interface Constants • { • public final int ONE ; • public static final int TWO=2; • public static final int THREE=3; • }
Why Interface? (1) • interface Student{ • float getGPA(); • } • interface Employee{ • float getSalary(); • } • public class StudentEmploy implements Student, Employee{ • public float getGPA() • { // implementation } • public float getSalary() • { // implementation } • } Now, StudentEmploy is both Student and Employee.
Why Interface? (2) Consider. • Student[] students = new Student[10]; • Employee[] employees = new Employee[10]; Since a StudentEmployee can be viewed as both a Student and an Employee, we can use the following statements. • students[0] = new StudentEmployee(); • employees[0] = new StudentEmployee();
Why Interface? (3)Marker Interface • Marker Interfaces are empty interfaces, that is, interfaces that declare no methods or constants. • They are intended to mark classes as having certain properties. • Cloneable interface is a marker interface. • If your class does not implement Cloneable interface, you can not define clone method properly.
Interface : Comparable • public interface Comparable • { • public int compareTo(Object o); • }
Insertion SortInteger Array Insertion-Sort (int [] a) • for (int p=1; p< inarray.length; p++) • { • int tmp = inarray[p]; • int j; • for (j=p; j>0 && inarray[j-1]>tmp; j--) • inarray[j]= inarray[j-1]; • inarray[j]=tmp; • }
Insertion SortComparable Array Insertion-Sort (Comparable [] a) • for( int p=1 ; p < a.length ; p++ ) • { • Comparable tmp = a[p]; • int j ; • for (j=p ; j>0 && tmp.compareTo(a[j-1])<0; j--) • a[j] = a[j-1]; • a[j] = tmp; • }
Four Kinds of Methods final – cannot be overridden (bound at compile-time) abstract – must be overridden (bound at run-time) static – no controlling object (bound at compile-time) other – bound at run-time
Merge Sort, p293 Merge_Sort(A,p,r) if p < r { q [(p+r)/r] Merge_Sort(A,p,q) Merge_Sort(A,q+1,r) Merge(A,p,q,r) } In here, [x] means the largest integer less than or equal to x.
Quick Sort, p295 QuickSort(A,p,r) • if p<r • { • q Partition(A,p,r) • QuickSort(A,p,q) • QuickSort(A,q+1,r) • }
Wrapper Class • Incompatible Types; Comparable [] inarray = new Comparable[10]; inarray[0] = 10; // compile error inarray[1] = 20; // compile error • Correction Integer n1 = new Integer(10); inarray[0] = n1 ; System.out.println(inarray[0]);
List of Wrapper Class • All eight primitive types have wrapper classes. • Short, Integer, Long • Float, Double • Boolean • Byte, Character • Wrapper objects are immutable.