Inheritance Organizing Classes of Files Promoting Reuse of Code Polymorphism The Purpose of Java Interfaces An interface organizes java class files by using inheritance. Any class that implements an interface must have all of the methods that are listed in the interface. Those classes must either provide code for each method or state that a subclass will provide them. The Java List Interface Java provides the List interface and numerous classes implement it. One class is the ArrayList class and another is the LinkedList class. If you use either the ArrayList or LinkedList classes in a program, you call the same methods, like size(), add(obj), add(i, obj), remove(i), set(i, obj), and get(i). But there is different code for these methods in each one of the classes. In other words, the code for add(obj) in the ArrayList class is different from the add(obj) code in the LinkedList class but you call them the same way. These classes use different approaches to implement these methods with the LinkedList class striving to be more efficient by storing data dynamically instead of statically. You won’t learn about that in detail until Adv. Comp. Programming. java.util.List The List interface is part of the java.util package. So if you need to declare an ArrayList variable of type List you do it as follows: List <Student> shapes = new ArrayList <Student> ( ); and you need to import both of the following into your file: import java.util.List; import java.util.ArrayList; There is an advantage of doing this in a program. If you determined that it would be more efficient to use a LinkedList instead of an ArrayList only one line of code in the program needs to be changed … the original instantiation on the right side where the list is declared … List <Student> shapes = new LinkedList <Student> ( ); The java.util.List<E> interface An interface tells you the method signatures of the methods that classes that implement the interface must have. Here is what part of Java’s List interface looks like: public interface List { public int size ( ); public boolean add (E obj); public void add (int index, E obj); public E get (int index); public E set (int index, E obj); public E remove (int index); ……. } An interface has no instance variables or constructors and it doesn’t have the code for any method … just the method signatures! Notice the method signatures end in semicolons! The Shape Program Series You will be completing a series of programs that help you learn inheritance: Shape 1 Shape 2 Shape 3 Shape 4 ShapeMania ShapeSorter Before starting Shape1, let’s view the Shape interface and a hierarchy of files we will be working with. The Shape Interface import java.awt.Color; import java.awt.Graphics; public interface Shape { public int getXPos(); public int getYPos(); public Color getColor(); public double area(); public void draw (Graphics g); public void paint (Graphics g); public void move (int xLoc, int yLoc); public void stretchBy (int factor); public String toString(); } Here are the method signatures of the Shape inteface that we will use. Since Color is a return value for the method getColor() and g is a parameter of two methods, we must import the respective classes. The Shape 1 Program Heirarchy Shape Interface Circle Class Rectangle Class Triangle Class means implements ShapePanel1 ShapeApplet1 means uses ShapePanel uses the Shape Interface because it declares variables of type Shape. It also calls constructors and other methods of the Circle, Rectangle, and Triangle classes. Implementing an Interface In the previous diagram, the Circle, Rectangle, and Triangle classes implement the Shape interface, so their class definition lines are as follows: public class Circle implements Shape public class Rectangle implements Shape public class Triangle implements Shape Constructing a List of Circle Objects In a program file, we could construct numerous circles and place them in an ArrayList using: List <Circle> circles = new ArrayList <Circle> ( ); and Circle c1 = new Circle (100, 100, 75, Color.blue); circles.add(c1); Circle c2 = new Circle (50, 50, 60, Color.yellow); circles.add(c2); …….. but if we constructed a rectangle and tried to add it with … Rectangle r1 = new Rectangle (25, 25, 75, 50, Color.red); circles.add(r1); we would get a compile error. The same would happen if we tried to add a Triangle. So we would be limited to placing only circles in our ArrayList. So how do we add all shapes to a list? Constructing a List of Shape Objects We would declare and instantiate our ArrayList as follows: List <Shape> shapes = new ArrayList <Shape> ( ); and Shape s1 = new Circle (100, 100, 75, Color.blue); shapes .add(s1); Shape s2 = new Rectangle (25, 25, 75, 50, Color.red); shapes .add(s2); Shape s3 = new Triangle (0, 0, 50, 0, 25, 25, Color.red); shapes .add(s3); By placing all Shape objects in shapes, we can have shapes of different types in one list!!! Then we can use a loop to move them, draw them, or stretch all of them. In fact this makes it easy to use enhanced for loops! Traversing a List of Shape Objects This enhanced for loop would draw all of the shapes: for (Shape element: shapes) { element.draw(g); } or without an enhanced for loop, we could use: for (int i = 0; i < shapes.size(); i++) { shapes.get(i).draw(g); } Using an Array of Shape Objects It will be worthwhile to go over the last three slides using standard arrays rather than an ArrayList beginning on the next slide. This will help familiarize you with the code for implementing a list of Shape objects in different ways in the Shape Program Series. Constructing an Array of Circle Objects Similarly if we were using a standard array created as follows: Circle [ ] circles = new Circle [10]; and Circle c1 = new Circle (100, 100, 75, Color.blue); circles[0] = c1; Circle c2 = new Circle (50, 50, 60, Color.yellow); circles[1] = c2; …….. but if we constructed a rectangle and tried to add it with … Rectangle r1 = new Rectangle (25, 25, 75, 50, Color.red); circles[2] = r1; we would get a compile error. The same would happen if we tried to add a Triangle. So we would be limited to placing only circles in our array. Constructing an Array of Shape Objects We would declare and instantiate our array as follows: Shape [ ] shapes = new Shape [10]; and Shape s1 = new Circle (100, 100, 75, Color.blue); shapes[0] = s1; Shape s2 = new Rectangle (25, 25, 75, 50, Color.red); shapes[1] = s2; Shape s3 = new Triangle (0, 0, 50, 0, 25, 25, Color.red); shapes[2] = s3; Again, by placing all Shape objects in shapes, we can have shapes of different types in one array!!! Then we can use a loop to move them, draw them, or stretch all of them. In fact this makes it easy to use an enhanced for loop! Traversing a List of Shape Objects This enhanced for loop would draw all of the shapes: for (Shape element: shapes) { element.draw(g); } or without an enhanced for loop, we could use: for (int i = 0; i < shapes.size(); i++) { shapes[ i ].draw(g); } Back to the Shape Hierarchy Now that we have learned some basic information about inheritance, let’s go back to the Shape 1 Hierarchy Diagram on the next slide and explain why the arrows are shown as they are. The Shape 1 Program Heirarchy Shape Interface Circle Class Rectangle Class Triangle Class means implements ShapePanel1 ShapeApplet1 means uses ShapePanel uses the Shape Interface because it declares variables of type Shape. It also calls constructors and other methods of the Circle, Rectangle, and Triangle classes. Explanation of Arrows Obviously the dashed arrows mean implements. This means that Circle, Rectangle, and Triangle implement a common set of methods that have the same names and their classes must provide the code for those methods. It also means that a variable of type Shape can reference a Circle object, Rectangle object, or Triangle object. The normal arrows mean uses. This means that other files outside of the hierarchy can use the interface or classes in the hierarchy by declaring variables of any of those types, constructing objects of those types, and most importantly calling methods of those types. In other words, an outside file can declare a variable of type Shape, construct either a Circle, Rectangle, or Triangle for it to refer to, and call any method in the interface. Is-A and Has-A Relationships Programmers like to be able to refer to the relationships of classes or objects using two expressions: • is-A relationship • has-A relationship You need to understand the basic meaning of these two relationships for the AP Exam. Examples follow on the next slides. Is-A Relationships of Shape 1 Because of the class definition lines: public class Circle implements Shape public class Rectangle implements Shape public class Triangle implements Shape We can say that a Circle “is a” Shape a Rectangle “is a” Shape a Triangle “is a” Shape This is terminology that programmers use when discussing the relationship between classes and interfaces within a hierarchy. has-A Relationships of Shape 1 Also, we can express the relationship between classes that are outside the hierarchy and those that are inside the hierarchy. Since ShapePanel1 is outside the hierarchy, we can say that ShapePanel1 “has a” Shape (three of them) In fact, it has 3 shapes … a Circle, a Rectangle, and a Triangle, because there are Shape variables s1, s2, and s3 that refer to constructed Circle, Rectangle, and Triangle objects. So we could also indirectly say that ShapePanel1 “has a” Circle ShapePanel1 “has a” Rectangle ShapePanel1 “has a” Triangle Coding the Shape 1 Program So let’s get going … here is what has to be done: • The coding of the Shape Interface file is done. • Begin by coding the Circle class • Next, code the Rectangle class • Next, code the Triangle class • Next, code the ShapePanel1 class • The ShapeApplet1 driver class is done. Sample output is available online. The Shape 2 Program Heirarchy Shape Interface Circle Class Rectangle Class ConcentricCircle Class Triangle Class means implements means extends means uses ShapePanel2 ShapeApplet2 The Concentric Circle Shape Notice a new kind of arrow in the Shape 2 Hierarchy Diagram … a heavier solid arrow. The heavier solid arrow means extends. It points from the ConcentricCircle class to the Circle class. This indicates that the ConcentricCircle class inherits all of the characteristics of the Circle class. The class definition line for ConcentricCircle is: public class ConcentricCircle extends Circle The Concentric Circle Shape More specifically, the heavier solid arrow means that … • the ConcentricCircle class extends the Circle class. • the ConcentricCircle class is a subclass of Circle. • the Circle class is the superclass of ConcentricCircle. • a ConcentricCircle object inherits all of the characteristics of a Circle, plus has some additional ones it defines in its own class. You could think of a ConcentricCircle object as a child of the parent class Circle, even though we won’t use child and parent in referring to them. Is-A Relationships of Shape 2 Because of the class definition lines: public class Circle implements Shape public class Rectangle implements Shape public class Triangle implements Shape public class ConcentricCircle extends Circle Now we can say that … a Circle “is a” Shape a Rectangle “is a” Shape a Triangle “is a” Shape a ConcentricCircle “is a” Shape a ConcentricCircle “is a” Circle has-A Relationships of Shape 2 Now we can say that … ShapePanel2 “has a” Shape (four of them) In fact, it has 4 shapes … a Circle, a Rectangle, a Triangle, and a ConcentricCircle because there are Shape variables s1, s2, s3 and s4 that refer to constructed Circle, Rectangle, Triangle, and ConcentricCircle objects. So we could also indirectly say that ShapePanel2 “has a” Circle ShapePanel2 “has a” Rectangle ShapePanel2 “has a” Triangle ShapePanel2 “has a” ConcentricCircle Protected vs. Private For the ConcentricCircle class to function properly, it needs to have access to its inherited characteristics (radius, xPos, yPos, and color) that are defined in the Circle class. This is possible by making the instance variables of Circle protected rather than private. Making them protected allows a subclass to have access to them but classes that are not subclasses don’t have access. (By the way, don’t try to use protected on the AP Exam. It is not part of the subset and you will never be expected to use it.) Note that ConcentricCircle itself has only one private instance variable named numberOfCircles. The Use of Super by Subclasses Subclasses may call methods in their super class explicitly by using the Java key word super. You will notice that the first line of code in the ConcentricCircle default constructor is: super( ); This code indicates that we are calling the default constructor in the superclass Circle. This should be obvious since there are empty parentheses following the word super. After that code is executed, Java returns to ConcentricCircle default constructor and executes the line of code: numberOfCircles = 2; The Use of Super by Subclasses You will notice that the first line of code in the ConcentricCircle initializing constructor is: super( xLoc, yLoc, r, c ); This code indicates that we are calling the initializing constructor in the superclass Circle. This should be obvious since the four parameters match what would be needed if someone was calling the initializing constructor of the Circle class. After that code is executed, Java returns to ConcentricCircle initializing constructor and executes the line of code: numberOfCircles = n; // n is a parameter In all cases of the use of super in a constructor method, it must be used in the first line of code. This is a requirement of Java. The Use of Super by Subclasses You will notice that the first line of code in the ConcentricCircle draw method is: super.draw(g); This code indicates that we are calling the draw method in the superclass Circle to draw the outer most ring of the ConcentricCircle object. (If this line of code had not been first it would have been ok with Java. We just decide to logically do it that way.) After Java executes the code in Circle’s draw method, it returns to the ConcentricCircle draw method and executes the remainder of the code that draws the other concentric circles. Overriding the Draw Method By having a draw method in the ConcentricCircle class we are overriding the draw method in the superclass Circle. Consider this: • ConcentricCircle extends Circle so it inherits all of the characteristics and methods of Circle. ConcentricCircle wouldn’t have to have a draw method because it inherits it, but it needs a draw method so all of the rings can be drawn. The work of drawing all of the rings can’t be done in Circle’s draw method, because it can draw only one circle. • What is not evident is that if there was no draw method in ConcentricCircle, then when draw is called for a ConcentricCircle object, Java would automatically go up to the superclass Circle and execute that method! So in this case overriding is a good thing and prevents something from happening that we don’t want. Not Overriding move() & stretchBy() But is some cases not overriding is a good thing. We don’t override move() and stretchBy() in ConcentricCircle because we just want to use the code that is in those methods in Circle when we want to move or stretch a ConcentricCircle. So when you call move() or stretchBy() with a ConcentricCircle object, Java doesn’t find those methods in ConcentricCircle so it automatically goes up to the superclass Circle and if it finds them then it executes them. Note: overriding is not the same as overloading. See the Math class PPT to review overloading. Overridding the paint() method We really can’t paint a ConcentricCircle object, because if we did we wouldn’t be able to see the rings. It would be all one solid color. So our first inclination might be to not provide a paint() method in ConcentricCircle, but then we realize that a novice programmer might try to call paint anyway and if they did then it would execute the paint method in the Circle class and paint the ConcentricCircle a solid color. We prevent this from happening by overriding paint in ConcentricCircle and then just calling draw inside of it. So if someone calls paint for a ConcentricCircle object, Java finds the paint method in ConcentricCircle which only does one thing and that is call the draw method in ConcentricCircle. This way we can be assured that a ConcentricCircle object is always drawn and not painted. The setNumberOfCircles() method Besides moving or stretching a ConcentricCircle object, we may want to change the number of concentric circles it has. To do this, we must call the setNumberOfCircles() method. If we have used: Shape s4 = new ConcentricCircle(……); then because the setNumberOfCircles() method is not in the Shape interface, but is a method specific to the ConcentricCircle class, we cannot call the method as follows: s4.setNumberOfCircles(10); We must first explicitly cast s4 to a ConcentricCircle as follows: ((ConcentricCircle)s1).setNumberOfCircles(10); Both sets of parentheses are necessary, because it is the casted object that must make the call of the method. The ClassCastException If by accident, you miscode the method call by casting to the wrong class as in … ((Circle)s1).setNumberOfCircles(10); instead of ((ConcentricCircle)s1).setNumberOfCircles(10); then you will get a ClassCastException, meaning that you are trying to cast an object to a different type other than what it is. You need to know what a ClassCastException is for the AP Exam. Coding the Shape 2 Program Now its time to code the Shape 2 Program. Here is what to do: • Modify your Circle class to make the instance variables protected instead of private. This lets the subclass ConcentricCircle have direct access to the instance variables in Circle. • Next, code the ShapePanel2 class. In this program you will call more than just the draw, move, and paint methods. Sample output is available online. Abstract Classes The purpose of abstract classes is to contain the code that will be the same in subclasses. Therefore, the code doesn’t have to be repeated over and over again in the subclasses. This includes instance variables and methods. If we had thought about this in the beginning, then we could have created an abstract class immediately and placed all of the code that is the same in it. An abstract class also tells subclasses which methods they must have code for. Here is the code that Circle, Rectangle, and Triangle have in common: instance variables: xPos, yPos, color accessor methods: getXPos, getYPos, and getColor Let’s look at our Shape Hierarchy with the AbstractShape class added and then we will continue this discussion. The Shape 3 Program Heirarchy Object Class Shape Interface AbstractShape Class Circle Class Rectangle Class ConcentricCircle Class Triangle Class ShapePanel means implements means extends ShapeApplet means uses The Shape 3 Hierarchy Explanation • Notice now that the AbstractShape class is the only class to implement the Shape interface and that Circle, Rectangle, and Triangle now extend AbstractShape. This is necessary if we are going to put all of the code that is the same in AbstractShape. • The class definition lines for the four files are now: abstract public class AbstractShape implements Shape public class Circle extends AbstractShape public class Rectangle extends AbstractShape public class Triangle extends AbstractShape Is-A Relationships of Shape 3 Because of the class definition lines: abstract public class AbstractShape implements Shape public class Circle extends AbstractShape public class Rectangle extends AbstractShape public class Triangle extends AbstractShape public class ConcentricCircle extends Circle Now we can say that … a Circle “is a” AbstractShape a Rectangle “is a” AbstractShape a Triangle “is a” AbstractShape a ConcentricCircle “is a” AbstractShape a ConcentricCircle “is a” Circle or has-A Relationships of Shape 3 Now we can still say … ShapePanel3 “has a” Shape (four of them) In fact, it has 4 shapes … a Circle, a Rectangle, a Triangle, and a ConcentricCircle because there are Shape variables s1, s2, s3 and s4 that refer to constructed Circle, Rectangle, Triangle, and ConcentricCircle objects. So we can still say that ShapePanel3 “has a” Circle ShapePanel3 “has a” Rectangle ShapePanel3 “has a” Triangle ShapePanel3 “has a” ConcentricCircle Details About Abstract Classes • Even though an abstract class may have constructors, you cannot construct an object of an Abstract class using something like: Shape s1 = new AbstractShape( ); If you do this Java will give you a compile error. Think about that. Why would we want to construct a “skeleton” shape object that doesn’t have the specific information for either a Circle, Rectangle, or Triangle? We wouldn’t! Let’s look at some of the code of the AbstractShape class and explain some things …. Details About the AbstractShape Class abstract public class AbstractShape implements Shape { protected int xPos; // instance variables common to all subclasses protected int yPos; protected Color color; static private int shapeCount; // class variable to track the number of shapes public AbstractShape () { xPos = 0; yPos = 0; color = Color.black; shapeCount++; } // this constructor executed when super(); // is called from any subclass public AbstractShape (int xLoc, int yLoc, Color c) { xPos = xLoc; // this constructor executed when super(xLoc, yLoc, c); yPos = yLoc; // is called from any subclass color = c; shapeCount++; } Details About the AbstractShape Class After the constructors, we find this code … the code that was exactly the same in the Circle, Rectangle, and Triangle classes. We have to make sure we comment out this code in the three classes, because we now only need it here. public int getXPos() { return xPos; } public int getYPos() { return yPos; } public Color getColor() { return color; } Details About the AbstractShape Class Next, we find five method signatures that are preceded by the word abstract and all end in a semicolon. The code for these methods MUST be implemented in the subclasses Circle, Rectangle, and Triangle. We want the code to be written there because the code for each one is different for Circle, Rectangle, and Triangle. Making a method abstract is a way of forcing subclasses to provide code for a method. abstract public double area(); abstract public void draw (Graphics g); abstract public void paint (Graphics g); abstract public void move (int xLoc, int yLoc); abstract public void stretchBy (int factor); Note: the subclasses of an abstract class are referred to as concrete classes. So now with the Shape 3 hierarchy Circle, Rectangle, and Triangle are concrete classes. The Java Object Class All classes in Java can explicitly extend only one class as in …. public class Circle extends AbstractShape but they also implicitly extend the Object class. Its like the class definition line is public class Circle extends AbstractShape extends Object but you can’t write this in Java or it will complain. It is possible but totally unnecessary to include extends Object in a class definition line if the class does not already extend another class as in ... public class ArrayListProcessor3 extends Object but why would you want to waste time typing it? We mention it because you might see it. Just don’t assume anything special is happening if you see it in a class definition line. The Java Object Class Here is what several sources say about the Object class: • Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class. (You only need to know that the Object class has an equals() and a toString() method.) • The Object class sits at the top of the class hierarchy tree in the Java development environment. Every class in the Java system is a descendent (direct or indirect) of the Object class. The Object class defines the basic state and behavior that all objects must have, such as the ability to compare oneself to another object and to convert to a string. Implementing more than one Java Interface A final important fact about Java classes is that they can implement more than one interface. For example: public class MyGame extends JApplet implements ActionListener, implements MouseListener is a valid Java class definition line. Note the comma in between the implements clauses. Coding the Shape 3 Program • The AbstractShape class is complete. There is no code to write. We will examine the code. • Next, we will comment out the code in the Circle, Rectangle, and Triangle classes that is common to all three classes that has been transferred to the AbstractShape class. • Next, we will discuss “Class Constants”, “Class (static) Methods”, and “Class Variables”. • Finally, you will write the code in the ShapePanel3 class. Sample output is available online. Polymorphism It is difficult for any programmer to remember the names of methods in many different classes. So interfaces help by requiring us to call the methods by certain names with a specific method signature. So instead of progammers having to remember separate method names like: drawCircle(g) for the Circle class and drawRectangle(g) for the Rectangle class They just have to remember draw(g) because that is what the interface says to call the method!!! This is extremely helpful to programmers and promotes the efficient coding of programs and Java will know which draw method to execute because of the kind of object that makes the call of the method! This is polymorphism! Polymorphism Technically, polymorphism is a superclass reference to a subclass object, so if a driver file uses the code: List <Shape> shapes = new ArrayList <Shape> ( ); and Shape s1 = new Circle (100, 100, 75, Color.blue); shapes .add(s1); Shape s2 = new Rectangle (25, 25, 75, 50, Color.red); shapes .add(s2); Shape s3 = new Triangle (0, 0, 50, 0, 25, 25, Color.red); shapes .add(s3); where s1, s2, and s3 are superclass references to subclass objects (because they are declared of type Shape), then …….. (see next slide) Polymorphism … when an enhanced for loop draws all of the shapes with the loop variable element … then element is the superclass reference to a subclass object, because element gets each shape out of the list, but Java really knows what kind of subclass object it was constructed as, so it then knows which class to go to, so that it can execute the draw(g) method. for (Shape element: shapes) { element.draw(g); } The same is true if you were not using an enhanced for loop … Polymorphism for (int i = 0; i < shapes.size(); i++) { shapes.get(i).draw(g); } shapes.get(i) obtains one of the shapes in the list. shapes.get(i) represents a shape that is a superclass reference to a subclass object. So again, Java knows exactly what kind of object the shape really is and it knows which class to go to, so it can execute the draw(g) method. Summarizing Inheritance • If more than one class implements an interface, its methods are polymorphic. • A class can implement other methods in addition to those listed in an interface it implements. • All classes are part of a large class hierarchy with the Object class as the root. • In Java, each class inherits variables and methods of the classes above it in the hierarchy. • A class immediately above a class is a superclass. • A class immediately below a class is a subclass. • A subclass can add new variables, add new methods, or alter (override) existing inherited methods. • All classes defined by programmers automatically extend the Object class implicitly. There is no need to include extends Object in a class definition line.