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;
}