黑马程序员_Java泛型

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

1.什么是泛型

1.1 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
      这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
   1.2 不使用泛型和使用泛型的对比
      1.2.1 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,
            “任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。
        对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
      1.2.2 泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
   1.3 泛型的规则和限制
      1.3.1 泛型的类型参数只能是类类型(包括自定义类),不能是基本数据类型。
      1.3.2 同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
      1.3.3 泛型的类型参数可以有多个。
      1.3.4 泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
      1.3.5 泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName("java.lang.String")。
      1.3.6 参数化类型可以引用一个原始类型的对象。
      1.3.7 原始类型也可以引用一个参数化类型的对象。
   1.4 ArrayList<E> 类定义和ArrayList<Integer>类中涉及术语:
      1.4.1 整个ArrayList<E>称为泛型类型。
      1.4.2 ArrayList<E>中的E称为类型变量或类型参数。
      1.4.3 整个ArrayList<Integer>称为参数化的类型。
      1.4.4 ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
      1.4.5 ArrayList<Integer>中的<>念着typeof
      1.4.6 ArrayList称为原始类型。
   1.5 泛型的使用原理:
      泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,
      编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响。
      对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。
      由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,
      就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合对象,再调用其add方法即可。
 

2. 限制泛型

   2.1 在上面的例子中,由于没有限制class GenericsFoo<T>类型持有者T的范围,实际上这里的限定类型相当于Object,
       这和“Object泛型”实质是一样的。限制比如我们要限制T为集合接口类型。只需要这么做:
       class GenericsFoo<T extends Collection>,这样类中的泛型T只能是Collection接口的实现类,
       传入非Collection接口编译会出错。
           注意:<T extends Collection>这里的限定使用关键字extends,后面可以是类也可以是接口。
           但这里的extends已经不是继承的含义了,应该理解为T类型是实现Collection接口的类型,或者T是继承了XX类的类型。

3. 通配符泛型

   3.1 为了解决类型被限制死了不能动态根据实例来确定的缺点,引入了“通配符泛型”。
   3.2 针对上面的例子,使用通配泛型格式为<? extends Collection>,“?”代表未知类型,
       这个类型是实现Collection接口。

 3.2.1 如果只指定了<?>,而没有extends,则默认是允许Object及其下的任何Java类了。也就是任意类。
      3.2.2 通配符泛型不单可以向下限制,如<? extends Collection>,还可以向上限制,
            如<? super Double>,表示类型只能接受Double及其上层父类类型,如Number、Object类型的实例。
      3.2.3 泛型类定义可以有多个泛型参数,中间用逗号隔开,还可以定义泛型接口,泛型方法。

4. 泛型方法

   4.1 是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。

   4.2 使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。
   4.3 一个static方法,无法访问泛型类的类型参数,所以,若要static方法需要使用泛型能力,必须使其成为泛型方法。



/*
	整个称为ArrayList<E>泛型类型
	ArrayList<E>中的E称为类型变量或类型参数
	整个ArrayList<Integer>参数化的类型
	ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
	ArrayList<Integer>中<>念typeof
	ArrayList称为原始类型
	
	在创建数组实例时,数组的元素不能使用参数化的类型
	Vertor<Integer> vectorList[] = new Vector<Integer>[10];
	
	使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,
	可以调用与参数化无关的方法,
	不能调用与参数化 有关的方法
 */
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Vector;

public class Test1 {

	//泛型
	public static void main(String[] args) throws Exception{
		// TODO 自动生成的方法存根
		//Test2();
		//Test1();
		//Test3();
		Test4();
	}
	//泛型的好处是把运行时的错误变成编译时的错误,取出时候还不需转换
	private static void Test2() {
		ArrayList collection1 = new ArrayList();
		collection1.add(1);
		collection1.add(1L);
		collection1.add("abc");
		int i = (Integer)collection1.get(1);
	}
	
	private static void Test1() {
		ArrayList<String> collection1 = new ArrayList<String>();
		//collection1.add(1);
		//collection1.add(1L);
		collection1.add("abc");
		String element = collection1.get(0);
		//int i = (Integer)collection1.get(1);
		System.out.println(element);
		
		//<Integer>的可以传入,<String>类型的也可以传
		printCollection(collection1);
		
	}
	
	//泛型在反射技术中的应用
	private static void Test3() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		//Constructor<String> constructor = String.class.getConstructor(StringBuffer.class);
		Constructor<String> constructor = String.class.getConstructor(StringBuffer.class);
		String str2 = constructor.newInstance(new StringBuffer("abc"));
		System.out.println(str2.charAt(2));
		//Vector<Integer> vectorList[] = new Vector[10];
	}
	
	//把字符串放入ArrayList<Integer>集合中去
	private static void Test4() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
		ArrayList<Integer> list = new ArrayList<Integer>();
		list.add(1);
		//list.add("abc");
		//由于泛型只作用于编译阶段,所以可以用反射区获取add方法
		list.getClass().getMethod("add", Object.class).invoke(list, "abc");
		System.out.println(list.get(1));
		
		//<Integer>的可以传入
		printCollection(list);
	}
	
	//打印出任意类型的集合元素
	private static void printCollection(Collection<?> collection){
		System.out.println("集合中的元素个数:"+collection.size());
		for(Object obj:collection){
			System.out.println(obj);
		}
	}
}


自定义泛型:
package cn.hmm.Generic;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Test2 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		//MapDemo();
		Integer[] a = new Integer[]{1,2,3,4};
		//char[] b = new char[]{'a','b','c','d'};//基本数据类型不能转换
		swap(a,1,2);
		for(Integer c:a){
			System.out.println(c);
			
		}
		
		Object obj = "abc";
		String str = AutoConvert(obj);
	}
	
	//泛型一些应用
	private static void MapDemo() {
		HashMap<String,Integer> maps = new HashMap<String,Integer>();
		maps.put("ccz", 26);
		maps.put("hmm", 24);
		maps.put("hhc", 24);
		
		Set<Map.Entry<String, Integer>> entrySet = maps.entrySet();
		for(Map.Entry<String, Integer> entry : entrySet){
			System.out.println(entry.getKey() + ":"+entry.getValue());
			
		}
		
		
	}
		private static <T> void copy1(Collection<T> c,T[] a){
			
		}
		
private static <T> void copy2(T[]  c,T[] a){
			
		}
	//打印出任意类型的集合元素
		private static <T> void printCollection(Collection<T> collection,T obj2){
			System.out.println("集合中的元素个数:"+collection.size());
			for(Object obj:collection){
				System.out.println(obj);
			}
			collection.add(obj2);
		}
		
	private static <T> void fillArray(T a[],T obj){
		for(int i =0;i<a.length;i++){
			a[i] = obj;
		}
	}
	//
	private static <T> T AutoConvert(Object obj){
		return (T)obj;
	}
	//交换任意类型的数组的两个元素,泛型的类型不能是基本类型
	private static <T> void swap(T[] a,int i,int j){
		T temp = a[i];
		a[i] = a[j];
		a[j] = temp;
	}
}




泛型<E>定义在类上面,表示类里面的所有的非静态方法上的E都是一样的,如果静态的也要用泛型,需要自己去定义.

:

package cn.hmm.Generic;

import java.util.Set;

//dao Data access Object  -->crud(Create,Read,update,delete)
public class GenericDao<E> {

	public void add(E x){
		
	}
	
	public E findById(int id){
		return null;
	}
	public void delete(E obj){
		
	}
	public void delete(int id){
		
	}
	public void update(E obj){
		
	}
	public E findByname(String name){
		return null;
	}
	//如果是静态方法,要自己在方法上定义
	public static <T> void update2(T obj){
		
	}
	public Set<E> findByConditions(String s){
		return null;
	}
}



利用反射拿到集合中泛型的实际类型:
package cn.hmm.Generic;

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



public class GenericTest {


	public static void main(String[] args) throws NoSuchMethodException, SecurityException {
		// TODO 自动生成的方法存根
		//根据下面这个是没办法得到集合的类型的,但是可以根据方法,把集合当成参数传入
		//Vector<Date> v = new Vector<Date>();
		Method applyMethod = GenericTest.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){
		
	}
}


总结:
1:将运行时期的问题ClassCastException问题转换成了编译失败,体现在编译时期,程序员就可以解决问题。
2:避免了强制转换的麻烦。

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

详细请查看:www.itheima.com

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值