资讯专栏INFORMATION COLUMN

Java™ 教程(泛型的限制)

Bowman_han / 440人阅读

泛型的限制

要有效地使用Java泛型,必须考虑以下限制:

无法使用基元类型实例化泛型类型

无法创建类型参数的实例

无法声明类型为类型参数的静态字段

无法对参数化类型使用强制类型转换或instanceof

无法创建参数化类型的数组

无法创建、捕获或抛出参数化类型的对象

无法重载将每个重载的形式参数类型擦除为相同原始类型的方法

无法使用基元类型实例化泛型类型

考虑以下参数化类型:

class Pair {

    private K key;
    private V value;

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

    // ...
}

创建Pair对象时,不能将基本类型替换为类型参数KV

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

你只能将非基本类型替换为类型参数KV

Pair p = new Pair<>(8, "a");

请注意,Java编译器将8自动装箱到Integer.valueOf(8),将"a"自动装箱到Character("a")

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

有关自动装箱的详细信息,请参阅自动装箱和拆箱。

无法创建类型参数的实例

你无法创建类型参数的实例,例如,以下代码导致编译时错误:

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

作为解决方法,你可以通过反射创建类型参数的对象:

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

你可以按如下方式调用append方法:

List ls = new ArrayList<>();
append(ls, String.class);
无法声明类型为类型参数的静态字段

类的静态字段是类的所有非静态对象共享的类级变量,因此,类型参数的静态字段是不允许的,考虑以下类:

public class MobileDevice {
    private static T os;

    // ...
}

如果允许类型参数的静态字段,则以下代码将混淆:

MobileDevice phone = new MobileDevice<>();
MobileDevice pager = new MobileDevice<>();
MobileDevice pc = new MobileDevice<>();

因为静态字段os是由phonepagerpc共享的,所以os的实际类型是什么?它不能同时是SmartphonePagerTabletPC,因此,你无法创建类型参数的静态字段。

无法对参数化类型使用强制类型转换或instanceof

因为Java编译器会擦除泛型代码中的所有类型参数,所以无法验证在运行时使用泛型类型的参数化类型:

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

传递给rtti方法的参数化类型集是:

S = { ArrayList, ArrayList LinkedList, ... }

运行时不跟踪类型参数,因此它无法区分ArrayListArrayList之间的区别,你可以做的最多是使用无界通配符来验证列表是否为ArrayList

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

通常,除非通过无界通配符对其进行参数化,否则无法强制转换为参数化类型,例如:

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

但是,在某些情况下,编译器知道类型参数始终有效并允许强制转换,例如:

List l1 = ...;
ArrayList l2 = (ArrayList)l1;  // OK
无法创建参数化类型的数组

你无法创建参数化类型的数组,例如,以下代码无法编译:

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

以下代码说明了将不同类型插入到数组中时会发生什么:

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

如果你使用泛型列表尝试相同的操作,则会出现问题:

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

如果允许参数化列表数组,则前面的代码将无法抛出所需的ArrayStoreException

无法创建、捕获或抛出参数化类型的对象

泛型类不能直接或间接扩展Throwable类,例如,以下类将无法编译:

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

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

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

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

但是,你可以在throws子句中使用类型参数:

class Parser {
    public void parse(File file) throws T {     // OK
        // ...
    }
}
无法重载将每个重载的形式参数类型擦除为相同原始类型的方法

一个类不能有两个在类型擦除后具有相同的签名的重载方法。

public class Example {
    public void print(Set strSet) { }
    public void print(Set intSet) { }
}

重载将共享相同的类文件表示,并将生成编译时错误。

上一篇:类型擦除 下一篇:创建和使用包

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72952.html

相关文章

  • java编程思想》—— 泛型

    摘要:引用泛型除了方法因不能使用外部实例参数外,其他继承实现成员变量,成员方法,方法返回值等都可使用。因此,生成的字节码仅包含普通的类,接口和方法。 为什么要使用泛型程序设计? 一般的类和方法,只能使用具体的类型:要么是基本类型,要么是自定义类的对应类型;如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。----摘自原书Ordinary classes and meth...

    CODING 评论0 收藏0
  • Java教程(类型擦除)

    类型擦除 泛型被引入到Java语言中,以便在编译时提供更严格的类型检查并支持通用编程,为了实现泛型,Java编译器将类型擦除应用于: 如果类型参数是无界的,则用它们的边界或Object替换泛型类型中的所有类型参数,因此,生成的字节码仅包含普通的类、接口和方法。 如有必要,插入类型转换以保持类型安全。 生成桥接方法以保留扩展泛型类型中的多态性。 类型擦除确保不为参数化类型创建新类,因此,泛型不会...

    zsy888 评论0 收藏0
  • Java系列之泛型

    摘要:总结泛型的类型必须是引用类型,不能是基本类型,泛型的个数可以有多个,可以使用对创建对象时的泛型类型以及方法参数类型进行限制,如使用关键字和对泛型的具体类型进行向下限制或向上限制,最后一点,可以声明泛型数组,但是不能创建泛型数组的实例。 自从 JDK 1.5 提供了泛型概念,泛型使得开发者可以定义较为安全的类型,不至于强制类型转化时出现类型转化异常,在没有反省之前,可以通过 Object...

    MadPecker 评论0 收藏0
  • Java泛型

    摘要:虚拟机中并没有泛型类型对象,所有的对象都是普通类。其原因就是泛型的擦除。中数组是协变的,泛型是不可变的。在不指定泛型的情况下,泛型变量的类型为该方法中的几种类型的同一个父类的最小级,直到。 引入泛型的主要目标有以下几点: 类型安全 泛型的主要目标是提高 Java 程序的类型安全 编译时期就可以检查出因 Java 类型不正确导致的 ClassCastException 异常 符合越早出...

    woshicixide 评论0 收藏0
  • java表示型的方法

    摘要:使用表示泛型中的基本思想就是可以通过使用像这样适当的超类来实现泛型类。请看例子使用实现泛型使用接口类型表示泛型当有多个类要在一个通用的方法里表示泛型时,来表示可能就显得捉襟见肘了,因为这个时候无法明确的知道用户到底需要拆箱为哪种类。 1.1 使用Object表示泛型 Java中的基本思想就是可以通过使用像Object这样适当的超类来实现泛型类。--《数据结构与算法分析 Java语言描述...

    hosition 评论0 收藏0

发表评论

0条评论

Bowman_han

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<