参考文章: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>(); } }
HDU 1534 Schedule Problem 差分约束输出一组解,布布扣,bubuko.com
HDU 1534 Schedule Problem 差分约束输出一组解
原文:http://blog.csdn.net/u011686226/article/details/24185409