Download presentation
Presentation is loading. Please wait.
1
Java Generics
2
2 The Dark Ages: Before Java 5 Java relied only on inclusion polymorphism A polymorphism code = Using a common superclass Every class is a subclass of java.lang.Object So there's always at least one common superclass Collections were actually collections of objects You can put anything into a collection When you extract something, its static type is Object
3
3 Java 5 and Beyond Parametric polymorphism introduced in Java 5 September 2004 Most significant enhancement since Java's birth May resemble C++ templates, but: Implemented differently “Compile once and for all” Better error messages Type constraints are explicit Less power (e.g., cannot inherit from a type parameter) Parameters can only be types No executable blowup
4
4 Generics – Before and After // Without generics List list = new ArrayList(); list.add(new Integer(0)); Integer x = (Integer) list.get(0); // Programmer must downcast list.add("abc"); Integer y = (Integer) list.get(1); // Run -time exception // With Generics – The compiler “knows” the type of the list elements List list = new ArrayList (); list.add(new Integer(0)); Integer x = list.get(0); list.add("abc"); // Compiler Error – Expected ineteger
5
5 A Generic Method public static List dup(T t, int n) { List result = new ArrayList (); for(int i = 0; i < n; ++i) result.add(t); return result; }... List list = dup("abc", 2); // Implicit instantiation // Explicit not supported...
6
6 Recap: java.lang.Integer, Number package java.lang; public abstract class Number { public abstract int intValue(); public abstract long longValue(); public abstract float floatValue(); public abstract double doubleValue(); public byte byteValue() { return (byte) intValue(); } public short shortValue() { return (short) intValue(); } } package java.lang; public final class Integer extends Number { private final int n; public Integer(int v) { n = v; } public int intValue() { return n; } public long longValue() { return (long) n; } public float floatValue() { return (float) n; } public double doubleValue() { return (double) n; } }
7
7 The Cell class public class Cell { private T value; public T get() { return value; } public void set(T t) { value = t; } // T is at least an Object, so it supports toString() public String toString() { return value.toString(); } }
8
8 Using Cell Using Cell static void main(String[] args) { Cell ci = new Cell (); ci.set(new Integer(5)); System.out.println(ci.get()); int n = ci.get(); // auto-unboxing n = n*n; ci.set(n); // auto-boxing System.out.println(ci.get()); Cell cn = new Cell (); cn.set(ci.get()); }
9
9 Type Parameters with Upper Bounds public class NumberCell { private T value; public T get() { return value; } public void set(T t) { value = t; } public String toString() { return value.toString(); } // T is at least a Number, so it supports intValue() public int sum(int x) { return value.intValue() + x; } } The extend keyword specifies an upper bound for T Can be used with both classes and interfaces Can have multiple bounds: T extends MyClass & MyInterface
10
10 Cell is not compatible with Cell Cell is not compatible with Cell static void assign(Cell co, Object o) { co.set(o); } void main() { Cell ci = new Cell (); assign(ci, new Integer(10)); // Compiler error: // Cannot convert from Cell to Cell // Otherwise, the following code would break at run time assign(ci, "abc"); Integer n = ci.get(); System.out.println(n.intValue()); } The same conformance issue as with covariant input arguments
11
11 A better version of assign() static void assign(Cell co, T o) { co.set(o); } void main() { Cell ci = new Cell (); assign(ci, new Integer(10)); // Now it works }
12
12 The Wildcard: The Wildcard: static > boolean isNullA(C c) { T t = c.get(); return t == null; } static > boolean isNullB(C c) { return c.get() == null; } static boolean isNullC(Cell c) { return c.get() == null; } If a type parameter is used exactly once – and this occurrence is inside an upper bound – it can be replaced with a wildcard If a type parameter is used exactly once – and this occurrence is as a type of formal parameter of the method – it can be replaced with its upper bound
13
13 Wildcard: Type Checking Rules static boolean isNullC(Cell c) {... } Inside isNullC() : ? Cannot be used to declare the type of a variable c.get() return an Object c.set(o) is not allowed, even if o is of type Object. Exception to this rule: c.set(null) is allowed For every type Y, the type X is a supertype of X
14
14 Lower Bounds public static class Cell { private T value; public T get() { return value; } public void set(T t) { value = t; } public void copyTo(Cell c) { c.set(value); } } The super keyword specifies a lower bound for a wild-card Cannot be used with regular type parameters
15
15 Implementation of Generics: Type Erasure Compiling a Generic class: Cell Check: Type correctness Erase: Replace T with its upper bound ( Object ) Compile: to byte code Compiling an instantiation: Cell c; Replace: The instantiated type with the raw type Annotate: add a “footnote” specifying the substitution: c: T = String The annotation is saved in the class file declaring c Compiling a field access or a message send: c.get() Obtain: The annotation of the receiver variable, c Check: Actual method parameters against the actual type parameters (None in this example) Downcast: insert a cast of the return type to the actual type parameter, String
16
16 Type Erasure Benefit of Erasure: Binary compatibility with older libraries: List is translated to type List (raw type ) Code compiled using a "pre-generics" class works correctly Code written using a "pre-generics" class still compiles and work Drawback of Erasure generic type information is not known at runtime List and List refer to List type variables cannot be used in new expressions Type is unknown at runtime
17
17 Type Erasure: Example Generic form class Foo { T m(Set s) { } } Erased form: class Foo { Number m(Set s){} }
18
18 Erasure: Loophole List list = new ArrayList (); Object o = list; List err = (List ) o; // Warning: Unchecked Conversion err.add("abc"); Integer i = list.get(0); // Runtime error: cast from String to Integer Unchecked conversion warning Issued by the compiler when we use an instantiated type in a position where only the raw type is available Usually appears when we cast to an instantiated generic type The downcast check will be partial Indicates a danger of type errors at run time Avoid at all costs
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.