Sie sind auf Seite 1von 118

Java I--Copyright © 2000-2002 Tom Hunter

Chapter 9
Object-Oriented Programming:
Part II

Java I--Copyright © 2000-2002 Tom Hunter


Implicit
Subclass-object
to
Superclass-object
Conversion
Java I--Copyright © 2000-2002 Tom Hunter
• Joe was feeling entrepreneurial, and so he
decided to buy a piece of land in Arkansas.

• Joe paid $50 for what the deed described as a


wooden shack in the swamp.

• But, to his great surprise, when he got there,


Joe discovered he hadn’t bought a shack in a
swamp, but rather, the Taj Mahal on a beautiful
lake. Joe was ecstatic.

• Joe got more than he was promised.


Java I--Copyright © 2000-2002 Tom Hunter
• Mary was feeling entrepreneurial, and so she
decided to buy a huge Mansion on an estate in
Arkansas.

• Mary paid $5 Million for what the deed


described as a palatial estate on 40 acres.

• But, to her great surprise, found she hadn’t


bought a magnificent Mansion and estate, but
rather, a Doublewide trailer next to a dump.
Mary was horrified.

• Mary got less than was promised. Java I--Copyright © 2000-2002 Tom Hunter
• Joe’s situation is akin to Referring to a
Subclass object with a Superclass
reference.

You get more than you expected.


It’s a pleasant surprise.

SuperclassRef = new SubclassObject

Java I--Copyright © 2000-2002 Tom Hunter


• Mary’s situation is akin to Referring to a
Superclass object with a Subclass reference .

You get less than you expected.


It’s a tragic mistake.

SubclassRef = new SuperclassObject

Java I--Copyright © 2000-2002 Tom Hunter


Implicit Subclass-object to Superclass-object Conversion
• There are four possible conversions that can occur:

1.) Refer to a
Superclass object with a
Superclass reference.

This is routine

Java I--Copyright © 2000-2002 Tom Hunter


Implicit Subclass-object to Superclass-object Conversion

2.) Refer to a
Subclass object with a
Subclass reference.

This is also routine

Java I--Copyright © 2000-2002 Tom Hunter


Implicit Subclass-object to Superclass-object Conversion

3.) Refer to a
Subclass object with a
Superclass reference

This is safe because the Subclass object is an object of


its Superclass.

Such code can only refer to Superclass methods.


Java I--Copyright © 2000-2002 Tom Hunter
Why might want to do that?

Suppose many classes inherit from one Superclass.


• You can make an array of Superclass
references.
• Then, you can treat them all the same,
as if they really were all Superclass
objects.
• As long as you call methods that exist in
the Superclass (but were overridden
by each of the various Subclasses),
then the runtime system calls the
correct overridden method for each one!
Java I--Copyright © 2000-2002 Tom Hunter
This process is known as...

Java I--Copyright © 2000-2002 Tom Hunter


Implicit Subclass-object to Superclass-object Conversion

4.) Refer to a
Superclass object with a
Subclass reference .

This is a syntax error! It doesn’t make sense. It is only


remotely possible if the Subclass is explicitly cast into a
Superclass reference, which is a way of telling the
compiler you are doing this damn-fool thing with your
eyes open.
Java I--Copyright © 2000-2002 Tom Hunter
Implicit Subclass-object to Superclass-object Conversion

So, why is that a problem?

Here’s the problem:


A Subclass contains more and does more than its
Superclass parent.

If you use a Subclass reference to point to a


Superclass object, you are implying that the object has more
data variables available than it really does—and if someone
made that assumption—they would be sorely mistaken.

Java I--Copyright © 2000-2002 Tom Hunter


The Right Way
to Use
Polymorphism

Java I--Copyright © 2000-2002 Tom Hunter


class Employee
{ Employee is our
private String ssn;
Superclass. As we see,
public Employee() it contains the instance
{
ssn = ""; variable String
} ssn, a Constructor, the
public Employee( String soc_num ) Accessor method
{
ssn = soc_num;
getSSN() and the
} empty method
public String getSSN() calcPay(), which
{ we will need to
return ssn;
} override in all the
Subclasses because
public double calcPay()
{ they will all need to
return 0;
}
calculate pay
} differently.
Java I--Copyright © 2000-2002 Tom Hunter
class HourlyEmployee extends Employee
{ Instance variables
double hourlyRate;
int hoursWorked; specific to the Subclass
public HourlyEmployee()
{ Default Constructor
hourlyRate = 0.0;
hoursWorked = 0;
}

public void setHourlyRate( double rate )


{
hourlyRate = rate;
}
The overridden method
inherited from the
public void setHoursWorked( int hours )
{ Superclass.
hoursWorked = hours;
}

public double calcPay()


{
return hourlyRate * hoursWorked;
}
} Java I--Copyright © 2000-2002 Tom Hunter
public class DemoPolymorphism
{
double pay = 0;
public DemoPolymorphism()
{
Employee supEmp = new HourlyEmployee();
HourlyEmployee subHrEmp = new HourlyEmployee();

pay = supEmp.calcPay();
System.out.println( "Superclass pay = " + pay );

subHrEmp.setHourlyRate( 5.65 );
subHrEmp.setHoursWorked( 20 );
pay = subHrEmp.calc_Pay();
System.out.println( "Subclass pay = " + pay );

supEmp = subHrEmp;
pay = supEmp.calcPay();
We declare a reference to "Superclass
System.out.println( an object ofpay = "Employee
type + pay );
called }public
supEmp. However,
static we String[]
void main( instantiate an)
args
HourlyEmployee
{ object and assign the reference to the
DemoPolymorphism demo = new DemoPolymorphism();
Superclass Employee.
System.exit( This
0 ); works because—after all—
}
HourlyEmployee
} is an Employee. Java I--Copyright © 2000-2002 Tom Hunter
public class DemoPolymorphism
{
double pay = 0;
public DemoPolymorphism()
{
Employee supEmp = new HourlyEmployee();
HourlyEmployee subHrEmp = new HourlyEmployee();

pay = supEmp.calcPay();
System.out.println( "Superclass pay = " + pay );

subHrEmp.setHourlyRate( 5.65 );
subHrEmp.setHoursWorked( 20 );
pay = subHrEmp.calc_Pay();
System.out.println( "Subclass pay = " + pay );

supEmp = subHrEmp;
pay = supEmp.calcPay();
System.out.println( "Superclass pay = " + pay );
}
public static void main( String[] args )
{
DemoPolymorphism demo = new DemoPolymorphism();
System.exit( 0 );
}
} Java I--Copyright © 2000-2002 Tom Hunter
Superclass pay = 0.0
Subclass pay = 113.0
Superclass pay = 113.0
Press any key to continue . . .

Java I--Copyright © 2000-2002 Tom Hunter


The Wrong Way to Use
Polymorphism—a Syntax
Error—(Without An
Explicit Cast)

Java I--Copyright © 2000-2002 Tom Hunter


public class CastSubTypeReftoSuperTypeObject
{
double pay = 0;
public CastSubTypeReftoSuperTypeObject()
{ // Syntax Error ! ! !
HourlyEmployee subHrEmp = new Employee(); // Error!

// The error is not yet revealed.


pay = subHrEmp.calcPay();
System.out.println( "Subclass pay = " + pay );

// Error because the object doesn’t have these


// methods available.
subHrEmp.setHourlyRate( 5.67 );
subHrEmp.setHoursWorked( 20 );
pay = subHrEmp.calcPay();
System.out.println( "Subclass pay = " + pay );
}
In the program, we know
public static that subHrEmp
void main( String[] argswas
) declared as a
type HourlyEmployee.
{ But instead of getting a Mansion
CastSubTypeReftoSuperTypeObject demo;
(HourlyEmployee), the reference was assigned to a
demo = new CastSubTypeReftoSuperTypeObject();
Doublewide Trailer (Employee).
System.exit( 0 ); The object doesn’t have these
} and these message calls won’t work!
methods
} Java I--Copyright © 2000-2002 Tom Hunter
C:\CastSubTypeReftoSuperTypeObject.java:59:
Incompatible type for declaration.
Explicit cast needed to convert Employee to HourlyEmployee.
HourlyEmployee subHrEmp = new Employee(); // Error!
^
1 error

Tool completed with exit code 1

At this point, the compiler is extremely unhappy.


So, let’s give it what it is specifically asking for
—an explicit cast—and see what happens then.

Java I--Copyright © 2000-2002 Tom Hunter


public class CastSubTypeReftoSuperTypeObject
{
double pay = 0;
public CastSubTypeReftoSuperTypeObject()
{ // Now we’ve Band-Aided the Error with An
// Explicit cast
HourlyEmployee subHrEmp;
subHrEmp = (HourlyEmployee) new Employee();

// The error is not yet revealed.


pay = subHrEmp.calcPay();
System.out.println( "Subclass pay = " + pay );

// Error because the object doesn’t have these


// methods available.
subHrEmp.setHourlyRate( 5.67 );
subHrEmp.setHoursWorked( 20 );
pay = subHrEmp. calcPay();
System.out.println( "Subclass pay = " + pay );
}
public static void main( String[] args )
{
CastSubTypeReftoSuperTypeObject demo;
demo = new CastSubTypeReftoSuperTypeObject();

System.exit( 0 ); Java I--Copyright © 2000-2002 Tom Hunter


Exception in thread "main"
java.lang.ClassCastException: Employee at
CastSubTypeReftoSuperTypeObject.<init>(CastS
ubTypeReftoSuperTypeObject.java:60) at
CastSubTypeReftoSuperTypeObject.main(CastSub
TypeReftoSuperTypeObject.java:75)

Press any key to continue . . .

At this stage, the compiler is incensed—it


trusted us when we asked for that Explicit cast,
and look what happened.

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism
and
Dynamic Binding

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism and Dynamic Binding
Say that we have a bunch of objects that are
all Shapes:
Circles,
Squares,
Triangles,
Trapezoids, etc.
If we want to draw them all, we could use a
large switch statement that asks if the
object is a circle, do this. If a square, do this.
If a triangle, do that...

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism and Dynamic Binding
The big switch could work okay, but if
we decided to add a parallelogram to our
shapes, then we would have to remember to
add another branch to our switch statement.

Every place we wanted to do some


behavior based on the shape, we would have
to change our logic.

What a pain!
Java I--Copyright © 2000-2002 Tom Hunter
Polymorphism and Dynamic Binding
Polymorphism can save us that
trouble—and make programs that will work
with Shapes that hadn’t even been thought of
when the class was written.

With Polymorphism, the objects


themselves know what kind of object they are,
and they do the right behavior based on their
internal awareness of their own type!

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism and Dynamic Binding

In our Shapes example, we could assume


that each shape Subclass that inherits off of the
master Superclass—Shape—would have a
draw() method.

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism and Dynamic Binding
That draw() method would detail
exactly how to generate the Square or the
Circle or the Triangle.
Each shape subclass knows how to draw
itself.
Certainly, we could go through the
trouble of drawing each Shape one by one.

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism and Dynamic Binding
But… wouldn’t it be nice if we could
just treat all those various Shape Subclasses
as copies of the Superclass?

Then, we could create an array of


Superclass references that actually are
initialized with Subclass objects.

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism and Dynamic Binding
We could move through the array calling
the draw() method of the Superclass for
each element in the array.

The overridden draw() methods in


each Subclass shape could take care of
drawing the shape the right way.
Easy, right?

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism and Dynamic Binding

Therefore, to make this work, the only thing


we have to remember is:

• Declare draw() in the Superclass.

• Then, override draw() in each of the


Subclasses to draw the correct Shape.

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism and Dynamic Binding
• The Run-Time Type Identification system
will choose the correct subclass’s
draw() method dynamically—i.e.,
on-the-fly— at execution time.

• This is called dynamic method binding,


and it makes Polymorphism work.

Polymorphism relies on Dynamic Binding.

Java I--Copyright © 2000-2002 Tom Hunter


Polymorphism and Dynamic Binding

Polymorphism.

• Allows you to process Superclass


objects in a Generic way.

• Only the parts of a program that need


specific knowledge of the new class
must be tailored specifically to the
new class.
Java I--Copyright © 2000-2002 Tom Hunter
final Variables,
final Methods
and
final Classes

Java I--Copyright © 2000-2002 Tom Hunter


final Variables, final Methods and final Classes

• final variables—means they can’t be


changed after they are declared.

( These variables must be initialized


when they are declared. )

Java I--Copyright © 2000-2002 Tom Hunter


final Variables, final Methods and final Classes

• final methods—means they can’t be


overridden in any subclass.

• This allows the compiler to “inline” the


code, or remove the overhead of the method
call.

Java I--Copyright © 2000-2002 Tom Hunter


final Variables, final Methods and final Classes

• Declaring a method
static or
private
automatically makes it final .

Java I--Copyright © 2000-2002 Tom Hunter


final Variables, final Methods and final Classes

• final class. This means that nothing can


ever inherit from this class.

• A final class can never be a Superclass,


which is another way of saying it can never
spawn any Subclasses.

Java I--Copyright © 2000-2002 Tom Hunter


final Variables, final Methods and final Classes

• We also point out that all the methods in a


final class might as well be final (they are)
because they can never be overridden.

Therefore:
“A class declared final cannot be
extended and every method is implicitly
final.”
Java I--Copyright © 2000-2002 Tom Hunter
Opposite of
final
class is an
abstract
Superclass
Java I--Copyright © 2000-2002 Tom Hunter
abstract Superclass
• Whereas a final class CANNOT ever be a
Superclass (meaning, no Subclass can ever inherit from it)

• An abstract Superclass MUST be


Subclassed.

• I.e., an abstract Superclass can’t be


instantiated.

Java I--Copyright © 2000-2002 Tom Hunter


abstract Superclass
• The whole point of making an abstract
Superclass is so it will be Subclassed.

What Do We Need abstract Superclasses?


• An abstract Superclass defines a common
interface for the many Subclasses.

• It forces the Subclasses to all be build in a


similar way.
Java I--Copyright © 2000-2002 Tom Hunter
abstract Superclass
• Although an abstract Superclass can
have instance variables and Constructor
methods, all of its other methods are
declared as abstract .

Java I--Copyright © 2000-2002 Tom Hunter


abstract class

vs.

concrete class

Java I--Copyright © 2000-2002 Tom Hunter


abstract Superclass

• shape is a generic class. Since shape


really can’t even draw itself, we would
never want to instantiate a “shape ”.

• Instead, we would always choose to


instantiate some other specific kind of
shape—such as a Square, Circle
or Rectangle—that could draw itself.

Java I--Copyright © 2000-2002 Tom Hunter


abstract Superclass

• shape is merely the template, and thus,


it presents a good candidate for being an
abstract class.

Java I--Copyright © 2000-2002 Tom Hunter


abstract Superclass
• If a class has any method that is abstract,
then the class MUST be abstract.

• Whenever you decide to Subclass a class


from that abstract Superclass, then you
MUST override any method that is defined as
abstract.

Java I--Copyright © 2000-2002 Tom Hunter


abstract Superclass
• If you don’t override that abstract method,
then it is inherited in your subclass.

• It is inherited as an abstract method and, in


turn, it contaminates your Subclass.

• It makes your class—by default—also an


abstract class.

Java I--Copyright © 2000-2002 Tom Hunter


public class MustBeAbstract
{
public abstract void doSomething();
}

This class contains a method that is abstract.


Therefore, the method:
1) Cannot contain a “body” and,
2) The entire class must be declared abstract.
Java I--Copyright © 2000-2002 Tom Hunter
public abstract class MustBeAbstract
{
public abstract void doSomething();

These three things must be in place to


successfully make an abstract class.
Java I--Copyright © 2000-2002 Tom Hunter
abstract class MustBeAbstract
{
public abstract void doSomething();
}

public class TestAbstract


{
public static void main( String args[] )
{
MustBeAbstract mba = new MustBeAbstract();
System.exit( 0 );
}
}
• Here we are trying toclass
C:\TestAbstract.java:11: instantiate this abstract
MustBeAbstract is an class.
abstract class. It can't be instantiated.
• As we expected, the compiler
MustBeAbstract mba = newcomplains loudly.
MustBeAbstract();
^
1 error

Java I--Copyright © 2000-2002 Tom Hunter


abstract class MustBeAbstract
{
public abstract void doSomething();
}
class SubMustBe extends MustBeAbstract
{
public void anotherThing()
{
}
}
public class TestAbstract
{
public static void main( String args[] )
{
SubMustBe smb = new SubMustBe();
System.exit( 0 );
}
} • So, we will create a subclass and
see if
that makes the compiler any happier.
Java I--Copyright © 2000-2002 Tom Hunter
C:\TestAbstract.java:5:
class SubMustBe must be declared abstract.
It does not define void doSomething() from
class MustBeAbstract.
class SubMustBe extends MustBeAbstract
^

C:\TestAbstract.java:15:
Whatiswent
class SubMustBe wrong? class.
an abstract
It can't
Well, be we didn’t override the abstract
instantiated.
since
SubMustBe
method smb = new we
doSomething(), SubMustBe();
inherited
^ our class
the abstract method into
2 errors
SubMustBe. Since we had a method that
was abstract, the whole class had to be
declared abstract.
Java I--Copyright © 2000-2002 Tom Hunter
abstract class MustBeAbstract
{
public abstract void doSomething();
}
class SubMustBe extends MustBeAbstract
{
public void doSomething()
{
}
}
public class TestAbstract
{
public static void main( String args[] )
{
SubMustBe smb = new SubMustBe();
System.exit( 0 );
}
}
• Now we have overridden the abstract
method and the compiler is happy.
Java I--Copyright © 2000-2002 Tom Hunter
abstract Superclass

One last issue remains:


• We now know that we cannot instantiate an
abstract class.

• But… can we create a reference to an


abstract class?
Absolutely!

Java I--Copyright © 2000-2002 Tom Hunter


abstract Superclass

Why might we want to create a reference to an


abstract class?

To create an array and use


Polymorphism!

Java I--Copyright © 2000-2002 Tom Hunter


A Payroll System
using
Polymorphism

Java I--Copyright © 2000-2002 Tom Hunter


A Payroll System using Polymorphism

( Turn to page 414)

• The following example will show how one would


design a Payroll system using an abstract class and
abstract methods.

Java I--Copyright © 2000-2002 Tom Hunter


// Abstract base class Employee [ page 414 ]
public abstract class Employee This class Employee is
{
private String firstName; abstract because it
private String lastName; contains the abstract
last )earnings(),
method
public Employee( String first, String
{
firstName = first;
which therefore must be
lastName = last; overridden in any class
}
that expects to inherit
public String getFirstName() { return from Employee
firstName; } .
public String getLastName() { return lastName; }
public String toString() We chose to make
earnings()
{ return firstName + ' ' + lastName; } abstract
public abstract double earnings(); because we need to
} calculate earnings
differently depending on
the kind of employee.
Java I--Copyright © 2000-2002 Tom Hunter
public final class Boss extends Employee
{
private double weeklySalary;

public Boss( String first, String last, double s)


{
super( first, last ); // call superclass constructor
setWeeklySalary( s );
}

public void setWeeklySalary( double s )


{
weeklySalary = ( s > 0 ? s : 0 );
}
This method overrides
public double earnings()
{ the abstract method
return weeklySalary; inherited from the
} Superclass.
public String toString()
{
return "Boss: " + super.toString();
}
} Java I--Copyright © 2000-2002 Tom Hunter
A Payroll System using Polymorphism

( Turn to page 418)

• The driver application Test.java shows


Polymorphism in action.

• It shows how we use the Superclass reference.

• Although we’re doing the same thing as we process


through the various employees, each one is calculating its
own pay in a different way!

Java I--Copyright © 2000-2002 Tom Hunter


public class Test
{
public static void main( String args[] )
{
Employee ref; // superclass reference
String output = "";

Boss b = new Boss( "John", "Smith", 800.00 );


CommissionWorker c = new CommissionWorker( "Sue", "Jones", … 150);
PieceWorker p = new PieceWorker( "Bob", "Lewis", 2.5, 200 );
HourlyWorker h = new HourlyWorker( "Karen", "Price", 13.75, 40 );

ref = b; // Employee reference to a Boss


output += ref.toString() + " earned $" + ref.earnings();

ref = c; // Employee reference to a CommissionWorker


We start off making a
output += ref.toString() + " earned $” + ref.earnings();
reference to the abstract
ref = p; // Employee reference to a PieceWorker
output += ref.toString() + " earned Superclass Employee.
$" + ref.earnings();

ref = h; // Employee reference toRemember, although we can’t


an HourlyWorker
output += ref.toString() + " earned $" + ref.earnings();
instantiate an abstract class,
we sure can make a reference
System.out.println( “” + output );
System.exit( 0 );
} to one.
} Java I--Copyright © 2000-2002 Tom Hunter
public class Test
{
public static void main( String args[] )
{
Employee ref; // superclass reference
String output = "";

Boss b = new Boss( "John", "Smith", 800.00 );


CommissionWorker c = new CommissionWorker( "Sue", "Jones", … 150);
PieceWorker p = new PieceWorker( "Bob", "Lewis", 2.5, 200 );
HourlyWorker h = new HourlyWorker( "Karen", "Price", 13.75, 40 );

ref = b; // Employee reference to a Boss


output += ref.toString() + " earned $" + ref.earnings();
Next, we go ahead and
ref = c; // Employee reference to a CommissionWorker
instantiate each of the
output += ref.toString() + " earned $” + ref.earnings();

Subclasses
ref = p; // Employee reference to a and assign them to
PieceWorker
output += ref.toString() + " earned $" + ref.earnings();
appropriate references for the
ref = h; // Employee reference to an HourlyWorker
various types of Employee.
output += ref.toString() + " earned $" + ref.earnings();

System.out.println( “” + output );
System.exit( 0 );
}
} Java I--Copyright © 2000-2002 Tom Hunter
public
We class each
reassign Test of these Employee Subclasses to the Superclass.
{
Using thestatic
public Superclass reference
void main( ref,
String we call
args[] ) the methods toString()
{ earnings() that also exist in the Superclass. The Runtime
and Employee ref; // superclass reference
identifies
Stringthat—in
output =fact—this
""; ref reference is really pointing to a
different kind of object. So the Runtime performs the correct overridden
Boss b = new Boss( "John", "Smith", 800.00 );
methods.
CommissionWorker c = new CommissionWorker( "Sue", "Jones", … 150);
PieceWorker p = new PieceWorker( "Bob", "Lewis", 2.5, 200 );
HourlyWorker h = new HourlyWorker( "Karen", "Price", 13.75, 40 );

ref = b; // Employee reference to a Boss


output += ref.toString() + " earned $" + ref.earnings();

ref = c; // Employee reference to a CommissionWorker


output += ref.toString() + " earned $” + ref.earnings();

ref = p; // Employee reference to a PieceWorker


output += ref.toString() + " earned $" + ref.earnings();

ref = h; // Employee reference to an HourlyWorker


output += ref.toString() + " earned $" + ref.earnings();

System.out.println( “” + output );
System.exit( 0 );
}
} Java I--Copyright © 2000-2002 Tom Hunter
public class Test
{
public static void main( String args[] )
{
Employee ref; // superclass reference
String output = "";

This is
Boss b = new Boss( "John", "Smith", 800.00 );
CommissionWorker c = new CommissionWorker( "Sue", "Jones", … 150);
PieceWorker p = new PieceWorker( "Bob", "Lewis", 2.5, 200 );

Dynamic
HourlyWorker h = new HourlyWorker( "Karen", "Price", 13.75, 40 );

ref = b; // Employee reference to a Boss


output += ref.toString() + " earned $" + ref.earnings();

Method
ref = c; // Employee reference to a CommissionWorker
output += ref.toString() + " earned $” + ref.earnings();

Binding
ref = p; // Employee reference to a PieceWorker
output += ref.toString() + " earned $" + ref.earnings();

ref = h; // Employee reference to an HourlyWorker


output += ref.toString() + " earned $" + ref.earnings();

System.out.println( “” + output );
System.exit( 0 );
}
} Java I--Copyright © 2000-2002 Tom Hunter
A Payroll System using Polymorphism

• If we had made ref an array, then this could have been


done even easier.

• As we have seen, this can save you a lot of work.

• You write one driver program and it performs correctly


without you having to code anything.

• The objects—through their overridden methods—make


sure the right behavior happens!

Java I--Copyright © 2000-2002 Tom Hunter


Inheriting
Interface
and
Implementation

Java I--Copyright © 2000-2002 Tom Hunter


Inheriting Interface and Implementation
( Turn to page 421)

• This example shows how the abstract Superclass Shape


[ abstract because the method getName() is declared as
abstract and thus so must be the class ]
defines the interface of all the objects that are
Subclassed from it it.

Java I--Copyright © 2000-2002 Tom Hunter


Inheriting Interface and Implementation
• Along with the abstract method getName() that of
course must be overridden, Shape contains two other
methods area() and volume().

• Neither area() nor volume()are declared abstract so


they may—if desired—be inherited directly without being
overridden.

Java I--Copyright © 2000-2002 Tom Hunter


Inheriting Interface and Implementation
• We describe this situation as being the interface merely
because Shape gets to set the pace for its Subclasses.

• For example, Point inherits from Shape .

• Point overrides the getName() method (as it must) but


it can live with the area() and volume() methods in
Shape .

• The generic implementations in Shape are correct for


Point .

Java I--Copyright © 2000-2002 Tom Hunter


Inheriting Interface and Implementation
( Turn to page 424)

• In the driver program, lines 140, 143 & 146 we see how
an array of type Shape has been declared, and each
element in the array has been initialized to hold a
different one of the Subclasses.

• This allows them all to be treated in a polymorphic


way.

Java I--Copyright © 2000-2002 Tom Hunter


Creating
an
Interface

Java I--Copyright © 2000-2002 Tom Hunter


Creating an Interface
• When we used Shape in the previous example, we
employed Inheritance .

• There is an alternative to using Inheritance, and it is


called using an Interface.

• You are already quite familiar with interfaces—you’ve


used them to handle events.

Java I--Copyright © 2000-2002 Tom Hunter


interface
“A Java programming language
keyword used to define a collection
of method definitions and constant
values. It can later be implemented
by classes that define this interface
with the "implements" keyword.”

Java I--Copyright © 2000-2002 Tom Hunter


Creating an Interface
• To use an Interface, you must do two things:

• Use the implements keyword

• Override every method the interface has.

• If the implementing class fails to override any one


method, then that method is inherited and the
implementing class becomes abstract.

Java I--Copyright © 2000-2002 Tom Hunter


Creating an Interface
• You might choose to use an Interface instead of an
abstract class when there is no default implementation to
inherit.

1—No instance variables to inherit.


2—No default method implementations.

When points 1 and 2 are true, it means you would


be better off creating an Interface rather than inheriting
an abstract class.

Java I--Copyright © 2000-2002 Tom Hunter


public interface Shape
{
public abstract double area();
public abstract double volume();
public abstract getName();
}

Java I--Copyright © 2000-2002 Tom Hunter


package java.awt.event;

/* ActionListener.java 1.6 */
This is the actual code from Sun
import java.util.EventListener;
Microsystems that creates the
/** ActionListener
* The listener interface for receiving action events.
*
* @version 1.6 11/23/96
* @author Carl Quinn
*/

public interface ActionListener extends EventListener


{
/**
* Invoked when an action occurs.
*/
public void actionPerformed(ActionEvent e);
}

Java I--Copyright © 2000-2002 Tom Hunter


package java.util;

/* EventListener.java */

/* A tagging interface that all event


* listener interfaces must extend
*/

public interface EventListener


{
}

Finally, this is the code that creates


the EventListener. This organizes
everything that follows.

Java I--Copyright © 2000-2002 Tom Hunter


Creating an Interface
• You may not understand the reason to implement an
interface, if it doesn’t contain any code.

• However the real reason we bother is because you can


implement multiple interfaces in one class.

Java I--Copyright © 2000-2002 Tom Hunter


Creating an Interface: Putting It Together
MySuper ms = new MySub();

MyInterface mi = new MyImplMyInterface();

• If the reference type is an INTERFACE, the object it


refers to MUST be an object from a class which
implements the interface—either directly or through
inheritance.

Java I--Copyright © 2000-2002 Tom Hunter


Inner
Classes:
“Getting In Touch with
Your Inner Class”

Java I--Copyright © 2000-2002 Tom Hunter


“Getting in Touch with Your Inner Class”*

Being an object like me isn't as fun as you might


think.

It gets lonely...

Out here...
on the heap...
alone.

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”

Not to mention the horror—the


emotional devastation—when you feel
your last reference slip away and it hits
you—you've just become food for the
garbage collector

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”

But you know what helps? Having an


inner class. An inner class can ease the
loneliness... as long as somebody makes
an instance of that inner class. All I
really want is someone to bond with.

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”

Someone to share my most private


thoughts (and variables and methods).
Someone who knows EVERYTHING
about me. An intimate relationship
shared between two objects -- an outer
and an inner.

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”

I'm very protective of my inner class. If


somebody wants to instantiate my inner
class, they MUST go through me—an
object of the outer class.

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”

My inner class can't exist on its own. I,


as an instance of the outer class, can live
on my own (however unhappily). You
don't have to make an instance of an
inner class in order to have an instance
of the outer class. But you can NEVER
make an instance of my inner class
without an outer object to "bind" it to.

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”
My inner class needs me.
We have that special bond.
It makes life on the garbage-collectible
heap bearable.

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
class Outer
{
private int size ;
private String thoughts = "My outer thoughts";

class Inner
{
String innerThoughts = "My inner thoughts";

void doStuff()
{
// inner object has its own "this"
System.out.println( innerThoughts );

// and it also has a kind of "outer this"


// even for private data of outer class
System.out.println(thoughts);
}
} OK, but nothing really happens until somebody
}
makes an instance of BOTH classes...
Java I--Copyright © 2000-2002 Tom Hunter
class TestMe
{
public static void main( String args[] )
{
// instantiate me, the outer object
Outer o = new Outer();

}
Java I--Copyright © 2000-2002 Tom Hunter
class TestMe
{
public static void main( String args[] )
{
// instantiate me, the outer object
Outer o = new Outer();

// Inner i = new Inner();


// NO! Can't instantiate Inner by itself!

}
Java I--Copyright © 2000-2002 Tom Hunter
class TestMe
{
public static void main( String args[] )
{
// instantiate me, the outer object
Outer o = new Outer();

// Inner i = new Inner();


// NO! Can't instantiate Inner by itself!

Outer.Inner i = o.new Inner();


// now I have my special inner object
i.doStuff();
// OK to call methods on inner object
}

}
Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”

You can also instantiate both the outer class and inner
class at the same time:

Inner i = new Outer().new Inner();

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
That shows you need an outer object, so that you
can ask it to make an inner object. In this example, you
didn't even keep a reference to the outer object... only the
inner object i.
The inner object i still knows its outer object... its
"outer this".
By the way, there is no keyword "outer this” —that's
just a concept for the way inner objects behave.

They behave as if the outer object's variables were


their own.)

Java I--Copyright © 2000-2002 Tom Hunter


“Getting in Touch with Your Inner Class”
I hate static!
You've probably heard about static inner classes. Well,
they don't deserve to be called inner classes!
A static inner class (an inner class marked as static)
looks like this:
class Outer
{
static class Inner
{
}
}

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”

I don't like them because they don't give me that


special object-to-object bond.

In fact, static inner classes aren't even supposed to


be called inner classes at all.

Technically, they are "top-level nested classes".

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
“Getting in Touch with Your Inner Class”

A static nested class can be instantiated, but the


object created doesn't share any special relationship with
an outer object.
The static nested class is tied only
to the outer class, not an instance of
the outer class.
Outer.Inner i = new Outer.Inner();

* Adapted from http://www.javaranch.com/campfire/StoryInner.jsp


Java I--Copyright © 2000-2002 Tom Hunter
Inner
Classes

Java I--Copyright © 2000-2002 Tom Hunter


Inner Classes
• The ability to create Inner Classes was added to Java
with version 1.1.

• They are useful because they let you create a class close
to where they are needed and are being used—inside
another class.

• You can define an inner class:


—inside another class,
—inside a method or even
—as part of an expression.
• Still, they behave just like any other class.
Java I--Copyright © 2000-2002 Tom Hunter
Inner Classes
• Inner classes can…
—extend other classes and
—implement interfaces.

• They come in four types:


1— Static Inner Classes ( nested classes)
2—Member Inner Classes
3—Local Inner Classes
4—Anonymous Inner Classes

Java I--Copyright © 2000-2002 Tom Hunter


Inner Classes
• Until now, all classes have been defined at file scope,
where they are the outermost layer.

• Using Inner Classes, it is possible to nest one class


within another one.

• Inner classes have the following characteristics:


—They can access all the instance variables of the
so-called Outer Class.
—They do not need any special handles.

Java I--Copyright © 2000-2002 Tom Hunter


Inner Classes
• Inner classes can be either named or anonymous.
—An anonymous inner class is frequently
designated as the object that will do the
event handling for an object.

—Also, you can have a separate inner class for


every object that needs events handled.

Java I--Copyright © 2000-2002 Tom Hunter


Inner Classes
• Whenever we used the event-handling model, we have
been careful to stress what it takes to be an event
handler.

—the class has to implement the correct interface


of the Event Handler.
—In the case of the ActionListener interface,
the “handler” class only had to override
the method:
actionPerformed( ActionEvent e )
—This was required because this method was
declared abstract.
Java I--Copyright © 2000-2002 Tom Hunter
Inner Classes
• Well, any class that meets those requirements can be
an event handler.

• After you declare your inner class someplace in your


outer public class, you need to instantiate the inner class.

• Usual place is in the main() method.

Java I--Copyright © 2000-2002 Tom Hunter


private class ActionEventHandler
implements ActionListener
{
public void actionPerformed( ActionEvent e )
{
// do something with ‘e’
}
} • Usually, the Inner class object is not much more
complicated that this.
• Notice it is declared as private
• However, this only declares this “named” Inner class.
• Now we need to instantiate it.
• This class implements an ActionListener, so it is an
ActionListener.
ActionEventHandler handler = new ActionEventHandler();
button.addActionListener( handler );
Java I--Copyright © 2000-2002 Tom Hunter
button.addActionListener( new ActionListener()
{
public void actionPerformed(Ac
{
// do something with ‘e’
}
}
• Usually, it is possible to skip the declaring of the name.

• You can create a so-called “anonymous” inner class by


just declaring at the last second right in the place where
you need it.

Java I--Copyright © 2000-2002 Tom Hunter


button.addActionListener( new ActionListener()
{
public void actionPerformed(Ac
{
// do something with ‘e’
}
}
• The entire object is there, it just is doing what we need it
without any extra work.

• Since the previous class merely implemented the


ActionListener, then that class is an ActionListener.

• So, as long as our Inner Class also is an ActionListener,


we are still okay.

Java I--Copyright © 2000-2002 Tom Hunter


Inner Classes
• Named inner classes can be public, protected, private or
have package access.

• Every class—even an Inner Class—must have its own


file that ends in .class.

• When you compile a class that contains an Inner Class,


it makes a separate file.

Java I--Copyright © 2000-2002 Tom Hunter


Inner Classes
• Every class—even an Inner Class—must have its own
file that ends in .class.

• When you compile a class that contains an Inner Class,


it makes a separate file.
public class MyClass
{
private class MyInner
{
MyClass.class
}
} MyClass$MyInner.class
• If this class is saved in a file called MyClass.java,
it creates two class files. Java I--Copyright © 2000-2002 Tom Hunter
import javax.swing.*;
import java.awt.*;
import java.awt.event.*; This is the setup we’re
public class MyClass extends JApplet
more used to. One public
{
Container c; class MyClass with
JButton but; another class in the same
public void init() file, MyAction.
{
c = getContentPane(); This results in:
MyClass.class
but = new JButton( "Handle" ); and
MyAction act = new MyAction();
but.addActionListener(MyAction.class.
act );
c.add( but ); Notice, the closing
}
}
brackets of each are
outside of each other.
class MyAction implements ActionListener
{
public void actionPerformed( ActionEvent e )
{ System.out.println( "Out" );
}
} Java I--Copyright © 2000-2002 Tom Hunter
import javax.swing.*; Now, we have the setup that
import java.awt.*;
import java.awt.event.*; produces the most basic “named”
public class MyClass extendsInner
JApplet
class. Just by moving the
{
Container c; closing curly bracket so as to
JButton but; enclose MyAction inside of
public void init() MyClass, we have created two
{
classes—one inner and the other
c = getContentPane();
but = new JButton(
the "Handle" );
typical animal.
MyAction act = new MyAction();
This results
but.addActionListener( act );in:
c.add( but ); MyClass.class and
} MyClass$MyAction.class
class MyAction implements ActionListener
{
public void actionPerformed( ActionEvent e )
{ System.out.println( "Out" );
}
}
} Java I--Copyright © 2000-2002 Tom Hunter
import
Finally,javax.swing.*;
if we just transfer the entire MyAction structure to
import java.awt.*;
the inside
import of the: but.addActionListener() structure,
java.awt.event.*;
public
we haveclass MyClass extends
our anonymous JApplet
inner class:
{
MyClass.class
Container c;
and MyClass$1.class
JButton but;
public void init()
{
c = getContentPane();
but = new JButton( "Handle" );
//MyAction act = new MyAction(); // not needed
but.addActionListener(
new ActionListener()
Also, now {
ActionListener is a public void actionPerfor
{ System.out.println( "O
Constructor, so we need }
to add these parentheses }
);
c.add( but );
} Java I--Copyright © 2000-2002 Tom Hunter
Java I--Copyright © 2000-2002 Tom Hunter

Das könnte Ihnen auch gefallen