java 泛型笔记

泛型

泛型,又称参数化类型

泛型类并没有自己独有的 Class 类对象。比如:并不存在 List<Object>.class 或是 List<Interger>.class,Java 编译器会将二者都视为 List.class

泛型一些约定俗成的命名:

  • E - Element
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • T - 类型,主要用于表示第一类通用型参数。
    S - 类型,主要用于表示第二类通用类型参数。
    U - 类型,主要用于表示第三类通用类型参数。
    V - 类型,主要用于表示第四个通用类型参数。

1 泛型优点

泛型具有以下优点:

  • 编译时的强类型检查

  • 泛型要求在声明时指定实际数据类型,Java 编译器在 编译时会对泛型代码做强类型检查 ,并在代码违反类型安全时发出警告。在编译时发现并修复错误所付出的代价远比在运行时小。

  • 消除强制类型转换

    • 未使用泛型:
    List list = new ArrayList();
    list.add("hello");
    String s = (String) list.get(0);
    
    • 使用泛型:
    List<String> list = new ArrayList<String>();
    list.add("hello");
    String s = list.get(0);   // no cast
    
  • 泛型编程可以实现通用算法

    • 通过使用泛型,程序员可以实现通用算法,这些算法可以处理不同类型的集合,可以自定义,并且类型安全且易于阅读。

2 自动装箱

类型参数必须被实例化为引用类型,因此Java有一种特殊机制来使泛型代码能够处理原始数据类型。

自动将一个原始数据类型转换为一个封装类型被称为自动装箱,自动将一个封装类型转换为一个原始数据类型被称为自动拆箱。

Stack<Integer> stack = new Stack<Integer>();
stack.push(17) ; // 自动装箱(int -> Integer)
int i = stack.pop(); // 自动拆箱(Integer -> int)

3 类型擦除

类型擦除做了以下工作:

  • 把泛型中的所有类型参数替换为 Object,如果指定类型边界,则使用类型边界来替换。因此,生成的字节码仅包含普通的类,接口和方法。
  • 擦除出现的类型声明,即去掉 <> 的内容。比如 T get() 方法声明就变成了 Object get()List<String> 就变成了 List。如有必要,插入类型转换以保持类型安全。
  • 生成桥接方法以保留扩展泛型类型中的多态性。类型擦除确保不为参数化类型创建新类;因此,泛型不会产生运行时开销。

4 java 不支持泛型数组

  • 为什么 java 不支持泛型数组?

    • 共变数组(covariant array)

      • 数组的协变性(covariant)是指:

        如果类Base是类Sub的基类,那么Base[]就是Sub[]的基类。

        而泛型是不可变的(invariant),List< Base >不会是List< Sub >的基类,更不会是它的子类。

    • 类型擦除(type erasure)

      • 数组是具体化的 ( reified ),而泛型在运行时是被擦除的 ( erasure )。
      • 数组是在运行时才去判断数组元素的类型约束,
      • 而泛型正好相反,在运行时,泛型的类型信息是会被擦除的,只有编译的时候才会对类型进行强化。

5 类型通配符

上界通配符 语法形式:<? extends Number>

下界通配符 语法形式:<? super Number>

无界通配符 语法形式:<?>

6 泛型约束

  1. 泛型类型的类型参数不能是值类型
   Pair<int, char> p = new Pair<>(8, 'a');  // 编译错误
  1. 不能创建类型参数的实例
public static <E> void append(List<E> list) {
    E elem = new E();  // 编译错误
    list.add(elem);
}
  1. 不能生命类型为类型参数的静态成员
public class MobileDevice<T> {
    private static T os; // error

    // ...
}
  1. 参数类型不能使用类型转换或 instanceof
public static <E> void rtti(List<E> list) {
    if (list instanceof ArrayList<Integer>) {  // 编译错误
        // ...
    }
}

List<Integer> li = new ArrayList<>();
List<Number>  ln = (List<Number>) li;  // 编译错误
  1. 不能创建参数类型的数组
List<Integer>[] arrayOfLists = new List<Integer>[2];  // 编译错误
  1. 不能创建、catch 或 throw 参数化类型对象
// Extends Throwable indirectly
class MathException<T> extends Exception { /* ... */ }    // 编译错误

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


public static <T extends Exception, J> void execute(List<J> jobs) {
    try {
        for (J job : jobs)
            // ...
    } catch (T e) {   // compile-time error
        // ...
    }
}
  1. 仅仅是泛型类相同,而参数类型不同的方法不能重载
public class Example {
    public void print(Set<String> strSet) { }
    public void print(Set<Integer> intSet) { } // 编译错误
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值