黑马程序员-泛型

黑马程序员-泛型

 

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

  

概念:

      泛型(Generic)是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。Java语言引入泛型的好处是安全简单。使用java泛型,我们可以省掉强制类型转换。编译器会保留参数的类型信息,执行类型检查,执行类型转换操作。因此开发人员不需要自己确保类型转换的安全性,而把这个交给编译器去做。 

 

泛型涉及的专业术语:

       1、ArrayList<E> 整个称为泛型类型。

       2、ArrayList<E>中的E称为类型变量或类型参数。

       3、ArrayList<Integer>称为参数化的类型。

       4、ArrayList<Integer>中Integer称为类型参数的实例或实际类型参数。

       5、ArrayList<Integer>中<>念作typeof。

       6、ArrayList称为原始类型。

   

使用泛型的规则和注意: 

1、泛型的类型参数可以有多个。
2、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
3、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String");
6、参数化类型不考虑类型参数的继承关系。如:Vector<Object> vector=new Vector<String>()是错误的。
7、不能创建参数化的类型的数组。如:List<String>[] arr=new List<String>[5]错误。
8、泛型的参数类型还可以用&表达式。如<V extends Serializable & Cloneable>。
 

 参数化类型和原始类型的兼容性:

                List list=new ArrayList<String>();

             List<String> list=new ArrayList();

            这两种形式都是允许的。

 

类型擦除:

           类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。

 

代码示例:

         初识泛型:

public class GenericDeno {

	/**
	 * 泛型的初步认识
	 * @param args
	 */
	public static void main(String[] args) {
		 //首先在jdk1.5之前没有泛型是这样做的
            List list=new ArrayList();
            list.add(1);
            list.add(100l);
            list.add("黑马程序员");
            //在取出集合中的类型时由编码人员做强转,显然这样做是不安全的。虽然编译通过,但程序运行时会出错。
            int i=(Integer)list.get(1);
            
         //jdk1.5后用泛型的做法,可以看出泛型是在编译时期加了类型验证,让程序更安全。
            List<String> list1=new ArrayList<String>();
            list1.add("aaa");
            list1.add("bbb");
            list1.add("黑马程序员");
            //这里不需要手动强制转换了,由编译器自动或隐式完成了
            String value=list1.get(1);
	}

}

        理解擦除:

public class GenericDemo2 {

	/**
	 * 理解擦除
	 * @param args
	 */
	public static void main(String[] args) {
		//在运行时期,内存中的字节码中类型参数已被擦除,所以list_1和list_2关联的是同一份字节码。
		//泛型只是在编译器加了类型验证。
         ArrayList<String> list_1=new ArrayList<String>();
         ArrayList<Integer> list_2=new ArrayList<Integer>();
         
         Class clazz_1=list_1.getClass();
         Class clazz_2=list_2.getClass();
         
         System.out.println(clazz_1==clazz_2);//true
         
	}
}

    通配符(?):    

public class GenericDemo3 {

	/**
	 * ?通配符
	 * @param args
	 */
	//使用?通配符何以引用其他任意参数化的类型,?通配符定义的变量主要用作引用,可以调用与类型参数无关的方法,不可调用于类型参数有关的方法。
	public static void main(String[] args) {
		ArrayList<Integer> list=new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		list.add(3);
		//当不明确实际参数类型,可以用?号通配符。
		printColl(list);

	}
    public static void printColl(Collection<?> coll){
    	//coll.add(e);不能调用与类型参数有关的方法。
    	//coll.size();可以调用于类型参数无关的方法。
    	for(Object object : coll){
    		System.out.println(object);
    	}
    }
}

    类型推断:

public class GenericDemo4 {

	/**
	 * 类型推断
	 * @param args
	 */
	public static void main(String[] args) {
		//传入的两个实际类型参数都是int,由于T只能是引用类型会先装箱成Integer类型,然后编译器会自动推断出两个实际类型参数的最小共有类型。
		Integer integer=add(3,5);
		
		//由于3.6和4都是number,所以推断出T的实际类型参数为Number类型。
		Number number=add(3.5, 4);
		//float f=add(3.5, 4);错误
		
		//这里也和上面一样的推断,都是取最小共有类型。所以3和“abc”的共有类型是Object。
		Object object=add(3, "abc");
		
		swap(new String[]{"abc","xyz"}, 0, 1);
		//swap(new int[]{1,2}, 0, 1);错误,因为泛型的类型参数只能是引用类型,不能使基本类型。
     
	}
	// 定义一个泛型方法
    public static <T> T add(T x,T y){
    	
    	return null;
    }
    
    //一个交换任意数组元素的方法
    public static <T> void swap(T[] t,int i,int j){
    	T temp=t[i];
    	t[i]=t[j];
    	t[j]=temp;
    }
}

      异常中的泛型:

public class GenericDemo5 {

	/**
	 * 泛型在异常中的应用
	 * @param args
	 * @return 
	 */
    public static <T extends Exception> void Method() throws T{//声明泛型时必须说明T是Exception的子类。
    	try {
			
		} catch (Exception e) {//catch中不能捕捉T
			throw (T)e;//只能抛出T类型异常。
		}
    }
}

     自定义泛型接口、泛型类和泛型方法:

public class GenericTest {

    public static void main(String[] args) {

        Box<String> name = new Box<String>("corn");
        System.out.println("name:" + name.getData());
    }

}

class Box<T> {

    private T data;

    public Box() {

    }

    public Box(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

}

       通过反射获取参数化类型和实际类型参数:

public class GenericDemo6 {

	/**
	 * 反射获取参数化类型
	 * @param args
	 */
	public static void main(String[] args)throws Exception {
		Method method=GenericDemo6.class.getMethod("method", Vector.class);//反射method方法
		Type type=method.getGenericParameterTypes()[0];//通过method的方法获取泛型类型
		ParameterizedType p=(ParameterizedType) type;
		System.out.println(p.getActualTypeArguments()[0]);//class java.util.Date获取实际类型参数

	}
    public static void method(Vector<Date> v){
    	
    }
}



 

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






 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值