SDSU CS 535: Object-Oriented Programming & Design
Fall Semester, 1997
Doc 9, Inheritance

To Lecture Notes Index
San Diego State University -- This page last updated 29-Sep-97

Contents of Doc 9, Inheritance

    1. References
    2. Inheritance
      1. Super
      2. This Again
      3. Static Methods
      4. Access Levels and Inheritance
      5. Inheritance and Final
      6. Constructors and Inheritance
      7. Class Object
      8. Abstract Classes

References



The Java Programming Language, Arnold and Gosling, 1996, Chapter 3

The Java Language Specification, Gosling, Joy, Steele, 1996, section 6.6

java.lang.Object source code, rohan:/opt/java/src/java/lang/Object.java

Doc 9, Inheritance Slide # 1

Inheritance

class  Parent  {

   public int  parentVariable = 10;

   public  void  parentFunction()  {
      System.out.println(  "Parent Function"  );
   }

}

class  Child  extends  Parent  {

   public  void  childFunction()  {
      parentFunction();
      System.out.println(  "In Child " + parentVariable  );
   }
}

class  Inheritance  {

   public static void main( String args[] ) {
   
      Child  example  =  new Child();
      example.childFunction();
      example.parentFunction();
      System.out.println( example.parentVariable );
   }
}
Output
Parent Function
In Child 10
Parent Function
10

Doc 9, Inheritance Slide # 2
Hiding Fields
class  Parent  {
   public String  name  =  "Parent";
   public int test;
   public  void  parentPrint() {
      System.out.println(  name  );
   }
}

class  Child  extends  Parent  {
   public String  name  =  "Child";
   public String test;

   public  void  print()  {
      System.out.println(  name  );
   }
}

class  HiddenFields  {

   public static void main( String args[] ) {

      Child  whoAmI  =  new Child();

      whoAmI.print();
      whoAmI.parentPrint();

      System.out.println( whoAmI.name );
      System.out.println( ( (Parent ) whoAmI).name );
   }
}
Output
Child
Parent
Child
Parent

Doc 9, Inheritance Slide # 3
Overriding Methods
class  Parent  {
   
   public void print() {
      System.out.println( "In Parent" );
   }
}

class  Child  extends  Parent  {

   public  void  print()  {
      System.out.println( "In Child" );
   }
   
}

class  OverriddingMethods  {
   public static void main( String args[] ) {

      Child  whoAmI  =  new Child();
      whoAmI.print();
      ( ( Parent ) whoAmI).print();
   }
}
Output
In Child
In Child

Doc 9, Inheritance Slide # 4
Terms and Rules

Overloading
Providing more than one method with the same name, but with different signatures

Overriding
A class replacing an ancestor's implementation of a method with an implementation of it own
Signature and return type must be the same
Static methods can not be overridden

Hiding Fields
Giving a field in a class the same name as a field in an ancestor hides the ancestor's field
The field exists, but can not be accessed by its short name
When invoking a method on an object, the actual type of the object is used to determine which method implementation to use, that is the method is determined dynamically

When accessing a field in an object, the declared type of the reference is used to determine which field to use, that is the field is determined statically

Doc 9, Inheritance Slide # 5
Why not the Same rule for Methods and Fields?
This is polymorphism, examples showing why this is good later
class  Parent  {
   public  int  name  =  5;

   public  void  test() {
      System.out.println( "In Parent \t" + (name / 3) );
   }
}

class  Child  extends  Parent  {
   public String  name  =  "Can't divide me";
}
class FieldsMustBeResolveStaticly {

   public static void main( String args[] ) {

      Child  trouble  =  new Child();
      trouble.test();
   }
}



Doc 9, Inheritance Slide # 6
Method vs. Field Access
class  Parent  {
   public String  name  =  "Parent";

   public  void  print() {
      System.out.println( "In Parent \t" + name  );
   }
}

class  Child  extends  Parent  {
   public int  name  =  5;

   public  void  print()  {
      System.out.println( "In Child \t" + (name * 2)  );
   }
}

class  StaticVersesDynamic  {

   public static void main( String args[] ) {

      Child  prodigy  =  new Child();
      prodigy.print();   //Prints   In Child    10
      Console.println( prodigy.name );   //Prints    5

      Parent confused = new Child();
      confused.print();   //Prints   In Child    10
      Console.println( confused.name );   //Prints    Parent

      Parent ok = new Parent();
      ok.print();   //Prints   In Parent    Parent
      Console.println( ok.name );   //Prints    Parent
   }
}

Doc 9, Inheritance Slide # 7
Fancy Accesses
class  Parent  {
   
   private String name = "Parent";
   
   public void print() {
      System.out.println( "In Parent" );    
   }
   
   public void whichGetsCalled() {
      System.out.println( "In whichGetsCalled " + name );
      print();
   }
}

class  Child  extends  Parent  {

   private String name = "Child";
   
   public  void  print()  {
      System.out.println( "In Child" );
   }
}

class  Polymorphism  {
   public static void main( String args[] ) {

      Parent  whoAmI  =  new Child();
      whoAmI.whichGetsCalled();
      whoAmI = new Parent();
      whoAmI.whichGetsCalled();
   }
}
Output
In whichGetsCalled Parent
In Child
In whichGetsCalled Parent
In Parent

Doc 9, Inheritance Slide # 8
Overloading, Overriding and Return Types
class  Parent  {
   
   public void print() {
      System.out.println( "In Parent" );
   }
   
   public void print( String message ) {
      System.out.println( "In Parent" + '\t' + message );
   }

   public void print( int value ) {
      System.out.println( "In Parent" + '\t' + value );
   }
}

class  Child  extends  Parent  {

   public  int  print()  {            // Compiler Error
      System.out.println( "In Child" );
      return 5;
   }

   public void print( String message ) {
      System.out.println( "In Child" + '\t' + message );
   }
}

class  ReturnTypesCount  {
   public static void main( String args[] ) {

      Child  whoAmI  =  new Child();
      whoAmI.print();
      whoAmI.print( "Hi Mom" );
      whoAmI.print( 10 );         // Ok in Java, 
                              // Compile error in C++
   }
}


Doc 9, Inheritance Slide # 9

Super


super
Refers to the superclass of class that implements the method containing the reference to super
All references to super are resolved statically
class  Parent  {
   String  name  =  "Parent";    
   }

class  Child  extends  Parent  {
   String  name  =  "Child";

   public  void  print()  {
      System.out.println(  name  );
      System.out.println(  super.name  );
      System.out.println(  Parent.name  );
   }
}

class  SuperMain  {
   public static void main( String args[] ) {

      Child  whoAmI  =  new Child();
      whoAmI.print();
   }
}
Output
Child
Parent
Parent

Doc 9, Inheritance Slide # 10
More Super
class  Parent  {
   
   public String name = "Parent";
   
   public void print() {  System.out.println( "In Parent" );    }
}

class  Child  extends  Parent  {

   public String name = "Child";
   
   public  void  print()  {
      System.out.println( "In Child" );    
   }
   
   public  void superTest() {
      System.out.println( "In Child test " + super.name );
      super.print(); 
   }      
}

class GrandChild extends Child {

   public String name = "GrandChild";

   public  void  print()  {
      System.out.println( "In GrandChild" );    
   }
}
      
class  SuperIsStatic  {
   public static void main( String args[] ) {

      GrandChild  whoAmI  =  new GrandChild();
      whoAmI.superTest();
   }
}
Output
In Child test Parent
In Parent

Doc 9, Inheritance Slide # 11

This Again


this
references to fields via this are resolved statically
references to methods via this are resolved dynamically
class  Parent  {
   String  name  =  "Parent";

   public  void  print()  {System.out.println( "In Parent" + name ); }

   public  void  thisFunction()  {
      System.out.println(  this.name  );
      this.print();
   }
}

class  Child  extends  Parent  {
   String  name  =  "Child";

   public  void  print() { System.out.println( "In Child " + name ); }
}

class  This  {
   public static void main( String args[] )   {
      Parent  parentThis  =  new Child();
      parentThis.thisFunction();

      Child  childThis  =  new Child();
      childThis.thisFunction();
   }
}
Output
Parent
In Child Child
Parent
In Child Child

Doc 9, Inheritance Slide # 12
super.super and this.
class GrandParent {
   public String bother = "GrandParent";   
}

class Parent extends GrandParent {
   public String bother = "Parent";
}

class  Child  extends Parent {

   public String bother = "Child";
   
   public void bother( String bother ) {
      System.out.println( "bother " + bother );
      System.out.println( "this.bother " + this.bother );
      System.out.println( "super.bother " + super.bother );

      // super.super is a compile error
      //System.out.println( super.super.bother );
   }

   public static void main( String args[] ) {
      Child plays = new Child();
      plays.bother( "Hi" );
   }
}
Output
bother Hi
this.bother Child
super.bother Parent


Doc 9, Inheritance Slide # 13

Static Methods


Static methods reference are resolved statically
class  Parent  {

   public  static  void  classFunction()  {
      System.out.println(  "In Parent"  );
   }

   public  static  void  inheritMe()  {
      System.out.println(  "Inherited"  );
   }
}

class  Child  extends  Parent  {

   public  static  void  classFunction()  {
      System.out.println(  "In Child"  );
   }
}

class  StaticTest  {

   public static void main( String args[] ) {

      Parent  exam  =  new Child();
      exam.classFunction();

      Child  question  =  new Child();
      question.classFunction();
      question.inheritMe();
   }
}
Output
In Parent
In Child
Inherited

Doc 9, Inheritance Slide # 14

Access Levels and Inheritance


Private class members are accessible only in the class they are defined
class Private {
   private String name = "Private";

   public void print() {
      System.out.println( name );
   }

   public void tricky( Private argument ) {
      argument.name = "This access is legal";
   }
}

class Excluded extends Private {

   public void cantPrint() {
      System.out.println( name );    // Compile error
   }
}

class PrivateExample {
   public static void main( String[] args ) {

      Private top = new Private();
      Private bottom = new Private();
      top.tricky( bottom );
      bottom.print();
   }
}
Output (if compile error is removed )
This access is legal

Doc 9, Inheritance Slide # 15
Private and Dynamic Method Binding

Since a private method can not be called from the child, when an inherited method (foo) calls the parent private method (Parent.bar), the parent private method is always the one called

class Madre {
   public void foo() { 
      bar(); 
   }

   private void bar()    { 
      System.out.println( "Madre bar"); 
   }
}

class Hija extends Madre {
   public void bar()  { 
      System.out.println( "Hija bar");
   }

   public void static main( String[] args ) {
      Hija confundido = new Hija ();
      confundido.foo();
   }
}
Output
Madre bar

Doc 9, Inheritance Slide # 16
Protected Access and Inheritance
protected
Accessible in the package that contains the class
Accessible in all subclasses
package Botany;

public class Protected {
   protected String name = "Protected";
}

package Botany;

public class NoRelation {
   public  void  SampleAccess( Protected accessOK )  {
      accessOK.name  =  "This is legal";
   }
}

package  Tree;

public class NoRelationEither {
   public  void  SampleAccess( Botany.Protected noAccess)  {
      noAccess.name  =  "This is a compile Error";
   }
}

package  Tree;

public class Child  extends  Botany.Protected {
   public  void  SampleAccess( Botany.Protected noAccess,
                           Child  accessOK)  {
      name = "This is legal, I am related";
      noAccess.name  =  "This is a compile Error";
      accessOK.name  =  "This is legal";
   }
}

Doc 9, Inheritance Slide # 17
Protected Access and Inheritance: The Rules[1]

Let C be a class with a protected member or constructor.

Let S be a subclass of C in a different package.

The declaration of the use of the protected member or constructor occurs in S.

If the access is of a protected member, let Id be its name
If the access is by a field access expression of the form super.ID, then the access is permitted
If the access is by a qualified name Q.Id, where Q is a type name, then the access is permitted if and only if Q is S or a subclass of S.
If the access is by a qualified name Q.Id, where Q is an expression then the access is permitted if and only if the type of the expression Q is S or a subclass of S
If the access is by a field access expression E.Id, then the access is permitted if and only if the type of E is S or a subclass of S

Doc 9, Inheritance Slide # 18
Package Access and Inheritance
No Explicit Access
Accessible in the package that contains the class
Not accessible outside the package that contains the class
package Botany;

public class NoExplicit {
   String name = "No explicit access level given";
}

package Botany;

public class NoRelation {
   public  void  SampleAccess( NoExplicit accessOK )  {
      accessOK.name  =  "This is legal";
   }
}

package  Tree;

public class NoRelationEither {
   public  void  SampleAccess( Botany.NoExplicit noAccess)  {
      noAccess.name  =  "This is a compile Error";
   }
}

package  Tree;

public class Child  extends  Botany.NoExplicit {
   public  void  SampleAccess( Botany.NoExplicit noAccess,
                           Child  alsoNoAccess)  {
      name = "I am related, but this is NOT LEGAL";
      noAccess.name  =  "This is a compile Error";
      alsoNoAccess.name  =  "This is a compile Error";
   }
}

Doc 9, Inheritance Slide # 19
Inheritance of Access Levels

The access modifier of an overriding method must provide at least as much access as the overridden method
Note

A private method is not accessible to subclasses, so can not be overridden in the technical sense.

Thus a subclass can declare a method with the same signature as a private method in one of its superclasses and there is no requirement that the return type or throws clause of the method bear any relationship to those of the private method in the superclass
class Parent
   {
   protected void foo()  {};

   public void bar() {};

   private void noSeeMe() {};
   }

class Child extends Parent
   {
   public void foo() {};         // OK

   protected void bar() {};      // Compile Error

   public int noSeeMe() throws IOException{ return 5;};   //OK

   }

Doc 9, Inheritance Slide # 20
Rules Are Different for Fields
class Parent
   {
   protected int foo;

   public int bar;
   }

class Child extends Parent
   {
   public int foo;         // OK

   protected int bar;      // OK
   }


Doc 9, Inheritance Slide # 21

Inheritance and Final


The final modifier provides:
Security
Performance optimizations
A class declared to be final, can not have any subclasses

final  class  EndOfTheLine  {

   int  noSubclassPossible;

   public  void  aFunction()  {
      System.out.println(  "Hi Mom"  );
   }
}
class  ThisWillNotWork  extends  EndOfTheLine   {
   int  ohNo;
}

Does not compile


Doc 9, Inheritance Slide # 22
Final Method

A final method can not be overwritten
class  Parent  {

   public  final  void  theEnd()  {
      System.out.println(  "This is it"  );
   }

   public  void  normal()  {
      System.out.println(  "In parent"  );
   }
}

class  Child  extends  Parent  {

   public  void  theEnd()     {         // Compile Error
      System.out.println(  "Two Ends?"  );
   }

   public  void  normal()  {
      System.out.println(  "In Child"  );
   }
}


Doc 9, Inheritance Slide # 23

Constructors and Inheritance

class  Parent  {

   public  Parent()  {
      System.out.println(  "In Parent"  );
   }
}

class  Child  extends  Parent  {

   public  Child()  {
      System.out.println(  "In Child"  );
   }

   public Child( String notUsed ) {
      System.out.println(  "In Child with argument"  );
   }
}

class  Constructors  {

   public static void main( String args[] ) {
      System.out.println(  "Construct Parent"  );
      Parent  sleepy   =  new Parent();

      System.out.println(  "Construct Child"  );
      Child  care  =  new Child();
      care  =  new Child( "Try Me" );
   }
}
Output
Construct Parent
In Parent
Construct Child
In Parent
In Child
In Parent
In Child with argument

Doc 9, Inheritance Slide # 24
Calling Other Constructors
class  Parent  {

   public  Parent(  )  {
      System.out.println(  "In Parent, No Argument"  );
   }

   public  Parent(  String  message  )  {
      System.out.println(  "In Parent"  +  message  );
   }
}

class  Child  extends  Parent  {

   public  Child( String  message,  int  value  )  {
      this(  message  );                      // if occurs must be first
      System.out.println(  "In Child"  );
   }

   public  Child( String  message  )  {
      super(  message  );      // if occurs must be first
      System.out.println(  "In Child"  +  message  );
   }
}

class  Constructors  {
   public static void main( String args[] ) {
      System.out.println(  "Construct Child"  );
      Child  care  =  new Child( ">Start from Child<", 5 );
   }
}
Output
Construct Child
In Parent>Start from Child<
In Child>Start from Child<
In Child

Doc 9, Inheritance Slide # 25

Class Object


All classes inherit from Object
class Parent {
int size;
}

Is short hand for
class Parent extends Object {
int size;
}
class  Parent  {
   int  size;
}

class  TestObject  {

   public static void main( String args[] ) {

      Parent  watchThis  =  new Parent();

      int  myHash  =  watchThis.hashCode();  

      System.out.println(  myHash  );

         // Where does hashCode come from?
   }
}

Doc 9, Inheritance Slide # 26
Object's Methods (minus thread related)

clone()
Creates a clone of the object.

equals(Object)
Compares two Objects for equality.
Uses "==" to test for equality

finalize()
Code to perform when this object is garbage collected.

getClass()
Returns the Class of this Object.

hashCode()
Returns a hashcode for this Object.

toString()
Returns a String that represents the value of this Object.

If a class needs a implementation of equals which differs from the default "equals" the class should override both equals and hashCode

If two different objects satisfy the equals method, the hashCode should return the same value for both objects

Doc 9, Inheritance Slide # 27
Dangerous and Advanced Material
import sdsu.io.Console;

class Foobar {
   public String name = "Skip if this confuses you";
}

class DealingWithClasses {
   public static void main( String[] arguments ) throws 
         ClassNotFoundException, IllegalAccessException, 
         InstantiationException {

      Foobar  example = new Foobar();

      Console.println( example.getClass().getName() );
      Console.println( example.getClass().getSuperclass() );

      // Stop reading while it is still safe
      // Creating  an object from a string
      example = (Foobar) Class.forName( "Foobar" ).newInstance();

      String  whichClass = "java.util.Vector";

      Object interesting = Class.forName( whichClass ).newInstance();
      Console.println( interesting.getClass().getName() );
      
      whichClass = Console.readLine( "Enter a class name" );
      interesting = Class.forName( whichClass  ).newInstance();
      Console.println( interesting.getClass().getName() );
   }
}


Doc 9, Inheritance Slide # 28
Casting and Classes
class  Parent  {  int  data;  }

class  Child  extends  Parent  {  String  name;  }

class  Uncle  {  String  rich;  }

class  Casting {

   public static void main( String args[] )  {
      Object  object;
      Parent  parent;
      Child  child  =  new Child();
      Uncle  uncle;

      parent  =  child;
      object  =  child;
      parent  =  (Parent)  object;
      child  =  (Child)  object;

      uncle  =  (Uncle)  object;   //Runtime exception
      }
}
Output
java.lang.ClassCastException: Child
at Casting.main(All.java:21)


Doc 9, Inheritance Slide # 29

Abstract Classes

abstract  class  NoObjects  {

   int  noDirectObjectPossible  =  5;

   public  void  aFunction()  {
      System.out.println(  "Hi Mom"  );
   }

   public  abstract  void  subClassMustImplement(  int  foo  );
}

class Concrete  extends  NoObjects  {

   public  void  subClassMustImplement(  int  foo  )  {
      System.out.println(  "In Concrete"  );
   }
}

class  AbstractClasses  {

   public static void main( String args[] ) {
      NoObjects  useful  =  new  Concrete();
      Concrete  thisWorks  =  new  Concrete();

      useful.subClassMustImplement( 10 );
      System.out.println(  thisWorks.noDirectObjectPossible  );
   }
}
Output
In Concrete
5



visitors since 29-Sep-97