泛型的介绍,内部原理,更深应用,泛型中的?通配符,上限,下限



package com.base_super.generic;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Vector;

/**
 * 泛型,JDK1.5以后提出的新特性
 * 	泛型是提供给javac编译器使用的。
 * 		可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时,
 * 		会去掉“类型”信息,是程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样,
 * 		由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型结合中加入其它类型的数据。
 * 
 * 泛型术语:
 * 	ArrayList<E>类定义和ArrayList<Integer>类引用中设计如下术语:
 * 		1,整个成为ArrayList<E>泛型类型
 * 		2,ArrayList<E>中的E成为类型变量或类型参数
 * 		3,整个ArrayList<Integer>成为参数化的类型
 * 		4,ArrayList<Integer>中的Integer成为类型参数的实例或实际类型参数
 * 		5,ArrayList<Integer>中的<>,念做typeof
 * 		6,ArrayList成为院士类型
 * 	参数化类型与院士类型的兼容性:
 * 		1,参数化类型可以引用一个原始类型的对象。编译会出现警告,但编译通过。
 * 			例如:Collection<String> c=new Vector();
 * 		2,原始类型可以引用一个参数化类型的对象。编译会出现警告,但编译通过。
 * 			例如:Collection c=new Vector<String>();
 * 	参数化类型不考虑类型参数的继承关系:
 * 		1,Vector<String> v=new Vector<Object>();//编译错误
 * 		2,Vector<Object> v=new Vector<String>();//编译也错误,前后泛型必须相同
 * 	在创建数组实例时,数组的元素不能使用参数化的类型。下面的例子是编译不通过的,错误的,不能这样写
 * 		例如:Vector<Integer> vector[]=new Vector<Integer>[10];
 * 	思考一下:
 * 		Vector v=new Vector<String>();首先这句是正确的
 * 		Vector<Object> vv=v;//这句也是正确的,要分开来看,不能自己连在一起看,想编译器的执行代码的方式,是一行一行的执行,
 * 		执行第一行的时候,是把参数化的类型转化为原始类型,
 * 		执行第二行的时候,是把原始类型转化为参数化的类型。
 * @author wjw
 */
public class Generic_class1 {
	public static void main(String[] args) throws Exception {
		method();
	}
	public static void method() throws Exception{
		List<String> list1=new ArrayList<String>();
		list1.add("aaa");
		list1.add("bbb");
		list1.add("ccc");//此时该ArrayList对象只能存入字符串,因为泛型限定了
		System.out.println(list1);
		
//		System.out.println(Arrays.asList(list1));//这样也许就会明白Arrays.asList(Object[] obj)是这种类型的了
		
		//反射,实现构造器用泛型,就不用强转了
		Constructor<String> con=String.class.getConstructor(StringBuffer.class);
		String str=con.newInstance(new StringBuffer("fdsafd"));//注意Constructor构造器反射的写法方式
		System.out.println(str);
		
		List<Integer> list2=new ArrayList<Integer>();
		list2.add(22);
		list2.add(33);
		list2.add(44);
		System.out.println(list2);
		
		//打印list1和list2的类文件
		System.out.println(list1.getClass()==list2.getClass());//返回的是true,说明这两者的类文件是一样的
	
		//证明:
		//往整形List集合中插入字符串类型数据,通过反射实现,说明泛型只是在编译期间有效,编译后,就会去掉泛型
		list2.getClass().getMethod("add",Object.class).invoke(list2, "jfkdlsajfkdlsa");
		System.out.println(list2.get(3));//获取我刚通过反射插入到整形List中的字符串数据
		
		
		//下面这两句编译是正确的,不要连起来看,要按照编译器编译的方式看(一行一行的编译)
		Vector v=new Vector<String>();//将参数化类型转化为原始类型
		Vector<Object> vv=v;//将原始类型转化为参数化类型
	
//		method1(list1);//方法中限定的是Integer类型的集合,传入String类型的集合就会报错
//		method2(list1);//虽然方法中限定的是Object类型的集合,但用户泛型的数据类型不具备继承性,所以报错
		//所以为了传入任何类型的集合,定义了用“?”来当占位符,可以传入任何数据类型的集合
		method3(list1); //字符串类型
		method3(list2);//Integer类型
		method4();//限定通配符
	}
	public static void method1(Collection<Integer> coll){}//这个方法传入的参数限定的是Integer的集合,传入其他类型的集合就会报错
	public static void method2(Collection<Object> coll){}//这个方法传入的参数限定的是Object的集合,传入其他类型的集合就会报错
	
	/*	泛型中的?通配符
	 * 1,错误方式
	 * 		public static void printCollection(Collection<Object> cols){
	 * 			for(Object obj:cols){
	 * 					System.out.println(obj);
	 * 			}
	 * 			cols.add("string");//这个没错,因为字符串就是属于Object类型
	 * 			cols=new HashSet<Date>();//这个会报错,因为cols已经定义为Object类型了,不能再赋值Date类型了
	 * 		}
	 * 2,正确方式
	 * 		public static void printCollection(Collection<?> cols){
	 * 			for(Object obj:cols){
	 * 				System.out.println(obj);
	 * 			}
	 * 			cols.add("string");//错误,因为它不知道传进来的是不是String类型的
	 * 			cols。size();//这个正确,此方法和传进来的数据类型没关系
	 * 			cols=new HashSet<Date>();//正确,
	 * 
	 * 		}
	 * 
	 * 
	 */
	public static void method3(Collection<?> coll){//用?当占位符,可以传入任何类型的集合
//		coll=new ArrayList<Integer>();//可以再对coll进行实例化,但不能对其添加数据
//		coll.add(33);//这里报错,我想:类型不匹配
		System.out.println("------------------size:"+coll.size());
	}
	/*
	 * 泛型中的  ?通配符的扩展
	 * 1,限定通配符的上边界:
	 * 		  (1)正确:Vector<? extends Number> x=new Vector<Integer>();
	 * 		 (2)错误:Vector<? extends Number> x=new Vector<String>();
	 * 2,限定通配符的下边界:
	 * 		(1)正确:Vector<? super Integer> x=new Vector<Number>();
	 *		(2) 错误:Vector<? super Integer> x=new Vector<Byte>();
	 *	注意:限定通配符总是包括自己!!!  			 
	 * 	 
	 */
	public static void method4(){
		//上限,限定为Number的子类都可以,其他不行
		Vector<? extends Number> v=new Vector<String>();//会报错,因为String没有继承Number类
		Vector<? extends Number> v1=new Vector<Integer>();//正确,因为Integer继承Number类
		//下限,限定为Integer的父类都可以,其他不行
		Vector<? super Integer> v2=new Vector<Number>();//正确,因为Integer继承Number类
		Vector<? super Number> v3=new Vector<Byte>();//Byte与Integer是平级,不行,出现错误
		
		
	}
}

泛型方法的应用

@Test
	public void Test_r(){
		Integer a[]={1,2,3,4,5,6,7};
		reverse(a);
	}
	public <T> void reverse(T arr[]){
		int top=0;
		int end=arr.length-1;
		while(top<=end){
			swap(arr,top,end);
			top++;
			end--;
		}
		for(int i=0;i<arr.length;i++){
			System.out.print(arr[i]+",");
		}
	}
	//交换数组中两个角标对应的值
	public <T> void swap(T arr[],int pos1,int pos2){
		T temp=arr[pos1];
		arr[pos1]=arr[pos2];
		arr[pos2]=temp;
	}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

King·Forward

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值