`
cucaracha
  • 浏览: 141973 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
博客专栏
A8f3fa2f-18ce-3862-897a-5d2209197c90
Java NIO.2
浏览量:88231
7a076ba7-8ec8-3241-aa3c-67bb2f7856a2
Java EE 7 简明教...
浏览量:36856
社区版块
存档分类
最新评论

[泛型] 使用泛型的注意事项

阅读更多
在 Java 中有效地使用泛型,一定要注意以下限制:

不能使用原始数据类型实例化泛型类

考虑下面的泛型类:

class Pair<K, V> {

    private K key;
    private V value;

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

    // ...
}


在创建 Pair 对象的时候,类型参数 K 和 V 不能是原始数据类型:

Pair<int, char> p = new Pair<>(8, 'a');  // 编译错误


类型参数 K 和 V 只能使用非原始数据类型:

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

Java 编译器会像下面这样使用 Integer.valueOf(8) 自动封装 8,使用 Character('a') 自动封装 'a':

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


不能创建类型参数实例

不能创建类型参数的实例,下面这段代码会出现编译错误:

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


为了规避这个问题,你可以使用反射机制:

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


现在可以像下面代码这样来调用 append 方法:

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


不能使用类型参数声明静态属性

类的静态属性是类级别的变量,被所有非静态对象共享。因此,不能使用类型参数声明静态属性。

考虑下面的代码:

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

    // ...
}


如果允许类型参数声明静态属性,那么下面的代码将会很混乱:

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


因为静态属性 os 同时被 phone, pager, 和 pc 共享,那么现在 os 的真实类型是什么?它不可能同时是 Smartphone, Pager, 和 TabletPC 类型。因此,不允许声明静态的类型参数属性。

不能对泛型类使用强制类型转换和 instanceof

因为 Java 编译器在编译期会对所有泛型进行类型清除操作,因此,在运行时不能确定使用的是哪个类型的类型参数。

public static <E> void rtti(List<E> list) {
    if (list instanceof ArrayList<Integer>) {  // 编译错误
        // ...
    }
}


假如传递给 rtti 方法的 list 参数中的值如下:

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


运行时不会跟踪类型参数,因此也无法区分 ArrayList<Integer> 和 ArrayList<String> 的不同。你能做的最多是使用无限制的通配符来确保类型是 ArrayList:

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


通常情况下,除非使用了无限制的通配符,否则泛型类不能进行类型强制转换:

List<Integer> li = new ArrayList<>();
List<Number>  ln = (List<Number>) li;  // 编译错误


但是,在有的时候,如果编译器能确认类型参数是正确的情况下,可以进行类型强制转换:

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


不能创建泛型类的数组

你不能创建泛型类的数组,例如,下面的代码将不能通过编译:

List<Integer>[] arrayOfLists = new List<Integer>[2];  // 编译错误


下面的代码演示了为什么会发生这个错误:

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


那么如果是泛型类 List 的数组,同样会有这个问题:

Object[] stringLists = new List<String>[];  // 编译错误,但是我们假装可以这么做
stringLists[0] = new ArrayList<String>();   // OK
stringLists[1] = new ArrayList<Integer>();  // An ArrayStoreException should be thrown


不能创建、捕获或抛出类型参数的对象

泛型类不能直接或间接继承 Throwable 类,例如,下面的代码不能通过编译:

class MathException<T> extends Exception { /* ... */ }    // 编译错误

class QueueFullException<T> extends Throwable { /* ... */ // 编译错误


方法中也不能捕获类型参数异常:

public static <T extends Exception, J> void execute(List<J> jobs) {
    try {
        for (J job : jobs)
            // ...
    } catch (T e) {   // 编译错误
        // ...
    }
}


唯一能做的是,将类型参数放到方法的 throws 后面:

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


不允许仅仅是类型参数不同的情况下进行方法重载

下面这种写法将会发生编译错误:

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


文章来源:http://www.aptusource.org/2014/04/restrictions-on-generics/
1
0
分享到:
评论

相关推荐

    泛型java的泛型知识,非常有用

    3. **编写泛型类的注意事项** - 定义泛型类时,类型参数写在尖括号内,如 `class TestGen, V&gt;`。 - 实例化泛型对象时,需要指定类型参数的具体类型,如 `TestGen, String&gt; t = new TestGen, String&gt;()`。 - `...

    xe7结构体泛型

    然而,泛型结构体也有一些需要注意的事项: 1. **装箱与拆箱**:如果泛型结构体需要与引用类型进行交互,可能会涉及装箱(将值类型转换为对象)和拆箱(将对象转换回值类型),这会带来额外的性能成本。 2. **结构体...

    java泛型技术之发展

    5. **限制与注意事项** - **类型擦除**:泛型信息在运行时不可用,无法在运行时获取泛型类型。 - **不能实例化类型参数**:如 `new T()` 是不允许的。 - **原始类型与泛型**:原始类型(如int、double)不能直接...

    java泛型学习全面页面下载资料

    Java泛型是Java编程语言中的一个关键特性,...通过这些资料,你可以深入理解Java泛型的各个方面,包括其设计原则、用法以及实际编程中的注意事项。学习并掌握泛型将有助于提升你的Java编程能力,使代码更加优雅、安全。

    JVM如何理解Java泛型类.doc

    #### 三、创建泛型对象的注意事项 在创建泛型对象时,需要注意以下几点: 1. **显式指定类型**:当创建泛型对象时,最好明确指定类型参数`T`的具体类型,以便编译器能够进行类型检查。例如: ```java Pair...

    泛型实际应用(简介)

    - 注意事项: - 约束可以用于多个条件:例如同时实现两个接口或继承自某个类。 - 约束可以是接口、基类或特定的类型。 - 约束可以用来实现更复杂的功能,比如对泛型参数进行类型检查等。 - **构造函数约束**: ...

    Java泛型定义与用法实例详解

    泛型的引入使得Java语言更加灵活和强大,本文将详细介绍Java泛型的定义、原理、使用方法及相关操作注意事项。 一、泛型的由来 泛型的出现是为了解决早期Java集合框架中的类型安全问题。在早期Java集合框架中,集合...

    Java泛型研究.pdf

    Java泛型研究 Java泛型是Java语言中的一种重要机制,自从Java 1.5版本引入泛型以来,Java开发者可以更方便地编写...开发者需要了解泛型的基本概念、作用、应用和注意事项,以便更好地使用泛型提高代码的质量和安全性。

    Hibernate泛型Dao

    4. `README.md`或类似的文档:解释如何运行示例,以及可能的注意事项。 在实际应用中,还需要理解JDBC(Java Database Connectivity)的基础知识,因为Hibernate是在JDBC之上建立的。此外,了解SQL语言也是必要的,...

    实例190 - 泛型化的折半查找法

    6. **注意事项**: - 泛型不支持原始类型(如int、char等),因此在处理这些类型时,通常需要使用对应的包装类(如Integer、Character)。 - 虽然泛型提供了类型检查,但并不能提高运行时性能,其主要作用在于编译...

    Week17_第9讲_泛型与集合类.pdf

    - **注意事项**: - 如果定义了泛型却没有使用,IDE如Eclipse会给出警告提示。 - 泛型类型参数可以使用任意非保留关键字,但通常习惯使用`E`、`T`等单个大写字母表示。 #### 三、泛型代码示例 - **示例1**:定义...

    Java基础笔记之集合框架和泛型

    详细的介绍了集合框架的用法,及其语法规则,剖析了使用的使用注意事项,帮助更牢靠的掌握集合框架的知识及泛型内容。谢谢

    Java-泛型.ppt

    - **注意事项:** - 如果没有指定具体的数据类型,默认操作类型为`Object`。 - 泛型类型只能是引用类型,不能是基本数据类型。 - 泛型类型在逻辑上被视为多个不同的类型,但实际上它们都是相同的类型。 **2. 从...

    Java泛型深入研究

    5. **泛型的限制与注意事项**: - **类型擦除**:Java的泛型在运行时被擦除,这意味着在运行时无法检测到泛型的类型信息。这是由于历史兼容性原因,因为Java需要保持与早期版本的二进制兼容性。 - **不能实例化...

    java中的泛型-详细

    3. **编写泛型类的注意事项** - 定义泛型类时,类型参数要在尖括号`&lt;&gt;`内声明,如`class TestGen, V&gt;`。 - 实例化泛型类时,必须指定类型参数的具体类型,例如`TestGen, String&gt; t = new TestGen, String&gt;()`。 -...

    Java泛型构造函数(学习资料)

    6. **注意事项** - 泛型构造函数中的泛型类型参数只存在于构造函数内部,不会影响整个类的行为。 - 泛型类型参数的约束(如`&lt;E extends Rankable & Serializable&gt;`)确保了传递给构造函数的对象具有特定的能力或...

    Java泛型编程快速入门

    #### 四、编写泛型类的注意事项 1. **定义泛型类**: - 在定义泛型类时,需要在类名后使用 `&lt;...&gt;` 来声明类型参数,如 `class TestGen, V&gt;`。 - 类型参数 `K` 和 `V` 代表的是类型,而不是具体的值。 2. **实例...

    Java高级之—泛型的使用

    **四、自定义泛型的注意事项** 1. 在定义泛型类时,不能在类的成员变量中直接初始化泛型类型的数组,因为编译器无法确定具体类型。例如,`T[] arr = new T[20];` 是不允许的。 2. 泛型的边界可以指定,如`public ...

    Java中的泛型机制详解

    #### 泛型的注意事项 - **避免在静态上下文中使用泛型**:由于静态成员独立于实例存在,因此在静态方法或静态字段中使用泛型是没有意义的,因为此时类型参数已经被擦除。 - **类型安全性和性能权衡**:虽然泛型提高...

Global site tag (gtag.js) - Google Analytics