黑马程序员---Java基础加强---JDK1.5新特性:泛型

-------  android培训 java培训 、期待与您交流! ----------

JDK1.5新特性:泛型
一、泛型
1.定义
泛型用<>来表示,来限定某一个容器装入的元素类型。<>里面填入的是元素的类型

2.集合运用泛型之后的叫法

ArrayList<E> :泛型类型,E称为类型变量或者类型参数,E只能是引用数据类型,不能是基本数类型。

ArrayList<Integer> :参数化的类型,Integer称为类型参数的实例

ArrayList:原始类型

<>:typeof  ArrayList<Integer> 读作,ArrayList typeof Integer


3.泛型的<>内的类型限定的几种情况

(1)<>里面直接填入元素的类型,

如,ArrayList<Integer> al=new ArrayList<Integer>();
注意:
第一:参数化类型可以引用一个原始类型的对象,

Collection<String> collection =new ArrayList();

第二:原始类型可以引用一个参数化类型

Collection collection =new ArrayList<String>();

第三:参数化类型不考虑类型参数的继承关系:

Vector<String> v=new Vector<Object>();
Vector<Object> v=new Vector<String>();//都是不对的。

第四:创建数组实例时,数组的元素不能使用参数化的类型

Vector<String> vector[]=new Vector<String>[10];//这是错的。

(2)<>里面写入?,即写入通配符。它的特点

第一:? 通配符为一个具体的类型,但是可以指向任意的类型。

如:Collection<?> collection=new ArrayList<Integer>();

第二:当一个容器使用的是通配符时,则此容器就不能使用与类型有关的方法

如,add(E e)方法。因为对于此容器,并不知道它具体的指向什么参数化类型的容器所以并不能使用与类型有关的方法。

ArrayList<?> al2=new ArrayList<Integer>();

al2.add(1);//不对。

第三:只能是Vector<?> v=new Vector<String>();而不能是Vector<String> v=new Vector<?>();

即通配符只能在左边不能在右边,即?通配符定义的变量主要用来用作引用。

总结:使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用来用作引用,可以调用与参数无关的

方法,不能调用与参数有关的方法。

练习:定义一个方法,用于打印任意参数化类型的集合中的所有数据。

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
public class FanXingTest 
{
	public static void main(String[] args)throws Exception 
	{
		// TODO Auto-generated method stub
		ArrayList<Integer> al=new ArrayList<Integer>();
		al.add(1);
		al.add(2);
		al.add(3);
		printElem(al);
	}
	//通过通配符来达到“打印任意参数化类型集合元素”的要求。
	public static void printElem(Collection<?> collection)throws Exception
	{
		System.out.println("未添加元素之前的size:"+collection.size());
		//不能直接调用collection.add("abc");可以利用反射来跳过编译器来添加元素
		Method method = collection.getClass().getMethod("add", Object.class);
		method.invoke(collection, "abc");
		//可以调用与参数无关的方法
		System.out.println("添加元素之后的size:"+collection.size());
		//打印此集合中的元素
		for (Object object : collection) 
		{
			System.out.println(object);	
		}	
	}
}

(3)c、向上限定

格式:<? extends Number>表示只能为Number的子类或者Number

Vector<? extends Number> v=new Vector<Integer>();//对的

Vector<? extends Number> v=new Vector<String>();//错的

Number的子类为7中基本类型的引用类型表示形式,即为Byte,Short,Integer,Boolean,Float,Double,Character。

(4)向下限定

格式:<? super Integer>表示只能为Integer或者Integer的子类

Vector<? super Integer> v=new Vector<Number>();//对的

Vector<? super Integer> v=new Vector<Byte();//错的,因为Integer和Byte是平级的。

4.泛型原理

泛型只是给编译器看的,即当编译之后,class文件中不再有相关的泛型信息。所以对于给定的参数化类型的集合,

要想对它里面添加别的类型的元素,只需要跳过编译器即可。

例子:

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
public class FanXingTest2 
{
	public static void main(String[] args) throws Exception
	{
		// TODO Auto-generated method stub
		Collection<Integer> collection=new ArrayList<Integer>();
		//通过反射获得方法add
		Method method=collection.getClass().getMethod("add",Object.class);
		//利用反射得到的方法来想集合中添加元素
		method.invoke(collection,"abc");
		method.invoke(collection,1);
		System.out.println(collection.size());
		for (Object integer : collection) 
		{
			System.out.println(integer);	
		}
	}
}

5.自定义泛型方法

(1)即在方法的返回值类型前面上加上<>来自定义泛型方法
例子:
public static <T> void swap(T[] arr,int x,int y)
{
   T temp=arr[x];
   arr[x]=arr[y];
   arr[y]=temp;
}
(2)泛型可以定义在类上、方法上、构造方法上、静态方法上、和异常上。
定义在异常上:
private static <T extends Exception> void sayHello()throws T
{
  try
  {
  }
catch (Exception e)//注意此处捕捉异常必须是具体的异常,不能写成
//T e
  {
     throw(T)e;
  }
}

(3)泛型也可以写成<V extends 接口1&接口2>即表示V是实现了接口1和接口2的类或者它的子类。
(4)在泛型中可以同时有多个类型参数,在定义他们时在尖括号中用逗号隔开
public static <K,V> V getValue(K key)
{
     return map.get(key);
}
(5)类型参数的类型推断
a、若:static <E> void swap(E[] a,int x,int y),只有一处用到,则类型直接由调用此方法
时传递的参数类型或者返回值来决定泛型参数的类型。
b、static <T> T add(T a,T b),即多处用到了类型变量,则若几处都对应同一种类型,则就确定为
此类型。
c、若,static <T> void fill(T[] A,T v).多处用到且这几处对应不同的类型,且无使用返回值,这时
取多个参数中的最大交集类型,eg fill(new Integer[3],3.5f),则对应Number。
d、若,static <T> T add(T a,T b);多处用到,且这几处对应不同的类型,且有返回值类型,则优先考虑
返回值类型。int x=add(3,3.5f);若返回值不对再试别的。最后应该确定为Number类型。

6.自定义泛型类

(1)作用:将泛型定义在类上,来达到类中的所有方法操作同一个类型。

例子:

class FanXing<T>
{
	public T get(int x)
	{
		return null;
	}
	public void delete(T x)
	{
	}
	public void update(T obj)
	{
	}
	//即对于静态方法不能使用类上的泛型变量。
	public static <E> E getclass(E e)
	{
		return null;
	}
}


(2)练习:

1> 获取HashMap集合中的元素

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapFan 
{
	public static void main(String[] args) 
	{
		// TODO Auto-generated method stub
		HashMap<String,Integer> hm=new HashMap<String,Integer>();
		hm.put("a",1);
		hm.put("b",1);
		hm.put("c",1);
		hm.put("d",1);
		Set<Map.Entry<String,Integer>> set=hm.entrySet();
		for (Map.Entry<String,Integer> me : set) 
		{
			System.out.println(me.getKey()+":::"+me.getValue());	
		}
	}
}

2> 通过反射获得泛型的实际类型参数

分析:要想得到泛型的实际类型参数,即得到Vector<Integer> v=new Vector<Integer>()中的Integer则通过v是没办法得到此实际类型参数的,因为当编译器一编译完,泛型就没了。

那么可以通过,public static void applyFan(Vector<Integer> v1){}这样的方法来得到此方法里面的参数的类型

,从而得到实际类型参数。

代码:

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Vector;
public class ReflectFan 
{
	public static void main(String[] args)throws Exception 
	{
		// TODO Auto-generated method stub
		//通过反射得到此方法
		Method method =ReflectFan.class.getMethod("applyVector", Vector.class);
		//通过调用方法getGenericParameterTypes()来得到此方法的泛型参数类型。
		Type[] types=method.getGenericParameterTypes();
		//得到此参数的参数类型。
		ParameterizedType pType=(ParameterizedType)types[0];
		System.out.println(pType.getRawType());//class java.util.Vector
		//下面结果为class java.lang.Integer
		System.out.println(pType.getActualTypeArguments()[0]);	
	}
	public static void applyVector(Vector<Integer> v)
	{
		
	}
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值