黑马程序员-------(高新技术)泛型

本文深入讲解Java泛型的基础概念,包括泛型类型、参数化类型、原始类型等,并探讨了泛型中的通配符及其扩展用法。同时,文章还介绍了如何通过反射获取泛型的实际类型参数,并给出了泛型在DAO模式中的应用实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

-------------java培训android培训、java博客、java学习型技术博客、期待与您交流! --------------

了解泛型

ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
整个称为ArrayList<E>泛型类型
ArrayList<E>中的E称为类型变量或类型参数
整个ArrayList<Integer>称为参数化的类型
ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
ArrayList<Integer>中的<>念着typeof
ArrayList称为原始类型
参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象,编译报告警告,例如, Collection<String> c = new Vector();//可不可以,不就是编译器一句话的事吗?
原始类型可以引用一个参数化类型的对象,编译报告警告,例如, Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去
参数化类型不考虑类型参数的继承关系:
Vector<String> v = new Vector<Object>(); //错误!///不写<Object>没错,写了就是明知故犯
Vector<Object> v = new Vector<String>(); //也错误!
编译器不允许创建泛型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型,例如,下面语句有错误:
  Vector<Integer> vectorList[] = new Vector<Integer>[10];
思考题:下面的代码会报错误吗?
Vector v1 = new Vector<String>();
Vector<Object> v = v1;

泛型中的?通配符

问题:
定义一个方法,该方法用于打印出任意参数化类型的集合中的所有数据,该方法如何定义呢?
错误方式:
public static void printCollection(Collection<Object> cols) {
  for(Object obj:cols) {
   System.out.println(obj);
  }
  /* cols.add("string");//没错
   cols = new HashSet<Date>();//会报告错误!*/
}
正确方式:
public static void printCollection(Collection<?> cols) {
  for(Object obj:cols) {
   System.out.println(obj);
  }
  //cols.add("string");//错误,因为它不知自己未来匹配就一定是String
  cols.size();//没错,此方法与类型参数没有关系
   cols = new HashSet<Date>();
 }
总结:
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
泛型中的?通配符的扩展

限定通配符的上边界:
正确:Vector<? extends Number> x = new Vector<Integer>();
错误:Vector<? extends Number> x = new Vector<String>();
限定通配符的下边界:
正确:Vector<? super Integer> x = new Vector<Number>();
错误:Vector<? super Integer> x = new Vector<Byte>();
提示:
限定通配符总是包括自己。
?只能用作引用,不能用它去给其他变量赋值
 Vector<? extends Number> y = new Vector<Integer>();
 Vector<Number> x = y;
 上面的代码错误,原理与Vector<Object > x11 = new Vector<String>();相似,
 只能通过强制类型转换方式来赋值。

通过反射获得泛型的参数化类型

示例代码:
	Class GenericalReflection {
		  private Vector<Date> dates = new Vector<Date>();
		  public void setDates(Vector<Date> dates) {
		    this.dates = dates;
		  }
		  public static void main(String[] args) {
		   Method methodApply = GenericalReflection.class.getDeclaredMethod("applyGeneric", Vector.class);
		   ParameterizedType pType = (ParameterizedType)
		                    (methodApply .getGenericParameterTypes())[0];
		            System.out.println("setDates("
		                    + ((Class) pType.getRawType()).getName() + "<"
		                    + ((Class) (pType.getActualTypeArguments()[0])).getName()
		                    + ">)" );
		  }
	}

泛型DAO的应用:
public abstract class DaoBaseImpl<T> implements DaoBase<T> {
	protected Class<T> clazz;
	public DaoBaseImpl() {
		Type type = this.getClass().getGenericSuperclass();
		ParameterizedType pt = (ParameterizedType) type;
		this.clazz = (Class) pt.getActualTypeArguments()[0];
		System.out.println("clazz = " + this.clazz);
	}
	}
public class ArticleDaoImpl extends DaoBaseImpl<Article> implements ArticleDao {
	}


 

package cn.itcast.day2;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import cn.itcast.day1.ReflectPoint;

public class GenericTest {
	public static void main(String[] args) throws Exception{
		/*ArrayList collection1 = new ArrayList();
		collection1.add(1);
		collection1.add(1L);
		collection1.add("abc");
		int i = (Integer) collection1.get(1);//编译要强制类型转换且运行时出错!*/
		
		/*编译器在编译完成后,会去掉泛型的<信息>*/		
		ArrayList<String> collection2 = new ArrayList<String>();
		//collection2.add(1);
		//collection2.add(1L);
		collection2.add("abc");
		String element = collection2.get(0);//编译要强制类型转换且运行时出错!
		System.out.println(element);
		
		Constructor<String> constructor1 = String.class.getConstructor(StringBuffer.class);	
		String con1_str = constructor1.newInstance(new StringBuffer("abc"));
		//String con1_str2 = constructor1.newInstance("abc");
		System.out.println(con1_str);
		System.out.println(con1_str.charAt(2));
		
		
		ArrayList<Integer> collection3 = new ArrayList<Integer>();
		//判断collection2与collection3在编译完成后的字节码是否对应同一个字节码
		/*因为编译器在编译完成后,会去掉泛型的<信息>*/		
		System.out.println(collection3.getClass() == collection2.getClass());
		
/*穿透编译器,赋值不匹配的类型数据*/
		//正常情况下,
		//collection3.add("sss");
		//ArrayList<Integer> collection3 是Integer类型,传入"sss"的String类型会报错
		//(泛型是可以编译器看的)所以用反射的方法,可以传入不匹配的类型数据,如下:
		collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
		System.out.println(collection3.get(0));
/*ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
		整个称为ArrayList<E>泛型类型
		ArrayList<E>中的E称为类型变量或类型参数
		整个ArrayList<Integer>称为参数化的类型
		ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
		ArrayList<Integer>中的<>念着typeof
		ArrayList称为原始类型
*/
/*参数化类型与原始类型的兼容性:*/
		Collection<String> c1 = new Vector();
		Collection c2 = new Vector<String>();
		
/*参数化类型不考虑类型参数的继承关系:*/
		//Vector<String> v = new Vector<Object>(); 		//编译不通过
		//Vector<Object> v = new Vector<String>(); 		//编译不通过

/*编译器不允许创建泛型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型,例如,下面语句有错误:*/
		//Vector<Integer>  [] vectorList = new Vector<Integer> [10];
		
		//编译器只会一行一行的扫描
		//所以下面编译会通过
		Vector v1 = new Vector<String>(); 
		Vector<Object> v = v1;
		
		
		printCollection(collection3);
		
		
		HashMap<String,Integer> maps = new HashMap<String,Integer>();
		maps.put("zxx", 28);
		maps.put("lhm", 35);
		maps.put("flx", 33);
		
		Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();
		for(Map.Entry<String, Integer> entry:entrySet){
			System.out.println(entry.getKey()+"----"+entry.getValue());
		}
		System.out.println("------自定义泛型------");
		//两个类型的交集是int,但是会自动装箱成Integer
		int i = add(3,5);
		//两个类型的交集是Number
		Number n1 = add(3.5,2);	
		//两个类型的交集是Object
		Object n2 = add(3.5,"abc");	
		
		swap(new String[]{"abc","xyz","itcast"},1,2);
		//泛型定义的方法,只能传入引用数据类型【Integer】,而不能是基本数据类型【int】
		//swap(new int[]{1,2,3,4,56},1,2);
		
		
		
		
		/*只是定义泛型方法的情况
		GenericDao dao = new GenericDao();
		dao.add(new ReflectPoint(3,3));
		String s = dao.findById(1);
		int i11 = dao.findById(1);*/
		
		//定义了泛型类的情况
		GenericDao<ReflectPoint> dao = new GenericDao<ReflectPoint>();
		dao.add(new ReflectPoint(3,3));
		ReflectPoint rp1 = dao.findById(1);
		
		
		//通过反射获得泛型的参数化类型【<Date>】
		//Vector<Date> v11 = new Vector<Date>();
		
		Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class);
		Type[] types = applyMethod.getGenericParameterTypes();
		ParameterizedType pType = (ParameterizedType)types[0];
		//实际类型,他可能有多个,是个数组,所以有【[0]】
		System.out.println(pType.getActualTypeArguments()[0]);;
		//原始类型
		System.out.println(pType.getRawType());
		//---事实上,Eclipse的自动生成方法就用到了以上的反射方法------//
		
	}
	/*泛型的对象本身没有提供直接获取泛型的参数化类型的方法
	 * 但是当把泛型传递到一个方法中使用,那么反射提供了对该方法获取泛型的参数化类型的方法
	 */
	public static void applyVector(Vector<Date> v1){
		
	}
	private static <T>void swap(T[] arr,int i,int j){
		T tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}	
	/*public static int add(int x,int y){
		return x+y;
	}*/
	public static <T> T add(T x,T y){
		return  y;
	}
	public static void printCollection(Collection<?> collection){
		//用通配符修饰的引用变量不能去调用与参数化有关的方法
		//collection.add(1);
		//collection.add("abc");
		//可以调用这个size()方法,与参数化无关的方法
		collection.size();
		collection.toArray();
		for(Object obj:collection){
			System.out.println(obj+"------printCollection");
		}
	}
	
	
}


 

package cn.itcast.day2;

import java.util.Collection;
import java.util.Date;
import java.util.Vector;

public class GenericExam {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
	//1、
		Object obj1 = 122;
		int i = autoConvert(obj1);
		Object obj2 = "abc";
		String s = autoConvert(obj2);
	//4、
		copy1(new Vector<String>(),new String[10]);
		copy2(new Date[10],new String[10]);
	}
	//1、编写一个泛型方法,自动将Object类型的对象转换成其他类型。
	public static <T> T autoConvert(Object obj){
		return (T)obj;
	}
	//2、定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象。
	private static <T> void fillArray(T[] arr,T obj){
		for(int i=0;i<arr.length;i++)
			arr[i]=obj;
	}
	//3、采用自定泛型方法的方式打印出任意参数化类型的集合中的所有内容。
	public static <T>void printCollection(Collection<T> collection,T obj){
		//用通配符修饰的引用变量不能去调用与参数化有关的方法
		//collection.add(1);
		//collection.add("abc");
		//可以调用这个size()方法,与参数化无关的方法
		collection.size();
		collection.toArray();
		for(Object objx:collection){
			System.out.println(objx+"------printCollection");
		}
	}
	//4、定义一个方法,把任意参数类型的集合中的数据安全地复制到相应类型的数组中。
	public static <T> void copy1(Collection<T> dest,T[] src){
		
	}
	public static <T> void copy2(T[] dest,T[] src){
			
	}


}


 

package cn.itcast.day2;

import java.util.Set;
//Dao:data access object----增删改查

//想要定义一个类之后,即可以操作“人”和“产品”两种类型


public class GenericDao<E> {
	//想要两个方法的类型统一,就有定义泛型类
	/*public <T>void add(T p){
		
	}
	public <T> T findById(int i){
		return null;
	}*/
	public void add(E p){
		
	}
	public E findById(int i){
		return null;
	}
	public void delete(E obj){
		
	}
	public void delete(int i){
		
	}
	public void update(E obj){
		
	}
	/*静态方法是不能用泛型的泛型类型【E】,
	 * 因为:对象还没定义,静态方法已经存在了,即还不知道对象类型,怎么能调用
	public static void update2(E obj){
	
	}*/
	//将静态方法,独立成泛型方法调用。与泛型类无关。下面就是泛型方法的模板
	public static <E> void update2(E obj){
		
	}
	public Set<E> findByConditions(String where){
		return null;
	}
}


-------------java培训android培训、java博客、java学习型技术博客、期待与您交流! --------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值