1. 泛型: 允许在定义类,接口时指定类型形参,这个类型形参将在声明变量,创建对象时确定(即传入实际的类型参数,也可以成为类型实参)。
如下示例: 可以对泛型形参做限制 class A<T extends C>{}, T就只能是C的子类。可以用extends设置上限,就可以用super设置下限 <? super T>,对应T或者T的父类。
class A<T> // <T>为泛型, 不必在意T的实际类型,这只是一个类型形参 { T info; } class B extends A<Double> //泛型类继承的时候需要明确参数类型 { } public class Main { public static void main(String[] args) { A<String> a = new A<String>(); //定义变量时 确定泛型类型 为String a.info = "hello_world"; System.out.println(a.info); B b = new B(); //继承时确定泛型为Double b.info = 3.14159; System.out.println(b.info); } }
2. 不管泛型类型的实际类型参数是什么,他们在运行时总是有同样的类,系统中并不会真真生成泛型类。类的静态变量和静态方法在所有实例中共有,所以不能用静态修饰泛型变量。
3. 泛型通配符, 由于有泛型类的存在,所有当泛型类做形参是,有可能并不能确定形参的类型,这时就可以用泛型通配符?。
同时可以限制通配符 void testB(A<? extends C>){} , 这样泛型参数类型就只能是C的子类。
如果Foo是Bar的一个子类,而G是有泛型声明的接口 或者 类,那么G<Foo>并不是G<Bar>的子类。
class A<T> { T info; } class B { void testB(A<?> a) //并不能确定形参的类型,可以用 泛型通配符 ? { System.out.println(a.info); } } public class Main { public static void main(String[] args) { A<String> a1 = new A<String>(); A<Double> a2 = new A<Double>(); a1.info = "hello_world"; a2.info = 3.14159; B b1 = new B(); b1.testB(a1); b1.testB(a2); } }
如下:
ArrayList<?> list = new ArrayList<String>();
list.add("hello"); //报错
泛型通配符 只是表示各泛型List的父类,并不能把元素加进去。
4. 泛型方法,在声明时定义一个或多个类型形参,
格式: 修饰符 <T, S > 返回值类型 方法名(形参列表) { 。。。 }
class A<T> { T info; } class B { void testB(A<?> a) //泛型通配符 { System.out.println(a.info); } } class C { static <T> void testC(T t) //泛型方法 { System.out.println(t); } } public class Main { public static void main(String[] args) { A<String> a1 = new A<String>(); A<Double> a2 = new A<Double>(); a1.info = "hello_world"; a2.info = 3.14159; B b1 = new B(); b1.testB(a1); b1.testB(a2); String t1 = new String("hello"); Double t2 = new Double(3.14); C.testC(t1); C.testC(t2); } }
从上可以看出 泛型通配符和泛型方法 用法上有很多交集,但如果某个方法中一个形参a的类型依赖于 另一个形参b的类型,则形参b的类型声明不能用通配符。因为b的类型无法确定的话,程序无法定义形参a的类型。
5. 泛型类和反射泛形
public class GenericDao<T> {
private T field1;
public void save(T obj){}
public T getId(int id){}
}
泛形的典型应用:BaseDao和反射泛型:
//基本Dao public abstract class BaseDao<T> { private Session session; private Class clazz; //哪个子类调的这个方法,得到的class就是子类处理的类型(非常重要) public BaseDao(){ Class clazz = this.getClass(); //拿到的是子类 ParameterizedType pt = (ParameterizedType) clazz.getGenericSuperclass(); //BaseDao<Category> clazz = (Class) pt.getActualTypeArguments()[0]; System.out.println(clazz); } public void add(T t){ session.save(t); } public T find(String id){ return (T) session.get(clazz, id); } public void update(T t){ session.update(t); } public void delete(String id){ T t = (T) session.get(clazz, id); session.delete(t); } }
public class BookDao extends BaseDao<Book> { // 子类Dao }