泛型

泛型主要作用:

类型检查报错,类型转型,类型约束

通配符 ?:

【子类的泛型类型对象不可以赋值给父类的泛型声明】例如:

ArrayList<Fruit>fruits=new ArrayList<Apple>()//集合中,不可行
Shop<Fruit> shop = new Shop<Apple>()//对象声明创建,不可行

但使用通配符可以解除这个限制【ArrayList<? extend Fruit>fruits = new ArrayList<Apple>()】

【协变covariant】? extend :表示定义了上界,放宽泛型声明要求,但是只能读数据,不能添加数据,例如:
1 ArrayList<? extend Fruit> fruits = new ArrayList<Apple>()
2 Banana banana = new Banana()
3 fruits.add(banana)//不可行,无法编译通过
4 fruits.get(0)//可行

在ide中,第3行就不会被编译通过。
何时使用? extend,一般用于场景功能或者三方库提供方法,例如:

//提供一个公共方法供外部使用
float getTotalWeight(List<? extend Fruit> fruits){
    float weight = 0;
    for(Fruit fruit:fruits){
        weight+=fruit.getWeight();//只能读取数据
    }
    return weight;
}

//以上方法中,形参使用了? extend,调用的地方就可以传入List<Apple>或者List<Banana>等包含Fruit子类的参数,而不仅仅局限于某一个特定的参数
【逆变contravariant】? super:表示定义下界,只能添加数据,不能读取数据,例如:
1 List<? super Apple>apples = new ArrayList<Fruit>()
2 apples.add(new Apple())//可行
3 Apple apple = apples.get(0)//不可行,无法编译通过

何时使用? super,也是场景化功能,例如:

//在某个类中,有一个方法需要传List数组,如果该数组里面的泛型参数可以是此类的父类,就可以用? super
//例如在Apple.java中,有以下方法
public void addToList(List<? super Apple>list){
    list.add(this);//只能添加数据
}
//方法addToList就可以传入Apple的父类的List,而不局限于List<Apple>
//例如以下使用情况
List<Fruit>fruits = new ArrayList<Fruit>()
addToList(fruits)

泛型擦除(java为了兼容性和性能,选择了擦除):

在java代码里面,类型擦除是泛型的特质,所有泛型在运行的时候,定义泛型的地方会被“擦除”掉,

在数组中:

1 Fruit[] fruits = new Apple[5]
2 fruits[0] = new Banana()
3 Apple apple = fruits[0]

运行的时候,第2行(添加)就已经报错了,因为不允许往Apple数组中添加Banana元素

但在ArrayList中如果有以下代码(强转):

1 ArrayList<Apple> apples = new ArrayList<Apple>()
2 ArrayList<Fruit> fruitList = (ArrayList) apples
3 fruitList.add(new Banana());
4 Apple apple = apples .get(0)

在ide中会编译通过,但是在运行时第4行会报错,但是第3行(添加)会通过,实际上第3行就不被允许,但是存在泛型擦除的情况,第3行却被运行通过了,使我们在第一时间未能发现错误,但是在使用的时候(第4行),就会出现错误的,但在数组中,是可以在添加的时候就发现错误;所以,在泛型的使用中,可能会因为类型擦除导致我们不能在第一时间发现问题,从而就会出现类型不安全的问题。【父类的泛型声明类型,不能创建子类的值,例如:ArrayList<Fruit> fruits = new ArrayList<Apple>(),是不被允许的】,所以? extend这种通配符,就可以在编译期发现这种类型不安全的问题(添加数据的时候),但是在数组中,不存在泛型擦除情况,所以在运行过程中可以发现问题。

泛型方法

例如:findViewById这个方法,与对象本身无关

    public <T extends View> T findViewById(@IdRes int id) {
        return getDelegate().findViewById(id);
    }

泛型类型推断(简化代码)

///val image:ImageView = findViewById<ImageView>(R.id.iv_image)
val image:ImageView = findViewById(R.id.iv_image)
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1、基本应用 Java泛型可以用在类、接口和方法上。基本使用请参考《on Java 8》. 2、类型擦除 ​ ...
    流_心阅读 2,498评论 0 0
  • 1.泛型的由来 一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义的类型,如果要编写可以适用于多...
    BigDreamMaker阅读 3,570评论 0 1
  • 一. Java 中的泛型 Java 5 中添加了泛型,用以编译时类型检查,借此消除使用集合类时常见的ClassCa...
    大鹏的鹏阅读 1,332评论 0 0
  • 泛型概述以及泛型类 泛型就是类型参数化,处理的数据类型不是固定的,而是可以作为参数传入; 泛型的核心: 告诉编译器...
    皮多堡阅读 3,914评论 0 0
  • ArrayList就是个泛型类,我们通过设定不同的类型,可以往集合里面存储不同类型的数据类型(而且只能存储设定的数...
    dinel阅读 3,355评论 0 2