JAVA泛型与类型安全

1. 基础泛型

//定义泛型类,接口的定义和类一样,extends 限定泛型上界
class A<T,P extends Number> {
  T t;
  P p;
  public <M> M doSomething(M params) {}
}

关于泛型的使用基本如此,开发者可以在实际使用时灵活地指定泛型所对应的实际类型,从而达到不同的效果

2. 协变与逆变与不变

  • 协变

在Java中的数组是协变的,简单来说即有:

A extends B  ==>  A[] extends B[]
B[] bs = new A[2]; //合法
  • 逆变

与协变相对,逆转了类型关系

  • 不变

Java 语言中的泛型基本上完全在编译器中实现,由编译器执行类型检查和类型推断,然后生成普通的非泛型的字节码。这种实现技术称为擦除(erasure)(编译器使用泛型类型信息保证类型安全,在生成字节码之前将其清除,因此运行时无法判断泛型的具体类型)

由于泛型擦除的原因,Java中的泛型是不变的,举一个栗子可以简明的说明这个问题,比如

A extends B    
List<B> bls = new ArrayList<A>();//类似数组的写法不合法,编译器检查不通过

为了解决泛型的不变,就需要用到通配符?与extends、super。

3. 通配符? 与 extends 与 super

先以泛型集合List<E>为例来说明以上三个关键字的特性
(1)通配符?在单独使用时可以看作是? extends Object

List<?> l0= new ArrayList<Object>();

(2)? extends xxx使得泛型具有协变的特性,extends限定了泛型的上界

//extends包含指向类及其子类
List<? extends Number> l1= new ArrayList<Number>();
List<? extends Number> l2= new ArrayList<Integer>();

那么狗二蛋,代价是什么呢?代价就是,此时泛型实例只能作为输出

l1.add(new Integer(1));//无法编译
Number n = l1.get(0);//可以获取到

(3)? super xxx使得泛型具有逆变的特性,super限定了泛型的下界

//super包含指向类及其父类
List<? super Integer> l3 = new ArrayList<Integer>();
List<? super Integer> l4 = new ArrayList<Number>();

那么狗二蛋,代价是什么呢?代价就是,此时泛型实例只能作为输入(但是由于泛型上界可以认为是Object,因此是可以输出到Object的,但是这毫无意义)

l3.add(new Integer(1));//可以编译
Object o = l3.get(0);//可以获取到

总结一点就是:写入需要有类型下界,而读出需要有类型上界

4. 在Android中的实例

在Android中,一个典型的例子就是RxJava的map操作

public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
    ObjectHelper.requireNonNull(mapper, "mapper is null");
    return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}

public interface Function<T, R> {
    /**
     * Apply some calculation to the input value and return some other value.
     * @param t the input value
     * @return the output value
     * @throws Exception on error
     */
    R apply(@NonNull T t) throws Exception;
}

这里泛型T作为泛型下界,承接上流的输入,泛型R则作为泛型上界,呈递输出到下游。由于上界和下界使用泛型定义,所以实际传入的类型不会被固定

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 第8章 泛型 通常情况的类和函数,我们只需要使用具体的类型即可:要么是基本类型,要么是自定义的类。但是在集合类的场...
    光剑书架上的书阅读 2,158评论 6 10
  • 本文大量参考Thinking in java(解析,填充)。 定义:多态算是一种泛化机制,解决了一部分可以应用于多...
    谷歌清洁工阅读 473评论 0 2
  • 参考地址:《Java 泛型,你了解类型擦除吗?》 《Java中的逆变与协变》 《java 泛型中 T、E .....
    琦小虾阅读 3,053评论 0 11
  • 晴空如洗,阿尔卑斯山的山峦间走来一群体型相当庞大的北山羊,它们是世界上生活海拔最高的哺乳动物,善于攀登和跳跃,能够...
    晴空月阅读 2,926评论 0 2
  • 目前安卓应用的安全现状,随着安卓应用的快速暴涨,相应的漏洞也逐渐增加。同时,市场上也出现了专业的安卓应用测试工具:...
    陈大冲阅读 369评论 0 0