CS535 Object-Oriented Programming & Design
Fall Semester, 1996
Inheritance
[To Lecture Notes Index]
San Diego State University -- This page last updated Sep 24, 1996

Contents of Inheritance
- References
- Inheritance
- Super
- This Again
- Static Methods
- Access Levels and Inheritance
- Inheritance and Final
- Constructors and Inheritance
- Class Object
- Abstract Classes
- Interfaces
Core Java, Chapter 4
The Java Programming Language, Arnold and Gosling, 1996, Chapters 3 and
4
The Java Language Specification, Gosling, Joy, Steele, 1996, section
6.6
java.lang.Object source code, rohan:/opt/java/src/java/lang/Object.java
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
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
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
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 simple 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
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 );
}
}
class StaticVersesDynamic {
public static void main( String args[] ) {
Child prodigy = new Child();
prodigy.print(); //Prints In Child 5
Console.println( prodigy.name ); //Prints 5
Parent confused = new Child();
confused.print(); //Prints In Child 5
Console.println( confused.name ); //Prints Parent
Parent ok = new Parent();
ok.print(); //Prints In Parent Parent
Console.println( ok.name ); //Prints Parent
}
}
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
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++
}
}
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
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 = "Child";
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
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
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
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
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";
}
}
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
No Explicit 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";
}
}
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
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" );
}
}
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
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
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?
}
}
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
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() );
}
}
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)
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
"Conducting" is when you draw "designs" in the nowhere - with your stick, or
with your hands - which are interpreted as "instructional messages" by guys
wearing bow ties who wish they were fishing.
- Frank Zappa
The public methods of classes can be thought of as units of design
Classes combine design and implementation
Interfaces can specify public methods but can have no implementation of
methods
Interfaces can have variables, but they are static and final
Interfaces give a type of multiple inheritance
Interface Example
In file Flyer.java:
public interface Flyer {
public boolean hasWings();
}
In file test.java:
interface Mammal {
static boolean hasLungs = true;
public boolean hasLegs();
}
interface Noisy extends Mammal {
public boolean hasBark();
}
class Dog implements Noisy {
public boolean hasLegs() {
return true;
}
public boolean hasBark() {
return true;
}
}
// file test.java continued
class Bird implements Mammal, Flyer {
public boolean hasLegs(){
return true;
}
public boolean hasWings() {
return true;
}
}
class InterfaceExample {
public static void main( String args[] ) {
Bird robin = new Bird();
Flyer crow = new Bird();
Noisy fido = new Dog();
Mammal fifi = new Noisy(); //Compiler Error
robin.hasLegs();
robin.hasWings();
boolean test = robin.hasLungs;
crow.hasLegs(); //Compile Error
}
}
Interfaces and Name Conflicts
public interface Left { public void truth(); }
public interface Right { public boolean truth(); }
class Congress implements Left, Right {
public ???? truth() { }
}
Method Name Conflicts
If a class implements two interfaces that each have a method with the same
name, say foo, then
- if both foo' s have different signatures, then the class implements two
overloaded foo methods
-
- if both foo' s have the same signature and same return type, then the class
implements only the one foo
-
- if both foo' s have the same signature and different return types, then the
class can not implement both interfaces
-
- if both foo' s have the same signature, same return type but differ in the
types of exceptions they throw, then the class implements only the one foo, but
it must contain the exceptions both foo's
If a class implements two interfaces that each have a field with the same
name, say bar, then the class has to use the full names for the fields.