Вы находитесь на странице: 1из 8

Polymorphism and Inheritance

Motivation (If you're convinced inheritance is cool, you can skip this)

Let's say we're writing a program with various kinds of clocks : Cuckoo clocks, digital clocks, grandfather clocks etc. They're all clocks but they have these additional properties that don't apply to clocks in general. A cuckoo clock would have a Cuckoo() method that starts the chirping. How would you write this class, which is a clock with one extra method?

One solution is to modify our existing clock definition and add on an extra function. These classes are exactly the same except for that one function. If we did this for all our clocks, we'll end up writing a separate class definition for every type of clock. And if we made a mistake in our original Clock definition, we'll have to copy and paste across all our clocks to fix it.

The solution to this problem is polymorphism the ability to create multiple forms of the same thing but still presenting the same interface to a client. Cuckoo, digital and grandfather clocks can all tell time so in most contexts they still look like Clocks to a user. But they can also have expanded functionality.

Inheritance

In Java a class can extend any other class. In fact, all classes in java have at least one superclass, the

Object class. Represents an is-a relationship.

A subclass inherits all the public and protected variables and methods that the super class has. Private

variables remain offhands.

Public - everyone can access it, like the name of a bank Private- only this class can access it, like a banks balance Protected subclasses can access it, like a bank's internal ID number

listing: BankBranch.java

class Bank{

private int balance;

protected int bankID;

public String bankName;

public Bank(String name, int balance, int bankID){

this.balance = balance;

this.bankID = bankID;

this.bankName = name;

}

}

public class BankBranch extends Bank{

public BankBranch(String name, int balance, int bankID){

super(name, balance, bankID);

}

public int getBalance(){

return balance;

}

public int getBankID(){

return bankID;

public static void main(String[] args){

}

public String getBankName(){

return bankName;

}

BankBranch b = new BankBranch("Chase", 54, 10282);

System.out.println(b.getBalance());

System.out.println(b.getBankID());

System.out.println(b.getBankName());

}

If you try to compile this, you get a compile time error :

BankBranch.java:23: balance has private access in Bank

return balance;

Because balance is a private variable, not even subclasses can access it. But, bankId is protected so subclasses can reference it.

-Constructors for subclasses always calls the constructor for the superclass with super(). This must be the first line of the constructor. This keeps in line with the whole idea that subclasses are the base class plus something more. If you don't call the super constructor, either super() or super ( int a, int b ….parameters) , java will automaticall add super() as the first line of the constructor. This causes problems when super() doesn't exist.

Cuckoo_Clock.java

class Clock{ int minute; int hour; public Clock(int minute, int hour){ this.minute = minute; this.hour = hour;

}

}

public class Cuckoo_Clock extends Clock{ public Cuckoo_Clock(int minute, int hour){ this.minute = minute; this.hour = hour;

}

public static void main(String[] args){ Cuckoo_Clock c = new Cuckoo_Clock(4, 3);

}

}

Here the issue is that Cuckoo_Clock doesn't call super(minute, hour) so java sticks in super(). But super() doesn't exist so we get a compile time error.

Remember, inheritance defines an Is-A relationship.

Static vs Dynamic, and Dynamic Method Dispatch

When you instantiate something, you do something like:

tube t = new tube(); But if pipe is a super class of tube, we can make instantiations like pipe p = new tube(); but which methods get called? The super or the sub class'? We always call the methods of the dynamic type. Just remember, Static is whats on the left side, dynamic is whats on the right side of the equals sign.

//Static : Tube

Dynamic : Tube

Tube t

=

new Tube()

//Static :Pipe

Dynamic : Tube

Pipe p

=

new Tube()

But when we use the “ . “ dot operator, to access a variable, we get the variables from the class' static type. You can change a class' static type by (type casting) it to another data type. But dynamic type never changes. Just remember Static Variables, Dynamic Methods Shadowing.java

class pipe{ int level = 1; public int carry(int b){ return b;

}

public int getLevel(){ return level;

}

}

class tube extends pipe{ int level = 2;

public int carry(int a){ return level + a;

}

public int getLevel(){ return level;

}

public int TubePressure(){ return 10282;

}

}

public class Shadowing{ public static void main(String[] args){ tube t = new tube();

// dynamic type : Tube, uses Tube.carry() => Output: 12

System.out.println(t.carry(10));

pipe p = (pipe)t;

//static type of p : Pipe, dynamic type: Tube. Uses Tube.carry() => Output: 12

System.out.println(p.carry(10));

//static type of p : pipe, we modify t's Pipe level but his Tube level is unchanged

p.level = 50;

//dynamic type : Tube. Uses Tube.carry() => Output: 12

System.out.println(p.carry(10));

// dot operator uses static vars: => Output: 50 System.out.println(p.level);

//dynamic type : Tube, uses Tube.getLevel => Output: 2 System.out.println(p.getLevel());

}

}

This confusion with p.level and p.getLevel() makes it look like there's two versions of the same variable. This is shadowing and it's a bug in java. For this reason, try to make your variables private whenever you can. Tinker around with this class. For example, if we hadn't defined a Tube.getLevel(), we would use Pipe.getLevel(), which returns 50.

What are static and dynamic types? Static means whats decided on compile time. The compiler uses the type on the left side of the = to decide if all the types match up. Dynamic type is used to deicde which method to invoke. This is dynamic method dispatch.

One more thing about casting between sub and super classes. It's always safe to cast a class to it's super class but it isn't always safe to cast from a super to a sub class.

Tube is a subclass of pipe. So any method that works in Pipe will with Tube. Pipe p = (Pipe) t;

This upcast is safe and is even done for you automatically. So a method public static boolean PipeCheck(Pipe p1, Pipe p2){

return p1.getLevel() == p2.getLevel();

}

you can pass Tubes and it will work fine.

But the opposite is not true. An Aqueduct is a Pipe and a Tube is a Pipe but an Aqueduct is not a Tube.

So a cast like

Aqueduct a = (Aqueduct) t;

Will get a ClassCast Exception. These downcasts are unsafe and have to be done manually. You can check if something is an instance of a class with instanceof

public static boolean isAqueduct(Pipe p){

return p instanceof Aqueduct;

}

Interfaces and Abstract Classes

An interface is an abstract type that forces a class to implement certain methods. If we know that a class implements an interface, then we know how to talk (or interface) to this class : through it's required methods. Think of an interface as a “can-do” relationship

An abstract class can be extended, and can have some kind of default implementation. Extending an abstract class still defines “is-a”. Methods declared to be abstract are required to be instantiated.

Differences between interfaces and abstract classes:

 

Interfaces

Abstract Classes

Multiple Inheritance

Implement several interfaces

Only one abstract class

Default code

An interface can't provide code, just a signature for a method that must be over ridden

Can provide complete default code, or just the signature, like an interface

Instance variables

All class variables in an interface become static and final.

Can have class variables

Access modifiers

All interface methods have to be public

Abstract classes get public, private, protected

Use interfaces to define common, peripheral abilities of a class but use abstract classes for common abilities that make up the core identitiy of the class.

For example, I'd use an interface Movable for a Car class and a Bicycle. Movable is something they both do but it's done in completely different ways. But I'd use an abstract class InternalCombustionVehicle for a Sedan and a SUV because the way they move is similar.

TrickyInterfaces.java

interface Edible { public Edible eat(int e);

}

interface Cookable extends Edible{ public int cookTime(int e); public String dishName(int e);

}

interface Compostable extends Edible{ public Edible compost(int c);

}

public class TrickyInterfaces implements Cookable{

}

What methods must Tricky Interfaces implement?

TrickyInterfaces must implement eat(int e), cookTime(int e), dishName(int e).

Note that you can use interfaces as a return type. Also, interfaces cannot implement other interfaces. When you implement an interface,you promise Java that you will give the required methods some kind of implementation but interfaces can't have implementation, just signatures.