参考文章:1.《JAVA编程思想 第4版》 2.java泛型详解http://luckykapok918.blog.163.com/blog/static/2058650432012102341548827/
Java泛型(generics)是JDK
5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(
public class Erased<T>{
private final int SIZE=100;
public static void f(Object arg){
T var=new T();//Error
T[] array=new T[SIZE];//Error
T[] array=(T) new Object[SIZE];//Unchecked warning
}
}interface Payable<T>{}
class Employee implements Payable<Employee>{}
class Hourly extends Employee implements Payable<Hourly>{}public class list2<W,T>{
void f(List<T> v){}
void f(List<W> v){}
}
类型擦除的基本过程也比较简单,
问题1:类型参数向上转型。
假设Apple类是Fruit类的子类,很多人会常常写这样一句代码:List<Fruit> flist=new ArrayList<Apple>();这句代码是错误的!!!
有人可能认为这不是向上转型么?事实上这不是向上转型。Apple的List不是Fruit的List,因为Fruit的List将会持有各种类型的Fruit,比如Orange,Banana。但是Apple的List持有的只是Apple和它的子类。因此,这种代码完全就是错误的。
我们需要注意,List<Fruit> flist=new ArrayList<Fruit>();flist.add(new Apple());这样的代码才是大家所谓的向上转型。
问题2:泛型对象调用方法。
看看下面的代码:
class HasF{
public void f();
}
class Manipulator<T>{
private T tt;
public Manipulator(T tt){this.tt=tt;}
public void mani(){tt.f();}//Error
public T get(){return tt;}
}
public class Erase(){
public static void main(String []args){
HasF hf=new HasF();
Manipulator<HasF> mad=new Manipulator<HasF>(hf);
mad.mani();
}
} 这段代码为什么会错呢,因为JAVA并不知道泛型的参数类型,对于T,它可能是各种类型,如String,Integet。不是这些类都有f()方法,这么调用f()方法当然是错误的。
问题3:创建类型实例。
对于以下代码:
public class Erased<T>{
private final int SIZE=100;
public static void f(Object arg){
T var=new T();//Error
T[] array=new T[SIZE];//Error
}
}
以上实例中出现的问题就是因为擦除以后,编译器无法识别类型参数,因为解决的方法就是为类型参数指定一个大概的范围,这个就是边界。
在使用泛型类的时候,既可以指定一个具体的类型,如List<
如上所示,试图对一个带通配符的泛型类进行操作的时候,
在有了边界以后我们再来看上述问题的解决之道。
问题1:我们只需将List<Fruit> filist=new ArrayList<Apple>();换成List<? entends Fruit> filist=new ArrayList<Apple>();即可。此时flist是”具有任何从Fruit继承的类型的列表“。
问题2:将代码改成:
class HasF{
public void f();
}
class Manipulator<T extends HasF>{
private T tt;
public Manipulator(T tt){this.tt=tt;}
public void mani(){tt.f();}
public T get(){return tt;}
}
public class Erase(){
public static void main(String []args){
HasF hf=new HasF();
Manipulator<HasF> mad=new Manipulator<HasF>(hf);
mad.mani();
}
}问题3:将代码改成:
class ClassFactory<T>{
T x;
public ClassFactory(Class<T> kind){
try{
x-kind.newInstance();
}catch(Exception e){
new RuntimeException(e);
}
}
}
泛型类与一般的Java类基本相同,只是在类和接口定义上多出来
class ClassTest<X extends Number, Y, Z> {
private X x;
private static Y y; //编译错误,不能用在静态变量中
public X getFirst() { //正确用法
return x;
}
public void wrong() {
Z z = new Z(); //编译错误,不能创建对象 ,因为泛型类并没有自己独立的Class类对象
}
} 2.使用泛型方法public <T> T f(T x){
return x;
} 这里面说明一点:当使用泛型类时,必须在创建对象的时候指定参数类型的值,而使用泛型方法的时候,通常不必指明参数类型,因为编译器会为我们找出具体的类型,这叫做"类型参数推断“。我们可以像调用普通方法一样调用f()。泛型方法它独立于类,对于这个方法的使用,一般只要可能的话,尽量使用泛型方法。3.容器类的使用
BruceEckel说过:"使用泛型类关于类型机制最吸引人的地方在于容器类的使用。”public class ListMaker<T>{
private Class<T> kind;
T[] create(){
return (T[])Array.newInstance(kind, 100);
}
}
由于擦除,kind将被存储为Class,没有任何参数,因此,使用它创建数组时候,Array.newInstance()并没有拥有kind所蕴含的类型信息,这不会产生具体的结果,所以要转型,这会产生一条警告,但是如果创建的是一个容器,编译器将不会给出任何警告,如下:public class ListMaker<T>{
List<T> create(){
return new ArrayList<T>();
}
}
原文:http://blog.csdn.net/a1091220321/article/details/24145691