Effective Java 读书笔记(四):泛型

Effective Java 读书笔记(四):泛型

请不要在新代码中使用原生态类型

声明中使用一个或多个类型参数的类或接口,就是泛型类或接口,统称为泛型。每个泛型都有一个相对应的原生态类型,即不带任何实际类型参数的泛型名称,比如 List< E> 的原生态类型是 List。

使用原生态类型,就失掉了泛型在安全性和表达性方面的所有优势。Java 中允许使用原生态类型,只是为了兼容性。安全性和表达下说详细一点儿就是:
1. 缺少了泛型所具有的编译时类型安全特性。
2. 需要进行显式的类型转换。

在实际中可以使用无限制通配符类型 List< ? > 、有限制通配符类型 List< ? extends T> 或 List< Object> 来代替原生态类型。

还有一些地方必须使用原生态类型:
1. 类文字 class literal:List.class 是合法的,List< String>.class 是不合法的。
2. 使用 instanceof 判断类型时。

一些术语总结如下:

术语示例
参数化的类型List< String>
实际类型参数String
泛型List< E>
形式类型参数E
无限制类型参数List< ? >
原生态类型List
有限制类型参数List< E extends Number>
有限制通配符类型List< ? extends Number>
递归类型限制< T extends Comparable< T>>
泛型方法static E List< E> asList(E[] a)

消除编译时的非受检警告

每一条警告都表示可能在运行时抛出异常,要尽最大努力消除警告。如果无法消除,但可以证明引起警告的代码是类型安全的,那就可以使用 @SuppressWarnings(“unchecked”) 注解禁止该警告。注意,要用注释把禁止警告的原因记录下来。

SuppressWarnings 可以用于任何粒度的代码中:局部变量声明、方法、类,实际中应该在尽可能小的范围内使用 SuppressWarnings 注解。

列表 List 优先于数组

数组和列表有哪些不同呢?
1. 数组是协变的,泛型是不可协变的
2. 数组是具体化的,能够在运行时检查元素类型约束。而泛型会在编译时进行类型擦除,导致泛型可以与没有使用泛型的代码随意互用。

以上区别导致,数组和泛型不能很好的混合使用,比如不能创建泛型的数组。比如 new List< E>[]、new E[]、new List< String>[] 都是非法的。

像 E、List< E> 和 List< String> 这样的类型应称作不可具体化的类型。不可具体化的类型是指运行时表示法包含的信息比它的编译时表示法包含的信息更少的类型。

优先考虑泛型

public class ArrayList {
    transient Object[] elementData; // non-private to simplify nested class access
    public Object get(int index) {
        return elementData(index);
    }       
}   

假如 ArrayList 写成上面的样子,那就需要使用方自己去做类型转换了,而且缺少先是类型安全,容易放入错误类型的对象。下面的 ArrayList 使用了泛型,不仅类型安全,而且使用更方便,不需要显示类型转换了。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    transient Object[] elementData; // non-private to simplify nested class access
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }    
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }       
}   

优先考虑泛型方法

使用泛型方法的原因和使用泛型类基本一致。

利用有限制通配符来提升 API 的灵活性

  1. 当参数用于 producer 的时候,使用 extends。
  2. 当参数用于 consumer 的时候,使用 super。

类型推导规则很复杂,当编译器无法推到出类型参数时,可以显示指定类型参数。

优先考虑类型安全的异构容器

异构容器是指能够容纳不同类型对象的容器,实现异构容器时,优先考虑使用泛型来实现类型安全的异构容器,这对于使用方来说好处多多。

public class Favorites {
  private final Map<Class<?>, Object> favorites = new HashMap<>();  

  public <T> void put( Class<T> key, T value ) {  
    favorites.put( key, value );  
  }  

  public <T> T get( Class<T> key ) {  
    return key.cast( favorites.get( key ) );  
  }    
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值