You are on page 1of 101

Inner Classes Generics Generics in JDK5.

0 Runtime Generics Conclusions

Advanced Java Programming

Maurizio Cimadamore
mcimadamore@deis.unibo.it

DEIS
Alma Mater Studiorum—Università di Bologna

Computational Models and Languages, A.A. 2006/2007


Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

1 Inner Classes

2 Generics

3 Generics in JDK5.0

4 Runtime Generics

5 Conclusions
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Outline

1 Inner Classes
Member Inner Classes
Local Inner Classes
Anonymous Inner Classes
Static Inner Classes
Inner Classes Implementation

2 Generics

3 Generics in JDK5.0

4 Runtime Generics

5 Conclusions
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Toward Inner Classes

The FixedStack class


public class FixedStack {
Object array[];
int top = 0;

FixedStack(int fixedSizeLimit) {array = new Object[fixedSizeLimit];}

public void push(Object item) {


array[top == array.length ? top - 1 : top++] = item;
}

public Object pop() {


return array[top == 0 ? top : top--];
}

public java.util.Enumeration getEnumeration() {


return new FixedStackEnum(this);
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Toward Inner Classes


An Enumeration class for FixedStacks
class FixedStackEnum implements java.util.Enumeration {
FixedStack theStack = null;
int count = top;

public FixedStackEnum(FixedStack theStack) {


this.theStack = theStack;
this.count = theStack.top;
}

public boolean hasMoreElements() {


return count > 0;
}

public Object nextElement() {


if (count == 0) {
throw new NoSuchElementException("FixedStack");
}
return theStack.array[--count];
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Inner Classes

Introduction
• JDK 1.1 introduced the key-concept of inner class
• An inner class is a class whose declaration appear within:
• class declarations
• method bodies
• expressions
• The aim is in enforcing the encapsulation providing a clean
way for structuring classes within a package. . .
• . . . we’ll see what it means in a moment!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Basic Definitions

The Scope of a class


• A class is associated to an enclosing scope which can be
• a package if the class is a toplevel class
• a class/method declaration if the class is an inner class

4 kinds of Inner Classes. . .


• Member Inner (MI) Classes
• Local Inner (LI) Classes
• Anonymous Inner (AI) Classes
• Static Inner (SI) Classes
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Member Inner Classes at a Glance


MI sample
public class FixedStack {
...

class FixedStackEnum implements java.util.Enumeration { //MI class!


int count = top; //LI classes can refer outer fields!

public boolean hasMoreElements() {return count > 0;}

public Object nextElement() {


if (count == 0) {
throw new NoSuchElementException("FixedStack");
}
return array[--count];
}
}
public java.util.Enumeration getEnumeration() {
return new FixedStackEnum();
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Member Inner Classes


Useful for...
• Hiding implementation details (private fields of a MI are
only accessible from the enclosing class’ scope)
• Expressing dependency beetween inner/enclosing class
instances (e.g a FixedStackEnum iterates over a given
FixedStack instance)

Properties
• A MI always have an enclosing instance which:
• must be specified when creating a new instance of a MI
fs.new FixedStackEnum(); //fs is a FixedStack
• can be accessed within a MI through the this keyword
FixedStack.this //within FixedStackEnum
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

MI with Private Constructors

Read-only classes

• A read-only class is a MI with private constructor(s)!


• The user won’t be able to instantiate that class directly. . .
• . . . but the enclosing class could to that!

A read-only class
public class FixedStack {
class FixedStackEnum implements Enumeration {
private FixedStackEnum() {...} //cannot access it from outside
}
...
}
...
FixedStack fs = new FixedStack(10);
FixedStack.FixedStackEnum it1 = fs.new FixedStackEnum();//error!
FixedStack.FixedStackEnum it1 = fs.getEnumeration();//ok!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Private MIs
Private MI
• What if a read-only class is itself declared as private?
• Access forbidden (not only instantiation) from outside. . .
• . . . the MI can thus be used only by its enclosing class

A read-only class
public class FixedStack {
/* cannot access it from outside */
private class FixedStackEnum implements Enumeration {
FixedStackEnum() {...} //cannot access it from outside
}
...
}
...
FixedStack fs = new FixedStack(10);
FixedStack.FixedStackEnum it1 = fs.new FixedStackEnum();//error!
FixedStack.FixedStackEnum it1 = fs.getEnumeration();//error!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Local Inner Classes at a Glance


LI sample
public class FixedStack {
...
public java.util.Enumeration getEnumeration() {

class E implements java.util.Enumeration { //LI class!


int count = top; //LI classes can refer outer fields!

public boolean hasMoreElements() {return count > 0;}

public Object nextElement() {


if (count == 0) {
throw new NoSuchElementException("FixedStack");
}
return array[--count];
}
};
return new E();
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Local Inner Classes


Useful for...
• Embedding a class declaration within the method’s body
which it is used
• Declaring classes to be used only locally (within the block
they are declared into)

Properties

• LI have the same visibility as variables in blocks


• LI may access any name available in ordinary expressions
within the same block (with some restrictions as we’ll see)
• as MI, LI have an enclosing instance. . .
• . . . but remember, LI have an enclosing method!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Sharing Local Variables

Accessing local variables within LI

• LI may access any variable available in ordinary expressions


within the block they are declared into. . .
• . . . provided the given variable is declared as final

An LI using a method’s argument


public class FixedStack {
...
public static java.util.Enumeration makeEnum(final Object[] array) {
class E implements java.util.Enumeration { //LI class!
int count = array.length; //can access ’array’ since it’s final
public boolean hasMoreElements() {return count > 0;}
...
};
return new E();
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Anonymous Inner Class at a Glance

AI sample
public class FixedStack {

public java.util.Enumeration getEnumeration() {


return new java.util.Enumeration() { //AI class!
int count = top; //AI classes can refer outer fields!

public boolean hasMoreElements() {return count > 0;}

public Object nextElement() {


if (count == 0) {
throw new NoSuchElementException("FixedStack");
}
return array[--count];
}
}; //we need the ’;’ since it’s an expression indeed!
}
...
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Anonymous Inner Classes


Useful for...
• Replacing a LI which would be used only once
• Defining the class of a method’s actual argument on-the-fly

Properties

• An AI is always a subtype of some type specified in the new


expression instantiating it. . .
• new Enumeration(){...};//subtype of Enumeration
• AI cannot have constructor declarations. . .
• . . . The argument list of an AI new expression is passed to a
matching constructor of the superclass.
• AI, as LI, may use local variables declared as final
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

More Fun with AI

AI in method calls
• There are situations in which we define a class only for
overriding a few methods of its superclass/superinterface

AI and Swing
public class GUI extends JFrame {
public GUI(final String msg) {
Button b;
add(b = new Button("Click Here!"));
b.setActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(GUI.this,"Hello! "+msg);
}
});
pack(); setVisible(true);
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

More Fun with AI

AI in method calls
• This tend to happen very frequently using Swing since we
have to define custom Listener classes for handling events

AI and Swing
public class GUI extends JFrame {
public GUI(final String msg) {
Button b;
add(b = new Button("Click Here!"));
b.setActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(GUI.this,"Hello! "+msg);
}
});
pack(); setVisible(true);
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Static Inner Classes at a Glance


SI sample
public class Graph {
static class Node { //SI class!
double x_coord;
double y_coord;
...
}

static class Arc { //SI class!


Node from; //we can use Node instead of Graph.Node
Node to;
...
}
private Node[] nodes; //we can use Node instead of Graph.Node
private Arc[] arcs; //we can use Node instead of Graph.Arc
...
}
...
Graph g = new Graph();
Graph.Node n1 = new Graph.Node(10,20); //full qualified name needed
Graph.Node n2 = new Graph.Node(20,10); //full qualified name needed
Graph.Arc a = new Graph.Arc(n1, n2); //full qualified name needed
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Static Inner Classes

Useful for...
• Modeling tightly coupled entities (a Graph is made up of
some Nodes and some Arcs)
• Providing meaningful namespaces (Graph.Node vs. Node)

Properties

• A SI is equivalent to a toplevel class (its enclosing scope is


always a package, no enclosing instance)
• SI can be instantiated using fully qualified identifiers
(Graph.Node, Graph.Arc, etc.)
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Brief Summary
Declaring an inner class

• MI and SI appear within the body of a class


• LI and AI appear within the body of a method

Accessing outer fields

• Both MI, LI and AI can refer to fields of their enclosing scope


• A SI can’t, since it doesn’t have an enclosing instance!

Creating an inner class


• Only MI and SI can be created from outside their scopes
• enclosingInstance.new MemberInner();
• new EnclosingClass.StaticInner();
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Compiling Inner Classes


Inner classes as toplevel classes

• javac translates inner classes into toplevel classes so that


each inner class has its own classfile
• This way JVM makes no distinction beetween inner and
toplevel classes at runtime!

Some complications. . .
• Must be taken into account that an inner class may access:
• one of its enclosing instances (MI, LI, AI)
• a final variable of its declaring scope (LI, AI);
• a field (even private ones) of its enclosing class(es)
• Some of the above aspect are quite not obvious (given two
classes A and B, how can A refer to a B’s private field?)
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Member Inner Classes Revised

FixedStack translated
public class FixedStack {
Object array[];
int top = 0;

FixedStack(int fixedSizeLimit) {array = new Object[fixedSizeLimit];}

public void push(Object item) {


array[top == array.length ? top - 1 : top++] = item;
}

public Object pop() {


return array[top == 0 ? top : top--];
}

public java.util.Enumeration getEnumeration() {


return new FixedStack$FixedStackEnum(this);
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Member Inner Classes Revised


FixedStackEnum translated
class FixedStack$FixedStackEnum implements java.util.Enumeration {

private FixedStack this$0; //enclosing instance!


int count;

FixedStack$FixedStackEnum(FixedStack this$0) {
this.this$0 = this$0;
int count = this$0.top; //outer field access!
}

public boolean hasMoreElements() {return count > 0;}

public Object nextElement() {


if (count == 0) {
throw new NoSuchElementException("FixedStack");
}
return this$0.array[--count];
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Translating Inner Classes into Toplevel Classes


Inner classes as toplevel classes
• When compiling the example two classfiles are generated:
• FixedStack.class
• FixedStack$FixedStackEnum.class
• Pay attention at how inner class names are encoded using ’$’
• And AI names? And name-clashing?

Accessing the enclosing instance

• The this$0 field is added by the compiler to the translated


class FixedStack$FixedStackEnum
• This way translated inner classes can still access fields of their
enclosing instances (e.g. this$0.top)
• What if the field to be accessed is private?
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Can We Do Better Than This?


HelloWorker
public class HelloWorker {
public void startWork() {
new WorkerThread().run();
}
}

class WorkerThread implements Runnable {


public void run() {
System.out.println("Hello World!");
}
}

Properties

• WorkerThread is visible to any class . . .


• . . . is there any way to make WorkerThread only available
within WorkerThread?
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Can We Do Better Than This?


HelloWorker (2)
public class HelloWorker {
public void startWork() {
new WorkerThread().run();
}

private static class WorkerThread implements Runnable {


public void run() {
System.out.println("Hello World!");
}
}
}

Properties

• WorkerThread is only available within WorkerThread. . .


• . . . what if we want WorkerThread to be accessed only within
startWork ?
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Can We Do Better Than This?

HelloWorker (3)
public class HelloWorker {
public void startWork() {
class WorkerThread implements Runnable {
public void run() {
System.out.println("Hello World!");
}
};
new WorkerThread().run();
}
}

Properties

• WorkerThread is only available within startWork


• It’s used only once. . . any idea?
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Can We Do Better Than This?


HelloWorker (4)
public class HelloWorker {

public void startWork() {


new Runnable {
public void run() {
System.out.println("Hello World!");
}
}.run();
}
}

Properties

• WorkerThread no longer exists. . .


• . . . It’s definition has been inlined directly into startWork to
achieve better encapsulation!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Outline

1 Inner Classes

2 Generics
Why Java Generics?
Generic Classes/Methods
Subtyping vs. Generics
Wildcards

3 Generics in JDK5.0

4 Runtime Generics

5 Conclusions
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Without Java Generics?

Numbers in JDK1.4’s Collection classes


public int[] toIntArray(Vector v) {
int[] res = new int[v.size()];
for (int i=0; i<v.size(); i++) {
res[i] = ((Number)v.get(i)).intValue();
}
return res;
}

...

Vector numbers;
numbers = new Vector();
numbers.add(new Integer(4));
...
numbers.add("One"); //OK for javac!
...
int[] intArr = toIntArray(numbers);
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Without Java Generics?

Numbers in JDK1.4’s Collection classes


Vector numbers; public int[] toIntArray(Vector v) {
numbers = new Vector(); int[] res = new int[v.size()];
numbers.add(new Integer(4)); for (int i=0; i<v.size(); i++) {
... res[i] = ((Number)v.get(i)).intValue();
numbers.add("One"); //OK for javac! }
... return res;
int[] intArr = toIntArray(numbers); }

Expressiveness & soundness

• Java syntax provides no way to enforce that both numbers


and v are Vectors of Numbers
• ClassCastExceptions may occur if:
• an element which is not a Number is added to numbers
• toIntValue is applied to a Vector whose element are not
Numbers
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

With Java Generics

Numbers in JDK5.0’s Collection classes


public int[] toIntArray(Vector<Number> v) {
int[] res = new int[v.size()];
for (int i=0; i<v.size(); i++) {
res[i] = v.get(i).intValue();
}
return res;
}

...

Vector<Number> numbers;
numbers = new Vector<Number>();
numbers.add(new Integer(4));
...
numbers.add("One"); //won’t compile!
...
int[] intArr = toIntArray(numbers);
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

With Java Generics

Numbers in JDK5.0’s Collection classes


Vector<Number> numbers; public int[] toIntArray(Vector<Number> v) {
numbers = new Vector<Number>(); int[] res = new int[v.size()];
numbers.add(new Integer(4)); for (int i=0; i<v.size(); i++) {
... res[i] = v.get(i).intValue();
numbers.add("One"); //won’t compile! }
... return res;
int[] intArr = toIntArray(numbers); }

Expressiveness & soundness

• Both numbers v are declared as Vectors of Numbers


• The compiler can check that:
• each element added to numbers is indeed a Number
• toIntArray is applied to a Vector of Numbers
• No more explicit cast is required!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Generics Types in JDK5.0

Generics are useful for. . .


• Abstracting code from types
• Improving compile-time support and code readability
(List<String> is more expressive than just List)

History

• the GJ (Generic Java) project, started in 1996, aimed to bring


support for parametric polymorphism into the Java language
• Since 2004 officially part of the JDK5.0 platform!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Declaring Generic Classes


A simple generic class
class List<E> {
E head;
List<E> tail;

List(E head, List<E> tail) {


this.head = head;
this.tail = tail;
}
List<E> append(E el) {
return nonEmpty() ? new List<E>(head, tail.append(el))
: new List<E>(el,new EmptyList<E>());
}
public boolean nonEmpty() {return true;}
}

class EmptyList<E> extends List<E> {


EmptyList() {super(null,null);}
public boolean nonEmpty() {return false;}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Declaring Generic Classes


A simple generic class
class List<E> {
E head;
List<E> tail;

List(E head, List<E> tail) {


this.head = head;
this.tail = tail;
}
List<E> append(E el) {
return nonEmpty() ? new List<E>(head, tail.append(el))
: new List<E>(el,new EmptyList<E>());
}
public boolean nonEmpty() {return true;}
}

Properties

• List<E> is a generic class declaring a type variable E


• E is a placeholder for concrete Java types
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Using Generic Classes

Sample using a generic class


List<Integer> li = new List<Integer>(0, new EmptyList<Integer>());
li = li.append(1);
Integer res = li.tail.head;

Properties

• When creating an instance of List<E> a concrete


instantiation must be provided for E (e.g. [E/Integer])
• Generic objects can be used as other Java objects!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Declaring Generic Methods

A simple generic method


class ListUtil {
public static <Z> List<Z> reverseList(List<Z> l) {
return l.nonEmpty() ? reverseList(l.tail).append(l.head)
: new EmptyList<Z>();
}
...
}

Properties

• <Z>reverseList is a generic method declaring a type


variable Z
• Z can only be referenced within the body of reverseList
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Using Generic Methods

Sample with a generic method call


List<String> ls = new List<String>("one",null);
ls = ls.append("two");
ls = ls.append("three");
List<String> rls2 = ListUtil.<String>reverseList(ls);

Properties

• When invoking <Z>reverseList a concrete instantiation


must be provided for Z (e.g. [Z/String])
• Alternatively, we could rely on type inference . . .
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Type-Inference Sounds Good. . .

Type-inference in method calls

• In a generic method call, there could be cases where


specifying the instantiation of the type parameter is useless
• JDK5.0 supports 2 ways of calling generic methods:
• type parameters can be specified programatically. . .
• . . . or they are inferred automatically by the compiler!

A sample with type-inference


EmpryList<String> els = new EmptyList<String>();
EmpryList<List<String>> ells = new EmptyList<List<String>>();
List<String> ls = new List<String>("one", els);
List<List<String>> lls = new List<List<String>>(ls,ells);
...
List<String> rls = ListUtil.<String>reverseList(ls); //[Z->String]
List<List<String>> rlls = ListUtil.reverseList(lls); //[Z->List<String>]
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

. . . But Not That Good!


Always the best?

• There are cases which don’t fit well with the inference scheme
• Often is better specifying method type parameters explicitly
(rather than relying on type inference)

When type-inference fails. . .


class ListUtil {
...
public static <Z> List<Z> make(Z head, List<Z> tail) {
return new List<Z>(head,tail);
}
public static <Z> List<Z> empty() {
return new EmptyList<Z>();
}
}
...
List<Float> lf = ListUtil.make("One", new EmptyList<Float>()); //[Z->?]
List<Object> lo = ListUtil.empty(); //default: [Z->Object]
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

More on Type Variables

Bounded polymorphism
• Instantiation of method/class type variable T can be
constrained by stating that T must:
• extend a given class (through extends)
• implement a given set of interfaces (through &)
• If no bound is specified, T extends Object is assumed

Bounded polymorphism in action


class List<E extends Number & Comparable<E>> {...}
class EmptyList<E extends Number & Comparable<E>> {...}
...
List<Integer> li = new List<Integer>(1, new EmptyList<Integer>()); //ok
List<Double> ld = new List<Double>(1, new EmptyList<Double>()); //ok
List<Float> lf = new List<Float>(1, new EmptyList<Float>()); //ok
...
List<String> ls = new List<String>("one", new EmptyList<String>());//ko!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Generic Quiz
A generic Cell
class Cell<E extends Number> {
E e;

public Cell(E e) {this.e = e;}

public static <K> Cell<K> makeCell(K k) {


return new Cell<K>(k);
}
}

Which statement is correct?


• Cell can be instantiated to Cell<String>
• Cell can only be instantiated to Cell<Number>
• Cell can only be instantiated to any Cell<T>, T <: Number
• This program compiles successfully
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Generic Quiz
A generic Cell
class Cell<E extends Number> {
E e;

public Cell(E e) {this.e = e;}

public static <K> makeCell(K k) {


return new Cell<K>(k);
}
}

Solutions
• Cell can only be instantiated to any Cell<T>, T <: Number
• This program won’t compile because of the type variable K in
makeCell. . . do you see why?
• Clue: it has to do with bounded polymorphism. . .
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Using Subtyping in Java

Playing with Pets


abstract class Pet {
String name;

Pet(String name) {this.name = name;}


abstract void sayHello();
}

class Doggy extends Pet {


Dog(String name) {super(name);}
void sayHello() {System.out.println("Woof");}
}

class Kitten extends Pet {


Kitten(String name) {super(name);}
void sayHello() {System.out.println("Meeow");}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Inclusive Polymorphism in Java

Inclusive polymorphism through subtyping


• Inheritance is a powerful tool for factorizing similar properties
into a common supertype:
• is-a relation: Doggy and Kitten are Pets in the since they
have all Pet’s properties (e.g. name)
• Code working on Pets also works on Kittens and Doggys

Playing with Pets


class Pets {
static void petGreetings(Pet[] pets) {
for (int i=0;i<pets.length;i++) {
pets[i].sayHello();
}
}
...
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Extending Subtyping to Generic Types

Subtyping vs. generics


• Generics and subtyping are orthogonal
• With generics, you reuse code
• With subtyping, you reuse classes

Subtyping beetween generic types?

• Given a generic class List<E> is there some useful relation


beetween List<Pet> and List<Kitten>?
• The answer is NO! But would be useful such a relation?
• If we could factorize List<Doggy>, List<Kitten>, . . . into a
common supertype we would be able to define functions
working with Lists of any Pet
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Java Arrays

Subtyping beetween Java arrays

• There is a similarity beetween Java arrays and generic types. . .


• . . . Pet[], Kitten[] can be thought of as Array<Pet>,
Array<Kitten>
• if S is a subtype of T (S <: T) then S[] <: T[] as well
• This is called covariance

Covariance in Java arrays

• Does covariance provide a sound subtyping beetween arrays?


• NO! Assigning an element to an array is unsafe!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

ArrayStoreCheck Required for Soundness

Arrays are unsafe


String[] as = new String[] {"One", "Two"};
Object[] ao = as; //this is legal
ao[0] = new Integer(2); //throws ArrayStoreException!

Making safe arrays

• The JVM enforce soundness in arrays assignments through a


runtime check
• This means that when an element is assigned to an array it is
checked to be type-compatible with the array’s type
• If check fails a runtime exception is thrown!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Factorizing Generic Types


Should generics be covariant?

• Factorizing generic types would be useful for defining more


general functions
• Covariance could be useful in factorizing generic types
• List<Kitten> <: List<Pet> since Kitten <: Pet!
• This leads to an unsound type system (as for arrays)

A different approach

• Instead of enforcing direct subtyping we could introduce new


types in order to factorize existing generic types
• This is called use-site variance (Igarashi, Viroli, ECOOP 2004)
• This is the approached exploited by JDK5.0’s wildcards!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Covariant Types in JDK5.0

Covariant Pets in action


class Pets {
static void petGreetings(List<? extends Pet> pets) {
while (pets.nonEmpty()) {
pets.head.sayHello();
pets = pets.tail;
}
}
...
}

...

List<Kitten> lk = ...
List<Doggy> ld = ...
List<Integer> li = ...
Pets.petGreetings(lk); //ok!
Pets.petGreetings(ld); //ok!
Pets.petGreetings(li); //NO!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Covariant Types in JDK5.0

Syntax and use of covariant types


• List<? extends T> is a covariant type which is supertype of
all List<S> where S <: T
• List<Kitten>, List<Doggy> <: List<? extends Pet>
• An element of type List<Kitten>, List<Doggy> can be
passed where a List<? extends Pet> is expected
• Useful for defining read-only functionalities

Covariant Pets in action


class Pets {
static void petGreetings(List<? extends Pet> pets) { List<Kitten> lk = ...
while (pets.nonEmpty()) { List<Doggy> ld = ...
pets.head.sayHello(); List<Integer> li = ...
pets = pets.tail; Pets.petGreetings(lk); //ok!
} Pets.petGreetings(ld); //ok!
} Pets.petGreetings(li); //NO!
...
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Contravariant Types in JDK5.0

Contravariant Pets in action


class Pets {
static void replaceWithDogs(List<? super Doggy> l) {
while (l.nonEmpty()) {
l.head = new Doggy("NewDog");
l = l.tail;
}
}
...
}

...

List<Object> lo = ...
List<Pet> lp = ...
List<Kitten> lk = ...
Pets.replaceWithDogs(lo); //ok!
Pets.replaceWithDogs(lp); //ok!
Pets.replaceWithDogs(lk); //NO!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Contravariant Types in JDK5.0

Syntax and use of contravariant types


• List<? super T> is a contravariant type which is supertype
of all List<S> where T <: S
• List<Object>, List<Pet> <: List<? super Doggy>
• An element of type List<Object>, List<Pet> can be passed
where a List<? super Doggy> is expected
• Useful for defining write-only functionalities

Contravariant Pets in action


class Pets {
static void replaceWithDogs(List<? super Doggy> l) { List<Object> lo = ...
while (l.nonEmpty()) { List<Pet> lp = ...
l.head = new Doggy("NewDog"); List<Kitten> lk = ...
l = l.tail; Pets.replaceWithDogs(lo); //ok!
} Pets.replaceWithDogs(lp); //ok!
} Pets.replaceWithDogs(lk); //NO!
...
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Bivariant Types in JDK5.0


Bivariant Pets in action
class Pets {
static int countPets(List<?> l) {
int petCount = 0;
while (l.nonEmpty()) {
petCount+ = (l.head instanceof Pet) ? 1 : 0;
l = l.tail;
}
return petCount;
}
...
}

...

List<Kitten> lk = ...
List<Doggy> ld = ...
List<Integer> li = ...
Pets.countPets(lk); //ok!
Pets.countPets(ld); //ok!
Pets.countPets(li); //ok!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Bivariant Types
Syntax and use of bivariant types
• List<?> is a bivariant type which is supertype of all List<S>
for every S.
• List<Object>, List<Pet>, List<Doggy> <: List<?>
• An element of type List<Object>, List<Pet>, List<Doggy>
can be passed where a List<?> is expected
• Useful for defining functionalities which do not read nor write

Bivariant Pets in action


class Pets {
static int countPets(List<?> l) {
int petCount = 0;
List<Kitten> lk = ...
while (l.nonEmpty()) {
List<Doggy> ld = ...
petCount+ = (l.head instanceof Pet) ? 1 : 0;
List<Integer> li = ...
l = l.tail;
Pets.countPets(lk); //ok!
}
Pets.countPets(ld); //ok!
return petCount;
Pets.countPets(li); //ok!
}
...
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Wildcards as Intervals

An useful metaphore

• You can think of a wildcard C<? [(extends|super) T]> as


a mathematical interval defined in the type space
• This interval is made up of all types S for which C<S> is a
subtype of the above wildcard type
• Consider as an example:
List<? extends Pet> =⇒ [Pet,nulltype]
List<? super Pet> =⇒ [Object,Pet]
List<?> =⇒ [Object,nulltype]
List<Doggy> =⇒ [Doggy,Doggy]
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Drawing Wildcards

List<?>

List<? super Pet>

List<? extends Pet>

List<Doggy>

Object Pet Doggy nulltype


Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Interval Intuition Useful for Subtyping


Generics vs. wildcards
• Wildcard subtyping can be thought of as an interval
containment test
• Given a generic type T and a wildcard W,if W’s interval
contains T then T <: W
• List<Doggy> <: List<?>
• List<Doggy> <: List<? extends Pet>

Wildcards vs. wildcards


• Given two wildcards W and Y,if Y’s interval contains W’s
interval then W <: Y
• List<? extends Doggy> <: List<? extends Pet>
• List<? super Pet> <: List<? super Kitten>
• List<? extends Pet> <: List<?>
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Subtyping at a Glance

List<?>

List<? super Pet>

List<? extends Pet>

List<Doggy>

Object Pet Doggy nulltype


Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Wildcards Quiz
1
List<?>

Object Number nulltype

2
List<? extends Number>

Object Number nulltype

3
List<? super Number>

Object Number nulltype


Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Wildcards Quiz Solved


1
List<?>

Object Number nulltype

2
List<? extends Number>

Object Number nulltype

3
List<? super Number>

Object Number nulltype


Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Outline

1 Inner Classes

2 Generics

3 Generics in JDK5.0
Java Collection Framework
Remarkable Generic Interfaces
Java Reflection API

4 Runtime Generics

5 Conclusions
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Generics and Wildcards in JDK5.0

The generified JDK

• Some part of the standard JDK have been generified


• That is they have been extended so to exploit generic types
and wildcards

Samples

• Java Collection Framework


• core Java interfaces (e.g. Comparable)
• Java Reflection API
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Generic Collection Framework

How JCF has been generified

• All collection classes have been generified!


• Some remarkable examples are:
• Vector<E>
• ArrayList<E>
• HashSet<E>
• HashMap<K,V>
• ...
• All collection classes are subtype of Collection<E>
• Since Collection<E> implements Iterable<E> all collection
classes can be used within enhanced for loops!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Generic JCF Samples

Pets and Vectors


Vector<Pet> vp = new Vector<Pet>();
vp.add(new Doggy("MyDog");
vp.add(new Kitten("MyKitten");
...
for (int i=0;i<vp.size();i++) {
vp.get(i).sayHello();
}

Pets and HashMaps


HashMap<String,Pet> map = new HashMap<String,Pet>();
map.put("Simon", new Doggy("Snoopy");
map.put("Paul", new Kitten("Kitty");
...
Set<Map.Entry<String,Pet>> entries = map.entrySet();
Iterator<Map.Entry<String,Pet>> entryIterator = entries.iterator();
while (entryIterator.hasNext()) {
entryIterator.next().getValue().sayHello();
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Iterating Collections in JDK1.4

Obtaining an Iterator

• JCF provides a mechanism for iterating elements of a given


collection class
• Every collection class must implements the iterator method
• This method returns an Iterator object whose methods can
be used for iterating through the collection’s elements:

The JDK1.4’s Iterator interface


interface Iterator {
boolean hasNext()
Object next()
void remove()
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Iterating Collections in JDK5.0

The Iterable interface


• Collection<E> now implements the interface Iterable<E>
• Iterable<E> is a one-method interface defining the method
Iterator<E> iterator()

The JDK5.0’s Iterator class


interface Iterator<E> {
boolean hasNext()
E next()
void remove()
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

A Pattern for Iterating Collections

Iterating a Collection
• For iterating all elements of a given collection c you can use
the following pattern
1. retrieve an Iterator object i through c.iterator()
2. if i.hasNext() = false we’re done; otherwise. . .
3. retrieve next c’s element through i.next()
4. repeat from step 2
• Or you can let Java do the task for you!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

JCF Sample Revised

Without enhanced for


HashMap<String,Pet> map = new HashMap<String,Pet>();
map.put("Simon", new Doggy("Snoopy");
map.put("Paul", new Kitten("Kitty");
...
Set<Map.Entry<String,Pet>> entries = map.entrySet();
Iterator<Map.Entry<String,Pet>> entryIterator = entries.iterator();
while (entryIterator.hasNext()) {
entryIterator.next().getValue().sayHello();
}

With enhanced for


HashMap<String,Pet> map = new HashMap<String,Pet>();
map.put("Simon", new Doggy("Snoopy");
map.put("Paul", new Kitten("Kitty");
...
for (Map.Entry<String,Pet> entry : map.entrySet()) {
entry.getValue().sayHello();
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Enhanced for Loop

Iterating Iterable classes

• All classes implementing the Iterable interface can be used


within enhanced for loops
• The enhanced for loop is a brand new feature of JDK5.0
• Other languages already have similar capabilities
• e.g. C#’s foreach statement

for (VarDecl : Expression)

• Iterates through all the elements of the Iterable object


specified in Expression
• each round assigning an element to the variable in VarDecl
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Building an Iterable List


Extending our List
class IterableList<E> extends List<E> implements Iterable<E> {

IterableList(E head, List<E> tail) {super(head, tail);}

public java.util.Iterator<E> iterator() {


class IterableListIterator<K> implements java.util.Iterator<K> {
List<K> list = null;

IterableListIterator(IterableList<K> l) {this.list = l;}


public boolean hasNext() {return list.nonEmpty();}
public K next() {
K temp = list.head;
list = list.tail;
return temp;
}
public void remove() {throw UnsupportedOperationException();}
};
return new IterableListIterator<E>(this);
}
...
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

The Comparable interface

Comparing Objects

• All comparable objects must implements the Comparable<E>


interface
• Comparable<E> is a one-method interface defining the
method int compareTo(E o)

Use of Comparable in java.util.Collections


<T extends Comparable<? super T>> T sort(List<T> list)

<T extends Comparable<? super T>> T min(Collection<? super T> coll)

<T extends Comparable<? super T>> T max(Collection<? super T> coll)

<T> int binarySearch(List<? extends Comparable<? super T>> list, T key)


Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

The Comparator Interface

Another way of comparing Objects

• Objects can also be compared by the means of an object


implementing the Comparator interface
• Comparator<E> is an interface defining the methods int
compare(E e1, E e2) and boolean equals(E e)

Use of Comparator in java.util.Collections


<T> void sort(List<T> list, Comparator<? super T> c)

<T> void min(Collection<? extends T> list, Comparator<? super T> c)

<T> void max(Collection<T extends T> list, Comparator<? super T> c)

<T> int binarySearch(List<? extends T> l, T k, Comparator<? super T> c)


Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Comparing Pets
Another Pet class
abstract class Pet implements Comparable<Pet> {
String name;

Pet(String name) {
this.name = name;
}
public int compareTo(Pet pet) {
return name.compareTo(pet.name);
}
abstract void sayHello();
}

Sorting Pets
ArrayList<Doggy> ald = new ArrayList<Doggy>();
ald.add(new Doggy("3:Snoopy"));
ald.add(new Doggy("1:Pippo"));
ald.add(new Doggy("2:Pluto"));
java.util.Collections.sort(ald);
System.out.println(ald);
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Again on Generics in JCF


java.util.Collections
<T> void fill(List<? super T> list, T obj)

<T> void copy(List<? super T> dest, List<? extends T> src)

boolean disjoint(Collection<?> c1, Collection<?> c2)

int frequency(Collection<?> c, Object o)

int indexOfSubList(List<?> source, List<?> target)

void shuffle(List<?> list)

java.util.Collection<E>
boolean addAll(Collection<? extends E> c)

boolean removeAll(Collection<?> c)

boolean retainAll(Collection<?> c)
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Generics in the Reflection API

Not only Collections!

• Class<T> is a parameterized class in the JDK5.0


• Here, T stands for the class represented by the Class object
• A number of methods in Class<T> have been redefined in
order to match with the new generic signature
• Class<? super T> getSuperclass()
• T newInstance()
• isAssignableFrom(Class<?> cls)
• <U> Class<? extends U> asSubclass(Class<U> clazz)
• Moreover, the Object’s Class getClass() method has
been redefined as <T> Class<? extends T> getClass()
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Outline

1 Inner Classes

2 Generics

3 Generics in JDK5.0

4 Runtime Generics
Compile time vs. Runtime Approach
Type Erasure in JDK5.0
Generic Types at Runtime
A Case Study: Generic Arrays

5 Conclusions
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Choosing the Right Implementation


Compile time approach
• Generic code can be translated into plain Java leaving
bytecode generation phase untouched
• Once compiled, generic code can run on every JVM!
• This is the implementation scheme exploited in JDK5.0

Runtime approach
• Direct support for generics into the JVM affects:
• core classes (e.g. ClassLoader)
• classfile format
• JVM’s runtime type system
• Generic code only runs on generic JVMs
• Better performances but compatibility issues!
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Type Erasure in JDK5.0

Generic types erased by javac!

• In JDK5.0 generics are implemented through a compile time


technique called erasure
• Erasure transform a generic Java as follows:
1. Type variables are removed from generic class/method
declarations (e.g. class List<E> ⇒ class List)
2. Type variables within a generic class are replaced by their
bounds (e.g. E ⇒ Object)
3. Generic expressions are replaced with non-generic ones (e.g.
new List<String> ⇒ new List)
4. Synthetic cast added to preserve soundness
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Erasing Lists
Generic List
class List<E> {
E head;
List<E> tail;

List(E head, List<E> tail) {


this.head = head;
this.tail = tail;
}
List<E> append(E el) {
return nonEmpty()
? new List<E>(head, tail.append(el))
: new List<E>(el,new EmptyList<E>());
}
public boolean nonEmpty() {
return true;
}
}
class EmptyList<E> extends List<E> {
EmptyList() {super(null,null);}
public boolean nonEmpty() {return false;}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Erasing Lists
Generic List translated
class List {
Object head;
List tail;

List(Object head, List tail) {


this.head = head;
this.tail = tail;
}
List append(Object el) {
return nonEmpty()
? new List(head, tail.append(el))
: new List(el,new EmptyList());
}
public boolean nonEmpty() {
return true;
}
}
class EmptyList extends List {
EmptyList() {super(null,null);}
public boolean nonEmpty() {return false;}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

The Need of Synthetic Cast


Correctness of the erased code
• Correctness of Java bytecode has to be preserved when:
• calling a method whose return type has been erased
• accessing a field whose type has been erased
• The compiler must ensure type-safety with an explicit cast!

Generic List client


List<Integer> li = new List<Integer>(0, new EmptyList<Integer>());
li = li.append(1);
List<Integer> tail = li.tail;
Integer res = tail.head;

Generic List client translated


List li = new List(0, new EmptyList());
li = li.append(1);
List tail = li.tail;
Integer res = (Integer)tail.head;
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Runtime Generics

Generic types not available at runtime

• Unfortunately, erasing types through erasure means that the


JVM knows nothing about generics!
• Both generic and wildcard types are said to be non-reifiable
types (not available at runtime)
• Cannot test if a given object is of a non-reifiable types
• Cannot create an array of a non-reifiable type
• Cast to non-reifiable types allowed but not safe!
• In other words, no type-dependent operation allowed for
generic/wildcard types
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Unchecked Type Conversion Lead to Heap Pollution

Unckecked warnings

• A cast to a generic type raises an unchecked warning


• This tells us that the compiler has no way to statically check
the correctness of the type conversion operation

Bad generic cast


List<Integer> li = new List<Integer>(0, new EmptyList<Integer>());
Object unknownList = li;
List<String> ls = (List<String>)unknownList; //unchecked warning!
String s = ls.head; //ClassCastException

Bad generic cast translated


List li = new List(0, new EmptyList());
Object unknownList = li;
List ls = (List)unknownList; //ok!
String s = (String)ls.head; //ClassCastException
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Generics Arrays not Allowed

Generic arrays are unsound

• If compiler would let us create generic arrays even legal code


(no warnings raised at compile time) might fail at runtime
• The resulting type system would be unsound!

Getting rid of generic arrays


List<Integer>[] liarr = new List<Integer>[5];//won’t compile
liarr[0] = new List<Integer>(0, new EmptyList<Integer>());
List[] rawarr = liarr;
rawarr[1] = new List<String>("one", new EmptyList<String>());
Integer i = liarr[1].head; //would fail at runtime
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

The Problem of Generic Arrays

A (non-working) generic FixedStack


public class FixedStack<E> {

E[] array;
int top = 0;

FixedStack(int fixedSizeLimit) {
array = new E[fixedSizeLimit]; //won’t compile!
}

public void push(E item) {


array[top == array.length ? top - 1 : top++] = item;
}

public E pop() {
return array[top == 0 ? top : top--];
}
...
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

A Possible Workaround

Another generic FixedStack


public class FixedStack<E> {

Object[] array;
int top = 0;

FixedStack(int fixedSizeLimit) {
array = new Object[fixedSizeLimit]; //ok!
}

public void push(E item) {


array[top == array.length ? top - 1 : top++] = item;
}

public E pop() {
return (E)array[top == 0 ? top : top--]; //unchecked warning!
}
...
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Another Workaround

Yet another generic FixedStack


public class FixedStack<E> {

E[] array;
int top = 0;

FixedStack(int fixedSizeLimit) {
array = (E[])new Object[fixedSizeLimit]; //unchecked warning!
}

public void push(E item) {


array[top == array.length ? top - 1 : top++] = item;
}

public E pop() {
return array[top == 0 ? top : top--]; //ok!
}
...
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

How do We Write A Generic Stack?

Lack of generic arrays as a huge problem

• Classes as FixedStack cannot be generified!


• All workarounds ends up in raising unchecked warnings!
• To be used only if you know what you’re doing!
• JDK5.0 itself contains classes (e.g. Vector<E>) raising
unchecked warning!
• Is this a problem?
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Breaking the JCF

An UnsafeVector
class UnsafeVector<E> extends java.util.Vector<E> {

/* java.util.Vector stores its elements into an array


* called elementData
*/
public boolean add(E o) {
super.add(o); //first, we add the element
elementData[size()-1] = o.toString();//then we replace it!
return true;
}
}

UnsafeVector is... unsafe!


UnsafeVector<Integer> uv = new UnsafeVector<Integer>();
uv.add(new Integer(1));
Integer i = uv.get(0); //throws a class cast exception - see why?
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Outline

1 Inner Classes

2 Generics

3 Generics in JDK5.0

4 Runtime Generics

5 Conclusions
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Now That You Are An Advanced Java Programmer. . .

What you should have learned in this talk


• Inner Classes
• The need for inner classes
• How to improve your code exploiting inner classes
• How inner classes are supported by the JDK
• Generics & Wildcards
• The need for generics/wildcards
• Writing reusable code exploiting generics/wildcards
• How generics/wildcards are implemented in JDK5.0

Putting things together

• It’s time for something more challenging. . .


Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Do You Remember This?. . .

The PermutationUtility class


import alice.tuprolog.*;
import java.util.*;

class PermutationUtility{
private static String theory =
"remove([X|Xs],X,Xs). \n" +
"remove([X|Xs],E,[X|Ys]):-remove(Xs,E,Ys). \n" +
"permutation([],[]). \n" +
"permutation(Xs,[X|Ys]):-remove(Xs,X,Zs),permutation(Zs,Ys).";

public static Iterable<List<Integer>> permutations(...) {...}


private static class PermutationIterable ... {...}
public static void main(...) {...}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Do You Remember This?. . .


The permutations method
static Iterable<List<Integer>> permutations(Collection<Integer> c) {
String list="[";
boolean first=true;
for (Integer i : c){
list = list+((!first)?",":"")+i;
first=false;
}
list=list+"]";
try {
Prolog engine=new Prolog();
Term goal=new Struct("permutation",engine.toTerm(list),new Var("X"));
System.out.println(goal);
engine.setTheory(new Theory(theory));
return new PermutationIterable(engine,goal);
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Do You Remember This?. . .

The PermutationIterable inner class


static class PermutationIterable implements Iterable<List<Integer>>{
private Prolog p;
private SolveInfo s;

PermutationIterable(Prolog p, Term goal){


this.p=p;
try{
s=p.solve(goal);
}
catch (Exception e) {
s=null;
};
}

public Iterator<List<Integer>> iterator() {...}


}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Do You Remember This?. . .


The PermutationIterable’s iterator method
public Iterator<List<Integer>> iterator(){
return new Iterator<List<Integer>>(){
public boolean hasNext(){
return (s!=null) && s.isSuccess() && p.hasOpenAlternatives();
}
public List<Integer> next(){
List<Integer> l=new LinkedList<Integer>();
try{
Iterator i=((Struct)s.getTerm("X")).listIterator();
for (;i.hasNext();){
l.add(new Integer(((Int)i.next()).intValue()));
}
s=p.solveNext();
} catch (Exception e){e.printStackTrace();}
return l;
}
public void remove(){} //not implemented yet!!
};
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Do You Remember This?. . .

The PermutationUtility’s main method


public static void main(String[] s) throws Exception{
List<Integer> l=new LinkedList<Integer>();
l.add(1);
l.add(2);
l.add(3);
l.add(4);
l.add(5);
l.add(6);
l.add(7);

/* since PermutationIterable is an Iterable class...


* ...we can use it within an enhanced for loop!
*/

for (List<Integer> lout : permutations(l)){


System.out.println(lout);
}
}
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Any Question?
Inner Classes Generics Generics in JDK5.0 Runtime Generics Conclusions

Advanced Java Programming

Maurizio Cimadamore
mcimadamore@deis.unibo.it

DEIS
Alma Mater Studiorum—Università di Bologna

Computational Models and Languages, A.A. 2006/2007

You might also like