黑马程序员—高新技术:泛型Generic

本文详细介绍了Java泛型的原理、应用、注意事项及高级特性,包括泛型的命名理解、参数化与原始类型兼容性、通配符使用、定义泛型类型等核心概念,旨在帮助开发者更好地理解和运用泛型技术。

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

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

泛型也是1.5以后出现的一种很重要的新特性。泛型是1.5众多的新特性中最难的部分。文档非常复杂,涉及非常多的数学公式。

泛型的应用:          
          能解决类型转换之苦,在集合,在反射中都有用到,不一定非要用,怎么简便怎么来。
          没有使用泛型时,不管上面类型的对象,都能存入一个集合之中。使用泛型集合,可以将一个集合的元素限定为一个特点的类型。
          这样集合只能存储指定类型的数据。这样更安全。并且在后续对集合进行操作时,编译器也能得知对象类型,不再需要强制类型转换
          在jdk1.5中,你还可以将原来不同类型的数据存入到一个集合中去,但是编译器会报出unchecked(为经核对的)警告。
          这个警告也可以通过注解进行压制。

另外:泛型是提供给Java编译器使用的。可以限定集合中的输出类型,挡住非法的输入类型。


          编译器编译带类型说明的集合时会去掉类型信息,使程序运行效率不受影响。对于参数化的泛型类型,getClass()的
返回值和原始类型完全一样。
          由于编译生成的字节码文件会去掉泛型的类型信息,只要能跳过编译器。就可以在某个泛型集合中加入其他类型的数据,例如,
用反射得到集合,在调用ADD方法即可。
          集合在编译完成后会去除泛型信息。
泛型是给编译器看的,而运行的时候已经没有任何泛型的痕迹了
 
 泛型的名词理解: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<Stirng> v=new Vector<Object>(); //错误  不写<OBJECT>反而没错,写了就是明知故犯
 Vector<Object> v=new Vector<String>(); //也错误,在集合中Object声明和String冲突,泛型中没有继承。
 
 在创建数组实例时,数组的元素不能使用参数化的类型。例如,下面语句有错误:
 Vector<Integer>vectorList[] = new Vector<Integer>[10];
 
 思考题:Vector v=new Vector<String>();
  true;参数化的类型可以给原始类型
  Vector<Object>v1=v;
  rrue;也是对的,看似错了,实际上是对的,v是原始类型。而我们推导的过程会有赋值动作,而编译器只会检查语法。NEW出来的跟对象没有任何关系。
 
***********************
泛型中的问好?——通配符。
问题:定义一个方法,打印出参数化类型中所有的数据。
泛型写入通配符,因为外部传入的集合可能是其他的参数类型,会产生不匹配的问题。而通配符可以解决
虽然能用通配符匹配传入值到方法,但是不能知道进来的是什么类型。而添加内容还是会收到参数限定


总结:使用?通配符可以引用各种参数化的类型,?通配符定义的变量主要作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。


通配符的扩展。例:
限定通配符的上边界:
正确:Vector<? extends Number> x=new Vector<Integer>();
错误:Vector<? extends Number> x=new Vector<String>();  String类型不在继承的number和它的子类范围内。


限定头佩服的下边界:  注意:限定头佩服总是包含自己。
          正确:Vector<? super Integer> x=new Vector<Number>();  //表示下限是Integer,只能是它往上的类,父类,父类的父类等。

          错误:Vector<? super Integer> x=new Vector<Byte>(); 


*map集合,获取值常用的通过键获取值,或者通过每一个键值对  比如map.Entry*
 因为map本身没有迭代,因为没有实习Iterable接口。
 而map中有个set集合,将map变成set,set装着每一个Entry可以通过它完成。
 在jsp中,这样的应用非常多。
 HashMap<String,Integer> maps = new HashMap<String,Integer>();
//添加原始
maps.put("lm", 22);
maps.put("ll", 25);
//如何遍历map集合呢,变成set集合
Set<Map.Entry<String, Integer>> entry=maps.entrySet();
for (Map.Entry<String, Integer> entryset: entry) {
System.out.println(entryset.getKey() + "*" + entryset.getValue());
}
 
 学习中是拿别人的东西过来用,学后是做东西给别让用。
 由C++的模板函数引入泛型。Java的泛型是从c++中的泛型借鉴而来的,因为Java虚拟机设计的原因泛型功能没有c++的功能强大。
 注意:只有引用类型才能作为泛型的实际参数。
 ******************************************
定义泛型类型。
如果类的实例对象的多处都要用到同一个类型参数,既这些地方引用的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,
也就是类级别的泛型。
语法格式如下:
          public class GenericDao<E>{  //如要要统一类型,那么泛型可以放到类上面。
          private T field1;
          public void save(T obj){};
          piblic T getByld(int id){};
          类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,如下两种方式都可以。
          GenericDao<String>dao=null;
          new genericDao<String>();

在类中如果存在多个方法要使用泛型,那么就使用类级别的泛型

}
 
package 泛型学习;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Date;
import java.util.Vector;

/**
	 * 定义一个方法:可以将任意类型的数组中的所有元素填充为相应类型的某个对象。
	 * 定义方法,从一个任意集合或者数字中将值转入一个指定内
	 */
public class GeneTest {
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		//验证:
		copy1(new Vector<String>(),new String[10]);
		copy2(new Date[10],new String[10]);  //这一行是取交集的类型。所以没有问题
		//copy1(new Vector<Date>(),new String[10]);//这一行因为泛型具备传播性,所以报错。
		
		//通过方法反射的使用,我们可以得到这个方法中参数的泛型。
		//Vector <Date> v1= new Vector<Date>();
		Method applyMethod = GeneTest.class.getMethod("applyVector", Vector.class);
		Type[] types=applyMethod.getGenericParameterTypes();//获得泛型参数。
		ParameterizedType pType = (ParameterizedType)types[0];//获得参数列表中第一个泛型类型。
		System.out.println(pType.getRawType());//获取原始类型
		System.out.println(pType.getActualTypeArguments()[0]);//获取指定位置的实际参数。
		
	}
	
	public static void applyVector(Vector<Date> v1){//我们不能通过变量v1得到泛型参数,但是可以作为方法的参数得到。
		
	}
	private static <T>void fillArray(T[] a,T obj){
		for (int i = 0; i < a.length; i++) {
			a[i] =obj;  //将取到的每一个值都进行转化。
		}
	}
	private static <T> void copy1(Collection<T> dest,T[] src){ //指定数组。
		//for或者add即可
	}
	private static <T>void copy2(T[] dest,T[] src){}
	
	
	
	
	
}

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------详细请查看: http://edu.youkuaiyun.com
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值