Polymorphism is a big word that you can break down into “poly” which means many and “morphism” which means form. So, it just means many forms. In Java it means that the method that gets called at run-time (when the code is run) depends on the type of the object at run-time.
This is similar to a toddler toy that has pictures of animals and when a handle is pulled an arrow spins. When the arrow stops the toy plays the sound associated with that animal.
If you were simulating this toy in software you could create an Animal class that had a makeNoise method. Each subclass of Animal would override the makeNoise method to make the correct noise for that type. This type of polymorphism is called inheritance-based polymorphism. You have a common parent class, but the behavior is specified in the child class.
In Java an object variable has both a declared (compile-time) type and an actual (run-time) type. The declared (compile-time) type of a variable is the type that is used in the declaration. The actual (run-time) type is the class that actually creates the object using new.
The variable nameList declared below has a declared type of List and an actual or run-time type of ArrayList. The compiler will check if the declared type has the methods or inherits the methods being used in the code and give an error if it doesn’t find the method(s). The List interface does have an add method so this code will compile. At run-time the execution environment will first look for the add method in the ArrayList class since that is the actual or run-time type. If it doesn’t find it there it will look in the parent class and keep looking up the inheritance tree until it finds the method. It may go up all the way to the Object class. The method will be found, since otherwise the code would not have compiled.
List<String> nameList = new ArrayList<String>();
nameList.add("Hi");
The variable message declared below has a declared type of Object and an actual or run-time type of String. Since the declared type of message is Object the code message.indexOf("h"); will cause a compiler error since the Object class does not have an indexOf method.
Object message = new String("hi");
message.indexOf("h"); // ERROR!! Objects don't have indexOf!
At compile time, the compiler uses the declared type to check that the methods you are trying to use are available to an object of that type. The code won’t compile if the methods don’t exist in that class or some parent class of that class. At run-time, the actual method that is called depends on the actual type of the object. Remember that an object keeps a reference to the class that created it (an object of the class called Class). When a method is called at run-time the first place that is checked for that method is the class that created the object. If the method is found there it will be executed. If not, the parent of that class will be checked and so on until the method is found.
In all of these cases, there are no errors at compile-time because the compiler checks that the “subclass is-a superclass” relationship is true. But at run-time, the Java interpreter will use the object’s actual subclass type and call the subclass methods for any overridden methods. This is why they are polymorphic – the same code can have different results depending on the object’s actual type at run-time.
public class Shape
{
public void what()
{
System.out.print("Shape ");
}
public static void main(String[] args)
{
Shape[] shapes =
{
new Shape(), new Rectangle(), new Square(), new Circle()
};
for (Shape s : shapes)
{
s.what();
}
}
}
class Rectangle extends Shape
{
public void what()
{
System.out.print("Rectangle ");
}
}
class Square extends Rectangle {}
class Oval extends Shape
{
public void what()
{
System.out.print("Oval ");
}
}
class Circle extends Oval
{
public void what()
{
System.out.print("Circle ");
}
}
The Shape object will print Shape. The Rectangle object will print Rectangle. The Square object will also print Rectangle since it doesn’t overrride the what method. The Circle object will print Circle.
This would be true if s1 was actually a Student, but it is a GradStudent. Remember that the run-time will look for the method first in the class that created the object.
Even though the getInfo method is in Student when getFood is called the run-time will look for that method first in the class that created this object which in this case is the GradStudent class.
public class Car
{
private int fuel;
public Car()
{
fuel = 0;
}
public Car(int g)
{
fuel = g;
}
public void addFuel()
{
fuel++;
}
public void display()
{
System.out.print(fuel + " ");
}
public static void main(String[] args)
{
Car car = new Car(5);
Car fastCar = new RaceCar(5);
car.display();
car.addFuel();
car.display();
fastCar.display();
fastCar.addFuel();
fastCar.display();
}
}
class RaceCar extends Car
{
public RaceCar(int g)
{
super(2 * g);
}
}
RaceCar, while it inherits object methods from Car via inheritance, has a separate and different constructor that sets the initial fuel amount to 2 * g, thus in this case, fuel for fastCar is set to 10 initially.
The variable car is a Car object, so the constructor used is not the same as the fastCar object which is a RaceCar. The car constructor does not change the passed in parameter, so it is set to 5 initially.
public class Book
{
public String getISBN()
{
// implementation not shown
}
// constructors, fields, and other methods not shown
}
public class Dictionary extends Book
{
public String getDefinition()
{
// implementation not shown
}
}
In the last lesson, you created a class called DiscountedItem as part of a Shopping Cart application. Please copy your solutions from the last lesson 4
The ShoppingCart contains a polymorphic ArrayList called order that you can use to add Items or DiscountedItems to the shopping cart. The Item class keeps track of the name and the price of each Item. The DiscountedItem class you wrote in the last lesson adds on a discount amount.
In the loop, you will test if each Item is a DiscountedItem by using the instanceof keyword (object instanceof Class returns true or false) similar to its use in the add(Item) method.
Make sure you print out the number of discounted items in the main method or in printOrder(), so that you can test your method. Add more items to the order to test it.
Copy in your code for DiscountedItem below and then write a method called countDiscountedItems which traverses the polymorphic ArrayList<Item>. Use instanceof to test each item to see if it is a DiscountedItem.