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.

2.1 Reference Types

Theme: Reference type variables allow polymorphism through storing subtypes of their declared type.

Equality and equality

The Object class

Wrapper classes

Exercise

Given:

Object o = new Object();
Object p = new Object();
Integer i = new Integer(21);
Integer j = new Integer(21);

What are the values of

  1. o == p
  2. o.equals(p)
  3. i == j
  4. i.equals(j)

See Equality.java

2.2 Arrays

Theme: array type variables allow polymorphism because they can store arrays of different size and dimension.

Multidimensional arrays

Array Example

2.3 Interfaces

Theme: interfaces provide polymorphism through type and subtypes.

Interfaces Example

Abstract Data Types

What is an abstract data type (ADT)?

2.4 Overloading

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).

Overloading Example

Summary

  1. Java has 8 primitive types; all other Java types are reference types.
  2. A reference is a pointer to an object (or some similar compound thing, such as an array or a class).
  3. Reference type fields have null as a default initial value.
  4. With reference types, use == 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.
  5. Four kinds of polymorphism in Java:
  6. Arrays must be declared, allocated, and initialized.

Comments

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?

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.

A Puzzle

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")?

Footnotes


  1. Revision history:
    • Version 5.3, 2012 Sep 4. Expanded flip/toss example, other minor editing.
    • Version 5.2, 2010 Sep 7. To markdown, changed examples, minor revisions.
    • Version 5.1, 2009 Sep 9. Clarified paragraph about functional languages; fixed indentation.
    • Version 5, 2009 Sep 7. Converted to reStructuredText; minor textual revisions.
    • Version 4, 2007 Sep 6. Clarified "flip" example.
    • Version 3, 2007 Sep 5. Corrected code for array initialization; added memory representation of one-dimensional array.
    • Version 2, 2007 Sep 3. Hypertextualized.
    • Version 1, 2006 Sep 4. Initial version.
  2. 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.

  3. Because the compiler cannot always tell how much memory is required for an object.

  4. There is no default. It is an error if a local variable (whether of reference or primitive type) is used before being explicitly initialized.

  5. There is an == operator in Haskell, but it means pretty much the same thing as the Java equals method.

  6. 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.

  7. No. In a language without overloading, we would simply have to use different names for each method. A simple, though not pretty, way to do this is to suffix the method name with an abbreviated representation of the argument types:
    • 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)
  8. All Java method calls are dynamically dispatched in this sense. In C++, only methods declared virtual are dynamically dispatched.