# java-generics-tutorial **Repository Path**: lin_andy/java-generics-tutorial ## Basic Information - **Project Name**: java-generics-tutorial - **Description**: Java泛型相关,Java泛型教程 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 4 - **Created**: 2023-03-11 - **Last Updated**: 2023-03-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Java泛型教程 ## 泛型类(generic class) ### 泛型类(generic class) 泛型类声明:在普通类声明后跟一个**类型参数**(type parameter)。 泛型类的*类型参数部分*可以有一个或多个用逗号分隔的**类型参数**。 这些类称为**参数化类**(parameterized classes)或**参数化类型**(parameterized types),因为它们接受一个或多个参数。 #### 语法 ```java public class Box { private T t; } ``` 其中: - **Box** − Box 是一个泛型类 - **T** − 传递给泛型类的一个泛型参数. 它可以是. - **t** − 泛型T的实例。 T是传递给泛型类Box的类型参数,应在创建Box对象时传递。 #### 例子 com.theten52.tutarial.generics.a0.GenericsTester ```java public class GenericsTester { public static void main(String[] args) { Box integerBox = new Box(); Box stringBox = new Box(); integerBox.add(new Integer(10)); stringBox.add(new String("Hello World")); System.out.printf("Integer Value :%d\n", integerBox.get()); System.out.printf("String Value :%s\n", stringBox.get()); } } class Box { private T t; public void add(T t) { this.t = t; } public T get() { return t; } } ``` #### 输出 ```text Integer Value :10 String Value :Hello World ``` ### 类型参数(type parameter)的命名约定 按照惯例,类型参数名称被命名为单个大写字母,因此可以轻松区分一个名称是*类型参数*还是*普通的类或接口*。 以下是常用类型参数名称列表: - **E** - Element,主要由Java集合框架使用。 - **K** - Key,主要用于表示Map中键的参数类型。 - **V** - Value,主要用于表示Map中值的参数类型。 - **N** - Number,主要用于表示数字。 - **T** - Type,主要用于表示第一个泛型类型参数。 - **S** - Type,主要用于表示第二个泛型类型参数。 - **U** - Type,主要用于表示第三个泛型类型参数。 - **V** - Type,主要用于表示第四个泛型类型参数。 #### 例子 ```java import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class GenericsTester { public static void main(String[] args) { Box box = new Box(); box.add(Integer.valueOf(10),"Hello World"); System.out.printf("Integer Value :%d\n", box.getFirst()); System.out.printf("String Value :%s\n", box.getSecond()); Pair pair = new Pair(); pair.addKeyValue("1", Integer.valueOf(10)); System.out.printf("(Pair)Integer Value :%d\n", pair.getValue("1")); CustomList list = new CustomList(); list.addItem(box); System.out.printf("(CustomList)Integer Value :%d\n", list.getItem(0).getFirst()); } } class Box { private T t; private S s; public void add(T t, S s) { this.t = t; this.s = s; } public T getFirst() { return t; } public S getSecond() { return s; } } class Pair{ private Map map = new HashMap(); public void addKeyValue(K key, V value) { map.put(key, value); } public V getValue(K key) { return map.get(key); } } class CustomList{ private List list = new ArrayList(); public void addItem(E value) { list.add(value); } public E getItem(int index) { return list.get(index); } } ``` #### 输出 ```text Integer Value :10 String Value :Hello World (Pair)Integer Value :10 (CustomList)Integer Value :10 ``` ### 类型推断(Type Inference) **类型推断**表示Java编译器有能力去查看方法调用及其相应的声明,以检查和确定类型参数。 类型推断算法检查参数的类型,如果可用,则返回分配的类型。 类型推断算法尝试查找可以填充所有类型参数的特定类型。 如果不使用类型推断,则编译器会生成未经检查的转换警告。 #### 语法 ```java Box integerBox = new Box<>(); ``` 其中: - **Box** − Box是一个泛型类。 - **<>** − 菱形运算符表示类型推断。 使用菱形运算符,编译器确定参数的类型。 从Java SE 7版开始,此运算符可以使用。 #### 例子 ```java public class GenericsTester { public static void main(String[] args) { //类型推断 Box integerBox = new Box<>(); Box stringBox = new Box(); integerBox.add(new Integer(10)); stringBox.add(new String("Hello World")); System.out.printf("Integer Value :%d\n", integerBox.get()); System.out.printf("String Value :%s\n", stringBox.get()); } } class Box { private T t; public void add(T t) { this.t = t; } public T get() { return t; } } ``` ### 泛型方法(generic method) 您可以编写一个可以使用不同类型的参数调用的***泛型方法***声明。 根据传递给泛型方法的***参数类型***,编译器会适当地处理每个方法调用。 以下是定义泛型方法的规则: - 所有泛型方法声明都有一个由尖括号(“<”和“>”)分隔的类型参数部分,它位于方法的返回类型之前。 - 每个类型参数部分包含一个或多个以逗号分隔的类型参数。 类型参数(也称为类型变量【type variable】)是指定泛型类型名称的标识符。 - 类型参数可用于声明返回类型,并充当传递给泛型方法的参数类型的占位符,这些参数称为***实际类型参数(actual type arguments)***。 - 泛型方法的方法体声明为任何其他方法的方法体。 请注意,类型参数只能表示引用类型,而不能表示基本类型(如int,double和char)。 #### 例子 ```java public class GenericMethodTest { // 泛型方法 printArray public static void printArray( E[] inputArray ) { // 打印数组元素 for(E element : inputArray) { System.out.printf("%s ", element); } System.out.println(); } public static void main(String args[]) { // 创建 Integer, Double and Character 数组 Integer[] intArray = { 1, 2, 3, 4, 5 }; Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 }; Character[] charArray = { 'H', 'E', 'L', 'L', 'O' }; System.out.println("Array integerArray contains:"); printArray(intArray); // 传入一个 Integer 数组 System.out.println("\nArray doubleArray contains:"); printArray(doubleArray); // 传入一个 Double 数组 System.out.println("\nArray characterArray contains:"); printArray(charArray); // 传入一个 Character 数组 } } ``` #### 输出 ```text Array integerArray contains: 1 2 3 4 5 Array doubleArray contains: 1.1 2.2 3.3 4.4 Array characterArray contains: H E L L O ``` ### 多类型参数(Multiple Type Parameters) 泛型类可以具有多个类型参数。以下示例将展示上述概念。 #### 例子 ```java public class GenericsTester { public static void main(String[] args) { Box box = new Box(); box.add(Integer.valueOf(10),"Hello World"); System.out.printf("Integer Value :%d\n", box.getFirst()); System.out.printf("String Value :%s\n", box.getSecond()); Box box1 = new Box(); box1.add("Message","Hello World"); System.out.printf("String Value :%s\n", box1.getFirst()); System.out.printf("String Value :%s\n", box1.getSecond()); } } class Box { private T t; private S s; public void add(T t, S s) { this.t = t; this.s = s; } public T getFirst() { return t; } public S getSecond() { return s; } } ``` #### 输出 ```text Integer Value :10 String Value :Hello World String Value :Message String Value :Hello World ``` ### 参数化类型(Parameterized Types) 泛型类可以具有参数化类型,其中类型参数可以替换为参数化类型。以下示例将展示上述概念。 #### 例子 ```java import java.util.ArrayList; import java.util.List; public class GenericsTester { public static void main(String[] args) { Box> box = new Box>(); List messages = new ArrayList(); messages.add("Hi"); messages.add("Hello"); messages.add("Bye"); box.add(Integer.valueOf(10),messages); System.out.printf("Integer Value :%d\n", box.getFirst()); System.out.printf("String Value :%s\n", box.getSecond()); } } class Box { private T t; private S s; public void add(T t, S s) { this.t = t; this.s = s; } public T getFirst() { return t; } public S getSecond() { return s; } } ``` #### 输出 ```text Integer Value :10 String Value :[Hi, Hello, Bye] ``` ### 原始类型(Raw Types) 原始类型:一个泛型类虽然定义了类型参数,但是使用时并未给其赋值。此时我们称此类型成为原始类型。 如果原始类型的类型参数在创建过程中未传递,则原始类型是通用类或接口的对象。以下示例将展示上述概念。 #### 例子 ```java public class GenericsTester { public static void main(String[] args) { Box box = new Box(); box.set(Integer.valueOf(10)); System.out.printf("Integer Value :%d\n", box.getData()); Box rawBox = new Box(); //不会有编译警告 rawBox = box; System.out.printf("Integer Value :%d\n", rawBox.getData()); //set(T) 方法会有一个 Unchecked call 的 Warning rawBox.set(Integer.valueOf(10)); System.out.printf("Integer Value :%d\n", rawBox.getData()); //此行代码会有一个 Unchecked assignment 的 Warning box = rawBox; System.out.printf("Integer Value :%d\n", box.getData()); } } class Box { private T t; public void set(T t) { this.t = t; } public T getData() { return t; } } ``` #### 输出 ```text Integer Value :10 Integer Value :10 Integer Value :10 Integer Value :10 ``` ## 有界类型(Bounded Type) ### 有界类型参数(Bounded Type Parameters) 有时您可能想限制允许传递给类型参数的类型的种类。例如,对Number进行操作的方法可能只希望接受Number或其子类的实例。这就是有界类型参数的用途。 要声明一个有界的类型参数,请列出类型参数的名称,然后列出extends关键字,然后列出其上限。 #### 例子 ```java public class MaximumTest { // 确定三个可比较对象中的最大对象 public static > T maximum(T x, T y, T z) { T max = x; // assume x is initially the largest if(y.compareTo(max) > 0) { max = y; // y is the largest so far } if(z.compareTo(max) > 0) { max = z; // z is the largest now } return max; // returns the largest object } public static void main(String args[]) { System.out.printf("Max of %d, %d and %d is %d\n\n", 3, 4, 5, maximum( 3, 4, 5 )); System.out.printf("Max of %.1f,%.1f and %.1f is %.1f\n\n", 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 )); System.out.printf("Max of %s, %s and %s is %s\n","pear", "apple", "orange", maximum("pear", "apple", "orange")); } } ``` #### 输出 ```text Max of 3, 4 and 5 is 5 Max of 6.6,8.8 and 7.7 is 8.8 Max of pear, apple and orange is pear ``` ### 多有界类型参数(Multiple Bounds) 类型参数可以具有多个边界。 #### 语法 ```java public static > T maximum(T x, T y, T z) ``` 其中 - **maximum**-maximum是一种通用方法。 - **T-**传递给泛型方法的泛型类型参数。它可以带任何对象。 T是传递给泛型类Box的类型参数,并且应该是Number类的子类型,并且必须包含Comparable接口。如果将一个类作为有界传递,则应在接口之前首先传递它,否则会发生编译时错误(先声明类,再在&后声明接口)。 #### 例子 ```java public class GenericsTester { public static void main(String[] args) { System.out.printf("Max of %d, %d and %d is %d\n\n", 3, 4, 5, maximum( 3, 4, 5 )); System.out.printf("Max of %.1f,%.1f and %.1f is %.1f\n\n", 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 )); } public static > T maximum(T x, T y, T z) { T max = x; if(y.compareTo(max) > 0) { max = y; } if(z.compareTo(max) > 0) { max = z; } return max; } // 一下声明会导致编译错误 /* public static & Number> T maximum1(T x, T y, T z) { T max = x; if(y.compareTo(max) > 0) { max = y; } if(z.compareTo(max) > 0) { max = z; } return max; }*/ } ``` 输出 ```text Max of 3, 4 and 5 is 5 Max of 6.6,8.8 and 7.7 is 8.8 ``` ### 对集合的支持(list,set,map) #### 语法 ```java List list = new ArrayList(); Set set = new HashSet(); Set set = new HashSet(); ``` ## 通配符(Wild Cards) ### 上界通配符(Upper Bounded Wildcards) 问号(?)代表通配符,代表泛型中的未知类型。有时您可能想限制允许传递给类型参数的类型的种类。例如,对Number进行操作的方法可能只希望接受Number或其子类的实例。 要声明一个上界通配符参数,先声明“?”,其次是extends关键字,最后是其上限。 ```java import java.util.Arrays; import java.util.List; public class GenericsTester { public static double sum(List numberlist) { double sum = 0.0; for (Number n : numberlist) sum += n.doubleValue(); return sum; } public static void main(String args[]) { List integerList = Arrays.asList(1, 2, 3); System.out.println("sum = " + sum(integerList)); List doubleList = Arrays.asList(1.2, 2.3, 3.5); System.out.println("sum = " + sum(doubleList)); } } ``` #### 输出 ```text sum = 6.0 sum = 7.0 ``` ### 无界通配符(Unbounded Wildcards) 问号(?)代表通配符,代表泛型中的未知类型。有时可以使用Object类中提供的功能来实现方法,或者代码独立于类型参数时,可以使用任何对象。 #### 例子 ```java public class GenericsTester { public static void printAll(List list) { for (Object item : list) System.out.println(item + " "); } public static void main(String args[]) { List integerList = Arrays.asList(1, 2, 3); printAll(integerList); List doubleList = Arrays.asList(1.2, 2.3, 3.5); printAll(doubleList); } } ``` #### 输出 ```text 1 2 3 1.2 2.3 3.5 ``` ### 下界通配符(Lower Bounded Wildcards) 问号(?)代表通配符,代表泛型中的未知类型。有时您可能想限制允许传递给类型参数的类型的种类。例如,对数字进行操作的方法可能只希望接受Integer或其超类(例如Number)的实例。 要声明下界通配符参数,先声明?,后跟super关键字,然后是其下界。 #### 例子 ```java import java.util.ArrayList; import java.util.List; public class GenericsTester { public static void addCat(List catList) { catList.add(new RedCat()); System.out.println("Cat Added"); } public static void main(String[] args) { List animalList= new ArrayList(); List catList= new ArrayList(); List redCatList= new ArrayList(); List dogList= new ArrayList(); //add list of super class Animal of Cat class addCat(animalList); //add list of Cat class addCat(catList); //编译错误,不能添加Cat的子类RedCat到list中 //addCat(redCatList); //编译错误,不能添加Animal的子类Dog到Cat类的list中 //addCat.addMethod(dogList); } } class Animal {} class Cat extends Animal {} class RedCat extends Cat {} class Dog extends Animal {} ``` #### 输出 ```text Cat Added Cat Added ``` ### 通配符使用准则 通配符有三种方式可以使用: - **上界通配符** − ? extends Type. - **下界通配符** − ? super Type. - **无界通配符** − ? 为了确定最适合某些条件下的通配符类型,我们首先将传递给方法的参数类型分类为**in变量**和**out变量**。 - **in变量** − in变量将数据提供给代码。例如,copy(src, dest)。此处src充当要复制的数据的来源。 - **out变量** −out变量保存由代码更新的数据。例如,copy(src, dest)。在此,dest充当要复制数据的目的地。 #### 通配符准则 - **上界通配符**-如果变量属于**in变量**,则将extend关键字和通配符一起使用。 - **下界通配符**-如果变量属于**out变量**,则将super关键字与通配符一起使用。 - **无界通配符**-如果可以使用Object类方法访问变量,请使用**无界通配符**。 - **没有通配符**-如果代码同时访问**in变量**和**out变量**中的数据,则不要使用通配符。 #### 例子 ```java import java.util.ArrayList; import java.util.List; public class GenericsTester { //in变量:上界通配符 public static void deleteCat(List catList, Cat cat) { catList.remove(cat); System.out.println("Cat Removed"); } //out变量:下界通配符 public static void addCat(List catList) { catList.add(new RedCat("Red Cat")); System.out.println("Cat Added"); } //无界通配符 //使用 Object 的 toString() 方法 public static void printAll(List list) { for (Object item : list) System.out.println(item + " "); } public static void main(String[] args) { List animalList= new ArrayList(); List redCatList= new ArrayList(); //add list of super class Animal of Cat class addCat(animalList); //add list of Cat class addCat(redCatList); addCat(redCatList); //print all animals printAll(animalList); printAll(redCatList); Cat cat = redCatList.get(0); //delete cat deleteCat(redCatList, cat); printAll(redCatList); } } class Animal { String name; Animal(String name) { this.name = name; } public String toString() { return name; } } class Cat extends Animal { Cat(String name) { super(name); } } class RedCat extends Cat { RedCat(String name) { super(name); } } class Dog extends Animal { Dog(String name) { super(name); } } ``` #### 输出 ```text Cat Added Cat Added Cat Added Red Cat Red Cat Red Cat Cat Removed Red Cat ``` ## 类型擦除(Type Erasure) ### 类型擦除(Type Erasure) 泛型用于在编译时进行更严格的类型检查,并提供泛型编程。为了实现泛型行为,java编译器应用了类型擦除。类型擦除是编译器用**实际的类(actual class )**或**桥接方法(bridge method)**替换泛型参数的过程。在类型擦除中,编译器确保不创建额外的类,并且没有运行时开销。 #### 类型擦除规则 - 如果使用了*有界类型参数*,则用其界限类(extend 或 super 关键字后跟的类)替换泛型类中的类型参数。 - 如果使用了*无界类型参数*,则将泛型类的类型参数替换为Object。 - 插入*类型转换*以保持类型安全。 - 生成桥接方法以将多态保持在扩展的泛型类型中。 ### 有界类型擦除(Bound Types Erasure) 如果使用有界的类型参数,Java编译器会用其界限类替换泛型类的类型参数。 #### 例子 ```java public class GenericsTester { public static void main(String[] args) { Box integerBox = new Box(); Box doubleBox = new Box(); integerBox.add(new Integer(10)); doubleBox.add(new Double(10.0)); System.out.printf("Integer Value :%d\n", integerBox.get()); System.out.printf("Double Value :%s\n", doubleBox.get()); } } class Box { private T t; public void add(T t) { this.t = t; } public T get() { return t; } } ``` 在这种情况下,java编译器会将T替换为Number类,并且在类型擦除之后,编译器将为以下代码生成字节码。 ```java public class GenericsTester { public static void main(String[] args) { Box integerBox = new Box(); Box doubleBox = new Box(); integerBox.add(new Integer(10)); doubleBox.add(new Double(10.0)); System.out.printf("Integer Value :%d\n", integerBox.get()); System.out.printf("Double Value :%s\n", doubleBox.get()); } } class Box { private Number t; public void add(Number t) { this.t = t; } public Number get() { return t; } } ``` 在两种情况下,结果都是相同的。 #### 输出 ```text Integer Value :10 Double Value :10.0 ``` ### 无界类型擦除(Unbounded Types Erasure) 如果使用无界的类型参数,则Java编译器会将泛型类的类型参数替换为Object。 #### 例子 ```java public class GenericsTester { public static void main(String[] args) { Box integerBox = new Box(); Box stringBox = new Box(); integerBox.add(new Integer(10)); stringBox.add(new String("Hello World")); System.out.printf("Integer Value :%d\n", integerBox.get()); System.out.printf("String Value :%s\n", stringBox.get()); } } class Box { private T t; public void add(T t) { this.t = t; } public T get() { return t; } } ``` 在这种情况下,java编译器将用Object类替换T,并且在类型擦除之后,编译器将为以下代码生成字节码。 ```java public class GenericsTester { public static void main(String[] args) { Box integerBox = new Box(); Box stringBox = new Box(); integerBox.add(new Integer(10)); stringBox.add(new String("Hello World")); System.out.printf("Integer Value :%d\n", integerBox.get()); System.out.printf("String Value :%s\n", stringBox.get()); } } class Box { private Object t; public void add(Object t) { this.t = t; } public Object get() { return t; } } ``` 在两种情况下,结果都是相同的。 #### 输出 ```text Integer Value :10 String Value :Hello World ``` ### 泛型方法擦除(Generic Methods Erasure) 如果使用无界的类型参数,则Java编译器将泛型类的类型参数替换为对象,如果使用有界的类型参数用作方法参数,则Java编译器将使用其界限类替换类型参数。 #### 例子 ```java public class GenericsTester { public static void main(String[] args) { Box integerBox = new Box(); Box stringBox = new Box(); integerBox.add(new Integer(10)); stringBox.add(new String("Hello World")); printBox(integerBox); printBox1(stringBox); } private static void printBox(T box) { System.out.println("Integer Value :" + box.get()); } private static void printBox1(T box) { System.out.println("String Value :" + ((Box)box).get()); } } class Box { private T t; public void add(T t) { this.t = t; } public T get() { return t; } } ``` 类型擦除之后,编译器将为以下代码生成字节码。 ```java public class GenericsTester { public static void main(String[] args) { Box integerBox = new Box(); Box stringBox = new Box(); integerBox.add(new Integer(10)); stringBox.add(new String("Hello World")); printBox(integerBox); printBox1(stringBox); } //Bounded Types Erasure private static void printBox(Box box) { System.out.println("Integer Value :" + box.get()); } //Unbounded Types Erasure private static void printBox1(Object box) { System.out.println("String Value :" + ((Box)box).get()); } } class Box { private Object t; public void add(Object t) { this.t = t; } public Object get() { return t; } } ``` 在两种情况下,结果都是相同的。 #### 输出量 ```text Integer Value :10 String Value :Hello World ``` ## 泛型限制(Restrictions on Generics) ### 不允许基本类型(No Primitive Types) - 原始类型(Raw Types):定义时没有声明类型参数的类型,如Box是原始类型,Box\则是泛型,而不是原始类型。 - 基本类型(Primitive Types):像int,char,byte等的类型。 使用泛型,基本类型不能作为类型参数传递。在下面给出的示例中,如果将int基本类型传递给box类,则编译器将生成一个警告。为了避免这种情况,我们需要传递Integer对象而不是int基本类型。 #### 例子 ```java public class GenericsTester { public static void main(String[] args) { Box integerBox = new Box(); //编译错误 //ReferenceType //- Syntax error, insert "Dimensions" to complete //ReferenceType //Box stringBox = new Box(); integerBox.add(new Integer(10)); printBox(integerBox); } private static void printBox(Box box) { System.out.println("Value: " + box.get()); } } class Box { private T t; public void add(T t) { this.t = t; } public T get() { return t; } } ``` #### 输出 ```text Value: 10 ``` ### 不允许实例化(No Instance) 类型参数不能用于实例化方法内部的对象。 ```java public static void add(Box box) { //compiler error //Cannot instantiate the type T //T item = new T(); //box.add(item); } ``` 要实现此类功能,请使用反射。 ```java public static void add(Box box, Class clazz) throws InstantiationException, IllegalAccessException{ T item = clazz.newInstance(); // OK box.add(item); System.out.println("Item added."); } ``` #### 例子 ```java public class GenericsTester { public static void main(String[] args) throws InstantiationException, IllegalAccessException { Box stringBox = new Box(); add(stringBox, String.class); } public static void add(Box box) { //compiler error //Cannot instantiate the type T //T item = new T(); //box.add(item); } public static void add(Box box, Class clazz) throws InstantiationException, IllegalAccessException{ T item = clazz.newInstance(); // OK box.add(item); System.out.println("Item added."); } } class Box { private T t; public void add(T t) { this.t = t; } public T get() { return t; } } ``` #### 输出 ```text Item added. ``` ### 不允许使用静态字段(No Static field) 使用泛型时,类型参数不允许为静态。 由于静态变量在对象之间共享,因此编译器无法确定要使用哪种类型。 如果允许使用静态类型参数,请考虑以下示例。 #### 例子 ```java public class GenericsTester { public static void main(String[] args) { Box integerBox = new Box(); Box stringBox = new Box(); integerBox.add(new Integer(10)); printBox(integerBox); } private static void printBox(Box box) { System.out.println("Value: " + box.get()); } } class Box { //compiler error private static T t; public void add(T t) { this.t = t; } public T get() { return t; } } ``` 由于stringBox和integerBox都有一个带有标记的静态类型变量,因此无法确定其类型。 因此,不允许使用静态类型参数。 ### 不能强制转换(No Cast) 除非强制使用无界通配符对其进行参数化,否则不允许强制转换为参数化类型。 #### 例子 ```java Box integerBox = new Box(); Box numberBox = new Box(); //Compiler Error: Cannot cast from Box to Box integerBox = (Box)numberBox; ``` 要实现相同的目的,可以使用无界通配符。 ```java private static void add(Box box) { Box integerBox = (Box)box; } ``` ### 不能使用instanceOf(No instanceOf) 由于编译器使用类型擦除,因此运行时不跟踪类型参数,因此在运行时,无法使用instanceOf运算符来验证Box \和Box \之间的差异。 #### 例子 ```java Box integerBox = new Box(); //Compiler Error: //Cannot perform instanceof check against //parameterized type Box. //Use the form Box instead since further //generic type information will be erased at runtime if(integerBox instanceof Box) { } ``` ### 不允许使用参数化类型的数组(No Array) 不允许使用参数化类型的数组。 ``` //Cannot create a generic array of Box Box[] arrayOfLists = new Box[2]; ``` 由于编译器使用类型擦除,因此会将类型参数替换为Object,并且用户可以将任何类型的对象添加到数组中。并且在运行时,代码将无法引发ArrayStoreException。 #### 例子 ```java // compiler error, but if it is allowed Object[] stringBoxes = new Box[]; // OK stringBoxes[0] = new Box(); // An ArrayStoreException should be thrown, // but the runtime can't detect it. stringBoxes[1] = new Box(); ``` ### 不允许扩展Throwable类(No Exception) #### 泛型类不允许直接或间接扩展Throwable类。 ```java //The generic class Box may not subclass java.lang.Throwable class Box extends Exception {} //The generic class Box may not subclass java.lang.Throwable class Box1 extends Throwable {} ``` #### 不允许方法捕获类型参数的实例。 ```java public static void execute(List jobs) { try { for (J job : jobs) {} // compile-time error // Cannot use the type parameter T in a catch block } catch (T e) { // ... } } ``` #### 在throws子句中允许使用类型参数。 ```java class Box { private int t; public void add(int t) throws T { this.t = t; } public int get() { return t; } } ``` ### 不允许重载(No Overload) 一个类不允许具有两个在类型擦除后可以具有相同签名的重载方法。 #### 例子 ```java class Box { //Compiler error //两个print方法在方法擦除后具有同一个方法签名 public void print(List stringList) { } public void print(List integerList) { } } ```