浅析java的泛型通配符
2013-05-28 14:49
246 查看
import java.util.ArrayList;
import java.util.List;
public class TestGeneric {
public static void main(String[] args) {
List<? extends Fruit> list1 = new ArrayList<Apple>();
//list.add(new Fruit());
//list.add(new Apple());
/*
*
* 上面的两句都是不正确的,为什么呢?首先为什么要List<? extends Fruit> = new ArrayList<Apple>();这样写呢?
这样写的目的无非是想利用一下,抽象的基类来表示子类(也就是父类引用指向子类对象)。但是这里需要注意的一个问题就是,
java的泛型机制是通过它的编译系统来完成的(其实,数组和泛型容器在这里的区别很大,见下面的例子)。List<? extends Fruit>告诉编译器:"我是一个可以装载某个具体的Fruit的子类的List容器"。
而=new ArrayList<apple>();则指明了这个list装载的实际上是Apple类型。那为什么list.add(new Apple())通不过编译呢?因为编译器只是
知道list可以装载某个Fruit的子类,但是它也不知道具体是那种。
其实上面的机制主要是为了保证java运行时的安全性。试想,如果你定义了List<? extends Fruit> list = new ArrayList<Apple>();
而list.add(new 任何Fruit的子类)可以通过编译的话,那么你的list就有可能装入了Banana类型,这样就与你的初衷 ArrayList<Apple>矛盾了
这样泛型的安全性就保证不了了。
<? extends Fruit>表示的是Fruit或者任何Fruit的子类,其中Fruit最大。<? super Fruit> 表示Fruit和任何Fruit的父类,
Fruit最小,这样的话,用List<? super Fruit>来声明的话,就可以任意的add Fruit的子类了,因为它肯定是你运行时对象的子类,这样并不破坏
泛型机制的装载安全性。
List<? super Banana> list2 = new ArrayList<Banana>();
list2.add(Banana);
list2.add(SmallBanana);
list2.add(BigBanana);
以上的写法都是可以的
*
*
*/
//Banana[] b = new BigBanana[10];
//List<Banana> list2 = new ArrayList<BigBanana>();
/*
* 上面的两个例子,b可以通过编译,但是list2没有,为什么?其实还是为了保证安全性(数组是不保证的,如果b[0]=new SmallBanana(),编译不报错,运行时候会报错ArrayStore),可能不慎引入
* Banana的子类但不是BigBanana类型。这样在编译的时候就保证了安全性。
*
*/
}
}
class Fruit{
}
class Apple extends Fruit{
}
class Banana extends Fruit{
}
class BigBanana extends Banana{
public String toString() {
return "I am a BigBanana";
}
}
class SmallBanana extends Banana{
public String toString() {
return "I am a SmallBanana";
}
}
import java.util.List;
public class TestGeneric {
public static void main(String[] args) {
List<? extends Fruit> list1 = new ArrayList<Apple>();
//list.add(new Fruit());
//list.add(new Apple());
/*
*
* 上面的两句都是不正确的,为什么呢?首先为什么要List<? extends Fruit> = new ArrayList<Apple>();这样写呢?
这样写的目的无非是想利用一下,抽象的基类来表示子类(也就是父类引用指向子类对象)。但是这里需要注意的一个问题就是,
java的泛型机制是通过它的编译系统来完成的(其实,数组和泛型容器在这里的区别很大,见下面的例子)。List<? extends Fruit>告诉编译器:"我是一个可以装载某个具体的Fruit的子类的List容器"。
而=new ArrayList<apple>();则指明了这个list装载的实际上是Apple类型。那为什么list.add(new Apple())通不过编译呢?因为编译器只是
知道list可以装载某个Fruit的子类,但是它也不知道具体是那种。
其实上面的机制主要是为了保证java运行时的安全性。试想,如果你定义了List<? extends Fruit> list = new ArrayList<Apple>();
而list.add(new 任何Fruit的子类)可以通过编译的话,那么你的list就有可能装入了Banana类型,这样就与你的初衷 ArrayList<Apple>矛盾了
这样泛型的安全性就保证不了了。
<? extends Fruit>表示的是Fruit或者任何Fruit的子类,其中Fruit最大。<? super Fruit> 表示Fruit和任何Fruit的父类,
Fruit最小,这样的话,用List<? super Fruit>来声明的话,就可以任意的add Fruit的子类了,因为它肯定是你运行时对象的子类,这样并不破坏
泛型机制的装载安全性。
List<? super Banana> list2 = new ArrayList<Banana>();
list2.add(Banana);
list2.add(SmallBanana);
list2.add(BigBanana);
以上的写法都是可以的
*
*
*/
//Banana[] b = new BigBanana[10];
//List<Banana> list2 = new ArrayList<BigBanana>();
/*
* 上面的两个例子,b可以通过编译,但是list2没有,为什么?其实还是为了保证安全性(数组是不保证的,如果b[0]=new SmallBanana(),编译不报错,运行时候会报错ArrayStore),可能不慎引入
* Banana的子类但不是BigBanana类型。这样在编译的时候就保证了安全性。
*
*/
}
}
class Fruit{
}
class Apple extends Fruit{
}
class Banana extends Fruit{
}
class BigBanana extends Banana{
public String toString() {
return "I am a BigBanana";
}
}
class SmallBanana extends Banana{
public String toString() {
return "I am a SmallBanana";
}
}
相关文章推荐
- Java 理论与实践: 使用通配符简化泛型使用 (二)
- javawebday65(泛型、通配符、注解、反射 注解使用)
- 浅析Java 泛型
- Java 泛型 通配符类型
- Java笔记之泛型(通配符)
- Java 理论与实践: 使用通配符简化泛型使用
- 黑马程序员--Java基础加强--05.【泛型通配符】【个人总结】
- Java基础之泛型——使用通配符类型参数(TryWildCard)
- Java基础(21):泛型—泛型的定义、用法与类型通配符的使用方式
- java 泛型详解(普通泛型、 通配符、 泛型接口)
- 初学Java,泛型类型通配符(三十七)
- [转贴] Java 理论与实践: 使用通配符简化泛型使用
- [Java 10 泛型] 泛型通配符 Info<?> i = new Info<String>(); 在程序中定义没有方法的接口,称之为标识接口
- java 泛型详解(普通泛型、 通配符、 泛型接口)
- Java 泛型学习三 通配符
- java_泛型,设置类型通配符的上限
- Java 泛型通配符extends 与 super
- java 泛型通配符 直接源码
- 黑马程序员——JAVA基础之泛型和通配符
- Java的泛型和通配符 泛型: