您的位置:首页 > 编程语言 > Java开发

从头认识java-13.11 对比数组与泛型容器,观察类型擦除给泛型容器带来什么问题?

2015-12-21 09:25 531 查看
这一章节我们继续类型擦除的话题,我们将通过对比数组与泛型容器,观察类型擦除给泛型容器带来什么问题?
1.数组
package com.ray.ch13;

public class Test {

public static void main(String[] args) {
Fruit[] fruits = new Apple[5];
fruits[0] = new Apple();
fruits[1] = new Fuji();
fruits[2] = new Fruit();
}
}

class Fruit {
}

class Apple extends Fruit {
}

class Fuji extends Apple {
}
观察上面的代码,我们可以看到,虽然定义只是Fruit 的数组,但是它可以放进去Apple、Fuji等子类型的对象,因为数组是持有对象的引用,而且可以在运行时向上转型。

2.泛型容器
一般用法:
package com.ray.ch13;

import java.util.ArrayList;

public class Test {

public static void main(String[] args) {
ArrayList<Fruit> fruits = new ArrayList<Fruit>();
fruits.add(new Fruit());
fruits.add(new Apple());
fruits.add(new Fuji());
}
}

class Fruit {
}

class Apple extends Fruit {
}

class Fuji extends Apple {
}
上面是我们的常用用法,定义一个List容器,泛型里面填写的是同一个类型。
但是,我们下面将根据向上转型的特性,看看能不能像数组一样?
例子:
package com.ray.ch13;

import java.util.ArrayList;

public class Test {

public static void main(String[] args) {
// ArrayList<Fruit> fruits = new ArrayList<Apple>();//error
ArrayList<? extends Fruit> fruits = new ArrayList<Apple>();
// fruits.add(new Apple());//error
// fruits.add(new Fruit());//error
fruits.add(null);// 这里只能是null,没有其他选择
}
}

class Fruit {
}

class Apple extends Fruit {
}

class Fuji extends Apple {
}
观察上面的代码,本来我们想跟数组一样,在创建list的时候只是把泛型定义为Fruit的子类,但是,编译器抛异常。这是因为泛型不是完全定义,它只是在编译器检查类型安全,在运行期就没有泛型的概念了。而当我们定义的时候是通过通配符“?”来定义,也就是说我可以放进去Fruit的本身或者子类,编译器可以知道,但是在运行期,jvm只是知道放进来Object,而在创建的时候是定义了Apple子类,虽然编译器知道,但是在运行期,jvm也只是知道放进来Object,这个时候在运行期就会引起类型安全的问题,因此,当我们放进去什么对象都会引起类型安全的时候,编译器只能给出null这个选项,不然就必然会出现类型安全的风险。
总的来说,因为数组是完全定义,在编译器和运行期都会进行类型检测,或者说数组本身就是持有对象,而泛型容器只是在编译器检查类型安全,而在运行期全是Object,只是半定义,或者说泛型容器不持有对象,才导致上面所展示的问题。

总结:这一章节我们主要对比数组与泛型容器,观察类型擦除给泛型容器带来什么问题。

这一章节就到这里,谢谢。
-----------------------------------
目录
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java