Version 5.31
Handout examples: Equality.java, Arrays.java, Speakers.java, Overloading.java
Polymorphism ("many-formed-ness") means that a symbol can mean different things in different contexts (p. 37).
Better: Methods or operators can behave differently depending on the objects the message is sent to or the arguments it has.
Theme: Reference type variables allow polymorphism through storing subtypes of their declared type.
Diagram a reference:
acct → instance of SavingsAccount
null?What is the default value for a reference type local variable? 4
a and b are two reference type variables, what is the meaning of a == b ?== tests for equality in the strong sense: references are to the same object.Look at the equals methods and explain the code for these two classes:
The distinction between the two kinds of "equal" is only needed because of the mutability of objects. If method eat mutates its object and we have
Rabbit a, b, c;
a = new Rabbit();
b = a;
c = new Rabbit();
a.eat();
then mutation of a guarantees mutation of b (and vice-versa) but has no effect on c (and vice-versa).
In functional languages like Haskell, there is no mutation and therefore no need for == in the Java sense.5
Object classThe top of the Java class hierarchy is the Object class. Since all other classes are, directly or indirectly, subclasses of Object, an Object -type variable can store a reference to any object, i.e., to any instance of any class.
The fact that Java allows a type to have subtypes (these can arise from inheritance and interfaces, both of which we take up in detail later) means that we sometimes need to distinguish between the declared type of a variable and the most specific type of its actual value (sometimes called the actual type of the value, for short).
So if we have
Object thing = new Beetle();
we can distinguish between:
thing is Object.thing is Beetle.This distinction creates an opportunity for polymorphism, because the variable could store different subtypes of its declared type.
Can a variable with declared type Object store a primitive value?
Int, Boolean, Double, etc.; each of these "wraps" a primitive datum as an object.Why have wrapper classes?
Object and want to store an int-type value in it, this is as close as we can get.Any disadvantages in using wrapper classes?
Prior to Java 1.5 we'd have to write something like
Object o = new Integer(5); // or (Integer) 5
int n = ((Integer) o).intValue();Since Java 1.5 we have autoboxing and unboxing; we can just write
Object o = 5;
int n = (Integer) o;
but this just hides what happens at runtime (the compiler generates code like above).
Given:
Object o = new Object();
Object p = new Object();
Integer i = new Integer(21);
Integer j = new Integer(21);
What are the values of
o == po.equals(p)i == ji.equals(j)See Equality.java
Theme: array type variables allow polymorphism because they can store arrays of different size and dimension.
Declare it:
int [] x;Allocate it (initialize the array variable):
x = new int[10];Initialize the elements of the array, or use the default element values (what are they?):
for (int i = 0; i < x.length; i++)
x[i] = 1; // or some other value We can do all three in one statement, for small arrays:
int [] x = new int[] {5, 7, 12}; // omit sizeHow is the array x represented in memory?
How is the array y represented in memory?
int [][] y = new int [2][4];Can we access a particular row as a unit?
int [] row = y[0];Do all rows of a two-dimensional array have to have the same length?
No, we can initialize each row separately, creating a "ragged" array:
int [][] y = new int [2][];
y[0] = new int[] {1, 3, 7};
y[1] = new int[] {5, 11, 19, 27, 38, 49, 53};How do arrays, even arrays of int, create an additional kind of polymorphism? 6
Theme: interfaces provide polymorphism through type and subtypes.
Both interfaces and classes are types. How is an interface different from a class?
How do we declare an interface?
How:
public interface Name {
methodDecls ...
}Declare an interface Speaker with a speak method.
public interface Speaker {
public void speak ();
}Why do we have interfaces?
Speakers.How do we define a class that implements the interface?
implements 〈InterfaceName〉Example:
public class Dog implements Speaker {
public void speak () {
System.out.println("Woof! Woof!");
}
}What is an abstract data type (ADT)?
Theme: overloaded names provide another kind of polymorphism.
Overloading means that a method name is used for two or more methods (in the same class).
These methods must differ in their signatures: the number and types of their arguments.
Example: a cat might have different reactions to meeting dogs and mice.
public class Cat {
...
public void react (Dog dog) { ... } // run away
public void react (Mouse mouse { ... } // chase
}The compiler looks at the declared types of the actual arguments in a method call to determine which of the overloaded methods is being called.
Would this work as intended if we have
Cat mycat = new Cat();
Object mymouse = new Mouse();
mycat.react(mymouse);(?) What is going on in Fig. 2-27, p. 60? (Overload example)
Does overloading add any new capabilityor power to a programming language? I.e., could we solve programming tasks in a language with overloading that we could not in a language without overloading? 7
null as a default initial value.== to ask if two expressions refer to the same object (same address); use the equals method to ask if the objects referred to have equal values (e.g., corresponding parts are equal; this can be defined to mean anything that makes sense for the application, though you should not define equals in a way that makes it false when == is true.Of the four kinds of polymorphism in Java, the fourth kind (method overloading) behaves very differently from the others.
In Drake's example, we have a Domino interface with two implementing classes, FieldDomino and ArrayDomino. If we have
Domino d = ...;
d.flip();
which flip method is called? It depends on the most specific type of the actual object which d refers to (recall that Domino has two implementing classes), and this is, in general, not known until run time:
d = userInput.equals("field") ?
new FieldDomino(5, 6) :
new ArrayDomino(5, 6);
d.flip();
Consequently this type of method call is said to be dynamically dispatched because at run time, the type information becomes available to determine which of the flip methods is to be run.8
On the other hand, if we have (in some class) methods declared as
public void toss (Domino d) { ...} // method 1
public void toss (FieldDomino d) { ...} // method 2
public void toss (ArrayDomino d) { ...} // method 3
and somewhere else (in the same class)
FieldDomino f = new FieldDomino();
ArrayDomino g = new ArrayDomino();
Domino j = new FieldDomino();
Domino k = new ArrayDomino();
then which method is called?
toss(f) calls method 2, because the declared type of f is FieldDomino.toss(g) calls method 3, because the declared type of g is ArrayDomino.toss(j) and toss(k) calls method 1, because the declared type of j and k is Domino. It doesn't matter that they are actually (most specifically) a FieldDomino (j) and an ArrayDomino (k).In these cases, which method is called is determined entirely by the declared type of the argument, which is known at compile time. Consequently, the compiler determines which method is called when it compiles each method call; these method calls are said to be statically dispatched because the determination is made at compile time.
If we have the overloaded methods foo (Object o, String s) and foo(String s, Object o), what happens in the method call foo("A", "B")?
They are pointers, but with their dangerous "points" removed so that Java can claim to have no pointers. For example, there is no pointer arithmetic in Java.↩
Because the compiler cannot always tell how much memory is required for an object.↩
There is no default. It is an error if a local variable (whether of reference or primitive type) is used before being explicitly initialized.↩
There is an == operator in Haskell, but it means pretty much the same thing as the Java equals method.↩
A variable declared as int[] can store an array of 10 ints, or an array of 100 ints, or in fact of any number of ints.↩
void foo(int m, int n, float x) could become void fooIIF(int m, int n, float x)int bar(double y, double z) could become int barDD(double y, double z)All Java method calls are dynamically dispatched in this sense. In C++, only methods declared virtual are dynamically dispatched.↩