您的位置:首页 > 编程语言 > Java开发

The Java™ Tutorials — Generics :Restrictions on Generics 泛型约束

2016-02-08 20:49 609 查看



The Java™ Tutorials — Generics :Restrictions on Generics 泛型约束

原文地址:https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html


关键点

无法利用原始类型来创建泛型 
解决方法:使用它们的包装类

无法创建类型参数的实例 
变通方案:利用反射就是可以

无法创建参数化类型的静态变量 
原因:静态变量是类所有,共享决定了其必须能确定。但多个类型作为参数传入此类的多个实例时,就会无法确定究竟赋予此静态变量哪个实例对象所传入的参数了

无法对参数化类型使用转换或者instanceof关键字 
但需要注意通配符的情况

无法创建参数化类型的数组
无法创建、捕获或是抛出参数化类型对象 
但却可以在throw后使用类型参数

当一个方法的所有重载方法的形参类型擦除后,如果它们具有了相同的原始类型,那么此方法不可重载 
原因:此情境下,类型擦除会产生两个同签名的方法


全文翻译

To use Java generics effectively, you must consider the following restrictions:
Cannot Instantiate Generic Types with Primitive Types
Cannot Create Instances of Type Parameters
Cannot Declare Static Fields Whose Types are Type Parameters
Cannot Use Casts or instanceof With Parameterized Types
Cannot Create Arrays of Parameterized Types
Cannot Create, Catch, or Throw Objects of Parameterized Types
Cannot Overload a Method Where the Formal Parameter Types of Each Overload Erase to the Same Raw Type

为了高效使用Java泛型,你必须考虑一下下面的约束条件:
无法利用原始类型来创建泛型
无法创建类型参数的实例
无法创建参数化类型的静态变量
无法对参数化类型使用转换或者instanceof关键字
无法创建参数化类型的数组
无法创建、捕获或是抛出参数化类型对象
当一个方法的所有重载方法的形参类型擦除后,如果它们具有了相同的原始类型,那么此方法不可重载


Cannot Instantiate Generic Types with Primitive Types 无法利用原始类型来创建泛型

Consider the following parameterized type:

看下下面的参数化类型:

class Pair<K, V> {

private K key;
private V value;

public Pair(K key, V value) {
this.key = key;
this.value = value;
}

// ...
}


When creating a Pair object, you cannot substitute a primitive type for the type parameter K or V:

当创建一个Pair对象时,你无法将类型参数 K 或者 V 替换为一个原始类型:

Pair<int, char> p = new Pair<>(8, 'a');  // compile-time error


You can substitute only non-primitive types for the type parameters K and V:

你仅可将 K 和 V 替换为非原始类型:

Pair<Integer, Character> p = new Pair<>(8, 'a');


Note that the Java compiler autoboxes 8 to Integer.valueOf(8) and ‘a’ to Character(‘a’):

需要注意的是,Java编译器将会把 8 自动包装为为 Integer.valueOf(8) ,将 ‘a’ 包装为 Character(‘a’):

Pair<Integer, Character> p = new Pair<>(Integer.valueOf(8), new Character('a'));


For more information on autoboxing, see Autoboxing and Unboxing in the Numbers and Strings lesson.

关于自动置入置出的更多信息,参见《数字和字符串》课时中的《自动置入置出》部分。


Cannot Create Instances of Type Parameters 无法创建类型参数的实例

You cannot create an instance of a type parameter. For example, the following code causes a compile-time error:

你无法创建一个类型参数的实例。例如,下面代码就会引起编译时错误:

public static <E> void append(List<E> list) {
E elem = new E();  // compile-time error
list.add(elem);
}


As a workaround, you can create an object of a type parameter through reflection:

这里有一个变通方案——通过反射创建一个参数化类型的实例:

public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance();   // OK
list.add(elem);
}


You can invoke the append method as follows:

你可以像下面这样调用 append 方法:

List<String> ls = new ArrayList<>();
append(ls, String.class);



Cannot Declare Static Fields Whose Types are Type Parameters 无法创建参数化类型的静态变量

A class’s static field is a class-level variable shared by all non-static objects of the class. Hence, static fields of type parameters are not allowed. Consider the following class:

一个类的类域是类变量,它被所有此类的非静态对象所共享。因此,参数化类型的静态变量是被禁止的。看下下面的这个类:

public class MobileDevice<T> {
private static T os;

// ...
}


If static fields of type parameters were allowed, then the following code would be confused:

如果允许类型参数的静态变量存在,那么下面代码就会混乱:

MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();


Because the static field os is shared by phone, pager, and pc, what is the actual type of os? It cannot be Smartphone, Pager, and TabletPC at the same time. You cannot, therefore, create static fields of type parameters.

由于该静态变量由phone、pager和pc三者所共享,那么os的类型究竟是什么呢?它无法同时兼具三者。因此,你不可以创建类型参数的静态变量。


Cannot Use Casts or instanceof with Parameterized Types 无法对参数化类型使用转换或者instanceof关键字

Because the Java compiler erases all type parameters in generic code, you cannot verify which parameterized type for a generic type is being used at runtime:

由于Java编译器会将泛型代码中所有的类型参数擦除,因此你也就无法确定一个泛型的运行时参数化类型究竟是什么了。

public static <E> void rtti(List<E> list) {
if (list instanceof ArrayList<Integer>) {  // compile-time error
// ...
}
}


The set of parameterized types passed to the rtti method is:

传入rtti方法的参数化类型集合为:

S = { ArrayList<Integer>, ArrayList<String> LinkedList<Character>, ... }


The runtime does not keep track of type parameters, so it cannot tell the difference between an 
ArrayList<Integer>
 and
an
ArrayList<String>
. The most you can do is to use an unbounded wildcard to verify
that the list is an ArrayList:

运行时并不记录类型参数,因此它无法辨别
ArrayList<Integer>
ArrayList<String>
两者的不同。你能做的就是利用非受限通配符去确认这个list是一个ArrayList:

public static void rtti(List<?> list) {
if (list instanceof ArrayList<?>) {  // OK; instanceof requires a reifiable type
// ...
}
}


Typically, you cannot cast to a parameterized type unless it is parameterized by unbounded wildcards. For example:

一般的,除非是一个类型的参数为非受限通配符,否则你就不能将此类型转化为参数化类型。例如:

List<Integer> li = new ArrayList<>();
List<Number>  ln = (List<Number>) li;  // compile-time error


However, in some cases the compiler knows that a type parameter is always valid and allows the cast. For example:

然而在某些情况下,编译器知道某个类型参数总是有效的,因而也就允许了类型转换。例如:

List<String> l1 = ...;
ArrayList<String> l2 = (ArrayList<String>)l1;  // OK



Cannot Create Arrays of Parameterized Types 无法创建参数化类型的数组

You cannot create arrays of parameterized types. For example, the following code does not compile:

你无法创建参数化类型数组。例如下面的代码就无法通过编译:

List<Integer>[] arrayOfLists = new List<Integer>[2];  // compile-time error


The following code illustrates what happens when different types are inserted into an array:

下面的代码说明了不同类型元素插入数组时究竟会发生什么:

Object[] strings = new String[2];
strings[0] = "hi";   // OK
strings[1] = 100;    // An ArrayStoreException is thrown.


If you try the same thing with a generic list, there would be a problem:

如果你对一个泛型list做同样的事,那也会出问题:

Object[] stringLists = new List<String>[];  // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>();   // OK
stringLists[1] = new ArrayList<Integer>();  // An ArrayStoreException should be thrown,
// but the runtime can't detect it.


If arrays of parameterized lists were allowed, the previous code would fail to throw the desired ArrayStoreException.

如果参数化List的数组被允许,之前的代码就无法抛出预期的ArrayStoreException异常了。


Cannot Create, Catch, or Throw Objects of Parameterized Types 无法创建、捕获或是抛出参数化类型的对象

A generic class cannot extend the Throwable class directly or indirectly. For example, the following classes will not compile:

一个泛型类型无法直接或间接继承Throwable类。例如,下面的代码就无法通过编译:

// Extends Throwable indirectly
class MathException<T> extends Exception { /* ... */ }    // compile-time error

// Extends Throwable directly
class QueueFullException<T> extends Throwable { /* ... */ // compile-time error


A method cannot catch an instance of a type parameter:

一个方法无法捕获一个类型参数的实例:

public static <T extends Exception, J> void execute(List<J> jobs) {
try {
for (J job : jobs)
// ...
} catch (T e) {   // compile-time error
// ...
}
}


You can, however, use a type parameter in a throws clause: 

不过你却可以在throws关键字后使用类型参数:

class Parser<T extends Exception> {
public void parse(File file) throws T {     // OK
// ...
}
}



Cannot Overload a Method Where the Formal Parameter Types of Each Overload Erase to the Same Raw Type 当一个方法的所有重载方法的形参类型擦除后,如果它们具有了相同的原始类型,那么此方法是不可重载的

A class cannot have two overloaded methods that will have the same signature after type erasure.

一个类中是无法存在类型擦除后具有相同签名的两个重载方法。

public class Example {
public void print(Set<String> strSet) { }
public void print(Set<Integer> intSet) { }
}


The overloads would all share the same classfile representation and will generate a compile-time error.

这两个重载方法在classfile中具有相同的表达,因此会生成一个编译时错误。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息