Java -- 泛型

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
}



 

原文地址:https://www.cnblogs.com/xj626852095/p/3648078.html