Inheritance Part 4 Abstract Classes 1 Abstract Classes
Inheritance (Part 4) Abstract Classes 1
Abstract Classes sometimes you will find that you want the API for a base class to have a method that the base class cannot define e. g. you might want to know what a Dog's bark sounds like but the sound of the bark depends on the breed of the dog 2 you want to add the method bark to Dog but only the subclasses of Dog can implement bark
Abstract Classes sometimes you will find that you want the API for a base class to have a method that the base class cannot define e. g. you might want to know the breed of a Dog but only the subclasses have information about the breed 3 you want to add the method get. Breed to Dog but only the subclasses of Dog can implement get. Breed
if the base class has methods that only subclasses can define and the base class has fields common to all subclasses then the base class should be abstract if you have a base class that just has methods that it cannot implement then you probably want an interface abstract : (dictionary definition) existing only in the mind in Java an abstract class is a class that you cannot make instances of 4 e. g. http: //docs. oracle. com/javase/7/docs/api/java/util/Abstract. List. html
an abstract class provides a partial definition of a class the "partial definition" contains everything that is common to all of the subclasses complete the definition an abstract class can define fields and methods subclasses inherit these an abstract class can define constructors subclasses must call these an abstract class can declare abstract methods 5 subclasses must define these (unless the subclass is also abstract)
Abstract Methods an abstract base class can declare, but not define, zero or more abstract methods public abstract class Dog { // fields, ctors, regular methods public abstract String get. Breed(); } the base class is saying "all Dogs can provide a String describing the breed, but only the subclasses know enough to implement the method" 6
Abstract Methods the non-abstract subclasses must provide definitions for all abstract methods 7 consider get. Breed in Mix
public class Mix extends Dog { // stuff from before. . . @Override public String get. Breed() { if(this. breeds. is. Empty()) { return "mix of unknown breeds"; } String. Buffer b = new String. Buffer(); b. append("mix of"); for(String breed : this. breeds) { b. append(" " + breed); } return b. to. String(); } 8
Pure. Breed a purebreed dog is a dog with a single breed one String field to store the breed note that the breed is determined by the subclasses the class Pure. Breed cannot give the breed field a value but it can implement the method get. Breed the class Pure. Breed defines an field common to all subclasses and it needs the subclass to inform it of the actual breed 9 Pure. Breed is also an abstract class
public abstract class Pure. Breed extends Dog { private String breed; public Pure. Breed(String breed) { super(); this. breed = breed; } public Pure. Breed(String breed, int size, int energy) { super(size, energy); this. breed = breed; } 10
@Override public String get. Breed() { return this. breed; } } 11
Subclasses of Pure. Breed the subclasses of Pure. Breed are responsible for setting the breed 12 consider Komondor
Komondor public class Komondor extends Pure. Breed { private final String BREED = "komondor"; public Komondor() { super(BREED); } public Komondor(int size, int energy) { super(BREED, size, energy); } // other Komondor methods. . . } 13
Another example: Tetris played with 7 standard blocks called tetriminoes blocks drop from the top player can move blocks left, right, and down player can spin blocks left and right 14
Tetriminoes spinning the I, J, and S blocks 15
Tetriminoes features common to all tetriminoes has-a color has-a shape has-a position draw move left, right, and down features unique to each kind of tetrimino 16 the actual shape spin left and right
Block • class name in italics for abstract classes - position : IPoint 2 D • an immutable 2 D point - grid : Block. Grid • a grid object that stores the shape + IBlock(IPoint 2 D, Color) • constructor defines the shape + spin. Left() • methods modify the shape to produce the rotated version of the block - color : Color + draw() + move. Down() + move. Left() + move. Right(). . . IBlock + spin. Right() 17 http: //www. eecs. yorku. ca/course_archive/2013 -14/F/1030/labs/06/lab 6. html
Inheritance (Part 5) Static Features; Interfaces 18
Static Fields and Inheritance static fields behave the same as non-static fields in inheritance public and protected static fields are inherited by subclasses, and subclasses can access them directly by name private static fields are not inherited and cannot be accessed directly by name 19 but they can be accessed/modified using public and protected methods
Static Fields and Inheritance the important thing to remember about static fields and inheritance there is only one copy of the static field shared among the declaring class and all subclasses consider trying to count the number of Dog objects created by using a static counter 20
// the wrong way to count the number of Dogs created public abstract class Dog { // other fields. . . protected, not private, so that static protected int num. Created = 0; subclasses can modify it directly Dog() { //. . . Dog. num. Created++; } public static int get. Number. Created() { return Dog. num. Created; } // other contructors, methods. . . } 21
// the wrong way to count the number of Dogs created public class Mix extends Dog { // fields. . . Mix() { super(); Mix. num. Created++; } // other contructors, methods. . . } 22
// too many dogs! public class Too. Many. Dogs { public static void main(String[] args) { Mix mutt = new Mix(); System. out. println( Mix. get. Number. Created() ); } } prints 2 23
What Went Wrong? there is only one copy of the static field shared among the declaring class and all subclasses Dog declared the static field Dog increments the counter everytime its constructor is called Mix inherits and shares the single copy of the field Mix constructor correctly calls the superclass constructor 24 which causes num. Created to be incremented by Dog Mix constructor then incorrectly increments the counter
Counting Dogs and Mixes suppose you want to count the number of Dog instances and the number of Mix instances Mix must also declare a static field to hold the count 25 somewhat confusingly, Mix can give the counter the same name as the counter declared by Dog
public class Mix extends Dog { // other fields. . . private static int num. Created = 0; // bad style public Mix() { super(); // will increment Dog. num. Created // other Mix stuff. . . num. Created++; // will increment Mix. num. Created } //. . . 26
Hiding Fields note that the Mix field num. Created has the same name as an field declared in a superclass whenever num. Created is used in Mix, it is the Mix version of the field that is used if a subclass declares an field with the same name as a superclass field, we say that the subclass field hides the superclass field considered bad style because it can make code hard to read and understand 27 should change num. Created to num. Mix. Created in Mix
Static Methods and Inheritance there is a significant difference between calling a static method and calling a non-static method when dealing with inheritance there is no dynamic dispatch on static methods 28 therefore, you cannot override a static method
public abstract class Dog { private static int num. Created = 0; public static int get. Num. Created() { return Dog. num. Created; } } public class Mix { private static int num. Mix. Created = 0; public static int get. Num. Created() { return Mix. num. Mix. Created; } } public class Komondor { private static int num. Komondor. Created = 0; public static int get. Num. Created() { return Komondor. num. Komondor. Created; } } 29 notice no @Override
public class Wrong. Count { public static void main(String[] args) { Dog mutt = new Mix(); Dog shaggy = new Komondor(); System. out. println( mutt. get. Num. Created() ); System. out. println( shaggy. get. Num. Created() ); System. out. println( Mix. get. Num. Created() ); System. out. println( Komondor. get. Num. Created() ); } } prints 2 2 1 1 30
What's Going On? there is no dynamic dispatch on static methods because the declared type of mutt is Dog, it is the Dog version of get. Num. Created that is called because the declared type of shaggy is Dog, it is the Dog version of get. Num. Created that is called 31
Hiding Methods notice that Mix. get. Num. Created and Komondor. get. Num. Created work as expected if a subclass declares a static method with the same name as a superclass static method, we say that the subclass static method hides the superclass static method 32 you cannot override a static method, you can only hide it hiding static methods is considered bad form because it makes code hard to read and understand
the client code in Wrong. Count illustrates two cases of bad style, one by the client and one by the implementer of the Dog hierarchy 1. 2. 33 the client should not have used an instance to call a static method the implementer should not have hidden the static method in Dog
- Slides: 33