More Polymorphism and Class Design
> Click or hit Control-Enter to run Example.main above
Q4 Review: Constructor Overloading
class Dog {
String breed;
double weight;
Dog() {
// First constructor
}
Dog(String setBreed) {
// Second constructor
this.breed = setBreed;
}
Dog(double setWeight) {
// Third constructor
this.weight = setWeight;
}
}
Based on the Dog
class defined above, which call will run the third
constructor?
Q4 Review: Setting Attributes
class Dog {
String breed;
double weight;
Dog() {
// First constructor
}
Dog(String setBreed) {
// Second constructor
this.breed = setBreed;
}
Dog(double setWeight) {
// Third constructor
this.weight = setWeight;
}
}
Based on the Dog
class defined above, what is one way to set both an
instance chuchu
's breed
and weight
?
Q4: Object Modeling
Define a public class
named Points
.
It should have a public instance method named score
and a second named
penalty
, both taking a single int
argument.
score
adds the passed number of points to the score, while penalty
removes
the passed number of points from the score.
Both functions should return the new score after the change is completed.
Your class should also provide a constructor taking a single int
argument that
sets the initial score.
Q4: Object Modeling
Note that your Points
class should not allow modifications to the score
except using the score
and penalty
methods.
So when you are finished your class should work as follows:
Points points = new Points(0);
System.out.println(points.score(10)); // Prints 10
System.out.println(points.score(20)); // Prints 30
System.out.println(points.penalty(30)); // Prints 0
System.out.println(points.penalty(5)); // Prints -5
Points anotherPoints = new Points(10);
System.out.println(anotherPoints.score(10)); // Prints 20
System.out.println(anotherPoints.score(20)); // Prints 40
System.out.println(anotherPoints.penalty(5)); // Prints 35
System.out.println(anotherPoints.penalty(25)); // Prints 10
> Click or hit Control-Enter to run Example.main above
Review: The Tree Of (Java) Life

In Java, each class has a single parent, meaning that classes are organized into a tree.
If we follow each node to its parent, we eventually get to the top, or root…
The Root Object: Object
public class Dog { }
// is equivalent to
public class Dog extends Object { }
If a Java class
does not explicitly extend
another class, it implicitly
extends Object
.
Review: Inherited from Object
public class Dog {
private String name;
Dog(String setName) {
this.name = setName;
}
}
public class Example {
public static void main(String[] unused) {
Dog chuchu = new Dog("Chuchu");
System.out.println(chuchu.toString());
}
}
All Java objects inherit a small number of important methods from Object
.
As a result, all Java objects implement these methods!
Review: Methods Inherited from Object
For our purposes, the following methods inherited from Object
are important:
-
String toString()
: return aString
representing the instance. Frequently used for debugging. -
boolean equals(Object other)
: return aboolean
indicating whether this object is the same as another object -
int hashCode()
: return anint
uniquely representing an object’s contents. We’ll talk more about hashing later—it’s incredibly important and useful.
Review: Method Overriding
public class Dog {
private String name;
Dog(String setName) {
this.name = setName;
}
public String toString() {
return this.name;
}
}
public class Example {
public static void main(String[] unused) {
Dog chuchu = new Dog("Chuchu");
System.out.println(chuchu.toString());
}
}
The default Object
methods are rarely useful.
So classes usually override them and provide their own.
Hierarchical Name and Method Resolution
The Java type hierarchy is used when resolving the names of variables and methods:
-
Does the class have a variable or method with the given name? If so, use it.
-
If not, search the parent class—but limited by
public
andprotected
-
Continue up the tree until the name is found or the search fails
> Click or hit Control-Enter to run Example.main above
Polymorphism
Polymorphism: the provision of a single interface to entities of different types.
We’ll discuss interfaces in more detail when we talk about about packages. For now, let’s identify two kinds of Java polymorphism using examples.
Subtype Polymorphism
public class Pet {
public void printMe() {
System.out.println("I'm a pet");
}
}
public class Dog extends Pet {
public void printMe() {
System.out.println("I'm a dog");
}
}
In Java, every object is really an instance of at least two types:
-
Each
Pet
is also anObject
-
Each
Dog
is also aPet
and also anObject
Object Conversion: Upcasting
public class Pet { }
public class Dog extends Pet {
public String toString() {
return "Dog";
}
}
public class Example {
public static void main(String[] unused) {
Dog chuchu = new Dog();
Pet xyz = new Pet();
Example.printAnything(chuchu);
Example.printAnything(xyz);
}
public static void printAnything(Object toPrint) {
System.out.println(toPrint.toString());
}
}
Java will upcast object types automatically.
> Click or hit Control-Enter to run Example.main above
But Instances Retain Their Types
public class Pet { }
public class Dog extends Pet {
public String toString() {
return "Still a Dog";
}
}
public class Example {
public static void main(String[] unused) {
Dog chuchu = new Dog();
Object chuchuAsObject = chuchu;
System.out.println(chuchuAsObject);
Pet chuchuAsPet = chuchu;
System.out.println(chuchuAsPet);
}
}
> Click or hit Control-Enter to run Example.main above
Object Conversion: Downcasting
public class Pet { }
public class Dog extends Pet {
public String toString() {
return "Still a Dog";
}
}
public class Example {
public static void main(String[] unused) {
Object chuchu = new Dog();
Example.printAnything(chuchu);
Pet chuchuAsPet = (Pet) chuchu; // chuchu is a Pet, so this works
Example.printAnything(chuchuAsPet);
}
}
We can also cast instances down but only if the instance is actually the appropriate subtype.
Java checks the cast at runtime to make sure that it is appropriate.
> Click or hit Control-Enter to run Example.main above
Type Testing: instanceof
public class Pet { }
public class Dog extends Pet { }
public class Cat extends Pet { }
public class Example {
public static void main(String[] unused) {
Pet chuchu = new Dog();
Pet xyz = new Cat();
System.out.println(chuchu instanceof Dog); // Prints true
System.out.println(chuchu instanceof Pet); // Prints true
System.out.println(chuchu instanceof Cat); // Prints false
}
}
The Java instanceof
operator allows you to test whether an object is an
instance of or a descendant of a particular class.
> Click or hit Control-Enter to run Example.main above
Liskov Substitution Principle
Substitutability is a principle in object-oriented programming stating that, in a computer program, if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e. an object of type T may be substituted with any object of a subtype S) without altering any of the desirable properties of T (correctness, task performed, etc.).
Liskov Substitution Principle
An example for Java:
Substitutability is a principle in object-oriented programming stating that, in a computer program, if
Dog
is a subtype ofPet
, then objects of typePet
may be replaced with objects of typeDog
(i.e. an object of typePet
may be substituted with any object of a subtypeDog
) without altering any of the desirable properties ofPet
(correctness, task performed, etc.).
Substitutability in Practice
public class Pet {
public boolean useful() {
return true;
}
}
public class Dog extends Pet {
public String toString() {
return "Dog";
}
}
public class Example {
public static void main(String[] unused) {
Dog chuchu = new Dog();
Pet xyz = new Pet();
System.out.println(chuchu.useful());
System.out.println(xyz.useful());
}
}
Subtype Polymorphism
We can always use toString
, but every class can implement it
differently.
Same Names, Different Behavior
Where else have we seen this before?
> Click or hit Control-Enter to run the code above
Polymorphism
Polymorphism: the provision of a single interface to entities of different types.
-
Subtype polymorphism: a single method can act on all descendants of a given class
-
Method overloading: a method can behave differently depending on its arguments
-
Generic types (discussed later)
Why Polymorphism?
This really gets to the purpose behind Java’s entire type system.
-
Descendant classes can implement or override ancestor behavior while retaining desirable ancestor properties
-
Polymorphism makes it possible to write methods that work for any descendant class—even ones that you may not have created
Generality v. Capability
Polymorphism presents one of many tradeoffs in computer program and system design:
-
Higher on the object hierarchy: more general, but can use fewer capabilities
-
Lower on the object hierarchy: less general, but can use more capabilities
> Click or hit Control-Enter to run Example.main above
Questions About Polymorphism?
More Class Design: final
Marking a class as final
means that it cannot be extended:
public class Pet { }
public final class Dog extends Pet { }
public class BigDog extends Dog { } // This won't work
> Click or hit Control-Enter to run Example.main above
More Class Design: abstract
Marking a class as abstract
means that it can only be extended and cannot
be instantiated:
public abstract class Pet { }
public class Dog extends Pet { }
Pet pet = new Pet(); // This will not work
Dog dog = new Dog(); // This will work
> Click or hit Control-Enter to run Example.main above
private
Classes?
In Java classes cannot be marked as private
: that would make little sense,
since nobody could use them.
-
To use it you have to create one
-
To create one you have to call one of it’s methods (the constructor)
-
But you can’t call it’s methods because the entire class is
private
Inner Classes
But we can achieve something similar using so-called inner classes:
public class Dog {
class DogFood {
public String toString() {
return "kibble";
}
}
private DogFood myFood;
Dog() {
myFood = new DogFood();
}
}
> Click or hit Control-Enter to run Example.main above
Object Modeling
We frequently use Java objects to model real objects or entities.
Objects allow us to design software that deals with things in realistic and natural ways.
> Click or hit Control-Enter to run Example.main above
Announcements
-
The MP3 early deadline is today.
-
I have office hours today at 10AM in my office (Siebel 2227).
-
We will not have a lecture this Wednesday—I may record a video lecture instead 1.