泛型程序设计(Generic programming):可以被很多不同的类型的对象所重用。比那些直接使用Object变量,然后强制类型的转换的代码具有更好的安全性和可读性。
使用类型参数(type parameters)可以将需要使用的类型,提前声明。如:
ArrayList<String> list = new ArrayList<String>();
使用类型参数可以告知这个类适用于什么类型,当调用对应的get()方法的时候,不需要进行强制类型转换,编译器本身就知道其对应的类型。
当实现一个泛型的时候非常不容易,因为你需要知道这个这个类对应的所有用途及其类型,所以java提供了通配符类型,来解决这个问题。
泛型类,就是指具有一个或者多个类型变量,也就是说这个类适应这几种类型。
使用类型变量T,用<>括起来,放在类名后面。这个泛型可以有多个类型变量,如<T,U>
可以使用类定义的类型变量指定类中属性和方法的类型。
public class Pari<T> { private T first; private T second; public Pari(){ first = null; second = null; } public Pari(T first,T second){ this.first = first; this.second = second; } public T getFirst(){ return first; } public T getSecond(){ return second; } public void setFirst(T value){ first = value; } public void setSecond(T value){ second = value; } }
泛型方法既可以在普通类中,也可以在泛型类中,定义方式是在方法名前加<T> T,说明该方法是泛型方法
public static <T> T getText(T param){ return param; }
有的时候,比如对于特定的方法执行特定的操作,但是该操作不适用于一些类型,这时可以对类型变量T设置限定,可以使其集成特别的类或者接口(没错,在这里对于接口也是使用继承,因为使用extends更加接近子类的意思),一个类型变量或通配符可以有多个限定
比如:T extends Comparable & Srializable
public static <T extends Comparable> Pari<T> getMinMax(T[] word){ if(word == null || word.length == 0) return null; T min = word[0]; T max = word[0]; for(int i=1;i<word.length;i++){ if(word[i].compareTo(max) > 0) max = word[i]; if(word[i].compareTo(min) < 0) min = word[i]; } return new Pari<T>(min,max); }
JVM中没有泛型,只有普通的类和方法
所有的类型参数都是用他们的限定类型转换(如果没有类型参数,则使用Object类型),这个过程称为擦除(erased),擦除类型变量,并替换为限定类型
有时为保持类型安全性,需要插入强制类型转换
不能用类型参数代替基本类型:因此Pari<double>是错误的,需要使用pari<Double>,原因是类型擦除,擦除之后为Object类型,object类型并不能存储double值
虚拟机中的对象总有一个特定的非泛型类型。因此,所有类型查询只产生原始类型。
如:if(a instanceof Pari<T>)是错误的,因为只能查询原始类型,即Pari
又如:
Pari<String> pari1 = ...
Pari<Employee> pari2 =...
if (pari1.getClass() == pari2.getClass())返回true,因为两次getClass()都是返回Pari.class
不能实例化参数类型数组
Pari<Sting>[] table = new Pari<String>[10];
因为当类型擦除后,为Pari[]类型,即可以转化为Object[]类型,这时候如果 table[0] = new Pari<Employee>();这时候就会抛出ArrayStoreException异常,所以,不允许创建参数类型数组。但是可以声明。如果想要实现可以使用通配类型数组然后进行强制类型转换
Pari<String>[] table = (Pari<String>[]) new Pari<?>[10];
new T()或者T.class这些都是非法的,因为类型擦除后为new Object(),这并不是想要的。
public Pari(){ first = new T(); second = new T(); }
但是可以通过反射调用Class.newInstance方法构造
public static<T> Pari<T> makePari(Class<T> c){ return new Pari<>(c.newInstance(),c.newInstance()) }
public static class Singleton<T>{ public static T s1; public static getS1(){ return s1 } }注意只是在静态类中不可以使用,普通类中可以使用。
public class Problem<T> extends Exception{}是不对的。但是可以在异常规范中使用类型变量,意思就是可以在抛出异常的方法中使用类型变量
泛型类允许继承或者扩展其他的泛型类,如ArrayList<T>类实现List<T>接口,即一个ArrayList<Manager>可以被转换为List<Manger>。
但是ArrayList<Manager>不能够实现ArrayList<Employee>或List<Employee>。
所以记住,泛型的继承实现,需要保证其类型参数的一致。
固定的泛型类型系统,存在很多的局限性,为了解决这一点,引入了:通配符类型。
Pari<? extends Employee>表示任何泛型Pari类型,他的类型参数是Employee的子类,如Pari<Manager>,当使用了通配符泛型,就可以将Pari<Manager>,给以这个Pari<? extends Employee>参数的函数了。
通配符限定与类型变量限定十分类似,但是可以指定一个超类型限定。
? super Manager
这个通配符限定了Manager的所有的超类,这与上面讲的通配符继承恰恰相反,这时候Pari<Employee> 或者Pari<Object>可以实现或者继承Pari<? super Manager>
带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。
需要注意,通配符不是类型变量,不能像之前的泛型类型参数一样定义变量或者方法
? t = p.getFirst()这是错误的。
原文地址:http://blog.csdn.net/colin_yjz/article/details/46663421