Inner Classes Generics Generics in JDK5.
0 Runtime Generics Conclusions
Advanced Java Programming
Maurizio Cimadamore
[email protected]
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
[email protected]
DEIS
Alma Mater Studiorum—Università di Bologna
Computational Models and Languages, A.A. 2006/2007