Example: The Java Type System

Java types are either primitive, reference, or method types.

The primitive types of Java are:

boolean = {false, true}
char = { '\uXXXX' | 0 <= X <= F }
byte = { n | -2k <= n < 2k for k = 8 }
short = { n | -2k <= n < 2k for k = 16 }
int = { n | -2k <= n < 2k for k = 32 }
long = { n | -2k <= n < 2k for k = 64 }
float = { n * 2m | -2-k <= n < 2k, k = 23 && -2-k <= m < 2k, k = 8 }
double = { n * 2m | -2-k <= n < 2k, k = 52 && -2-k <= m < 2k, k = 11 }

The reference types of Java are array types, interface types, and class types.

Subtypes and Subsumption

Here are the relationships between the primitive types, notice that boolean is incompatible with everything:

byte <: short <: int <: long <: float <: double
char <: int

For the reference types:

T1 extends T2 implies T1 <: T2
T1 implements T2 implies T1 <: T2
T1 <: T2 implies T1[] <: T2[]

Finally, if T1 is a primitive type and T2 is a reference type, then T1 <: T2 is never true, and T2 <: Object is always true.

Example

Of course we can use integers and floats in contexts where doubles are expected:

Math.cos(0);
Math.cos(0L);
Math.cos(.0F);
Math.cos(.0);

Example

Assume the following classes have been declared:

class Aircraft {
   void takeoff() { ... }
   void fly() { ... }
   void land() { ... }
}

class Airplane extends Aircraft { ... }
class Jet extends Airplane { ... }
class Blimp extends Aircraft { ... }
class Helicopter extends Aircraft { ... }

We have the following subclass relationships:

Jet <: Airplane <: Aircraft
Helicopter <: Aircraft
Blimp <: Aircraft

In other words, jets, airplanes, blimps, and helicopters can be used in contexts where aircraft are expected. For example, an array of aircraft can hold jets, airplanes, blimps, and helicopters:

Aircraft[] fleet = new Aircraft[4];
fleet[0] = new Airplane();
fleet[1] = new Helicopter();
fleet[2] = new Blimp();
fleet[3] = new Jet();

Such an array is called a heterogeneous container, because it contains different types of objects. Traversing a heterogeneous array is just like traversing a homogeneous array, because we know each object in the array inherits the methods of its super class:

for(int i = 0; i < 4; i++) {
   fleet[i].takeoff();
   fleet[i].fly();
   fleet[i].land();
}

As another example, the following method has an aircraft parameter:

class Pilot {
   void fly(Aircraft a) {
      a.takeoff();
      a.fly();
      a.land();
   }
   // etc.
}

But we can pass airplane, jet, helicopter, and blimp arguments to this method:

Pilot p = new Pilot();
p.fly(new Airplane());
p.fly(new Jet());
p.fly(new Helicopter());
p.fly(new Blimp());