Java基础之泛型






泛型 Generic:

在JDK1.5版本之后出现的新特性。是一个类型安全机制,用于解决安全问题。

泛型的好处:

1.将运行时期出现的问题ClassCastException转移到了编译时期,方便程序员解决问题,减少运行时期的问题,提高了安全性。

2.避免了强制转换的麻烦。

泛型的格式:通过<>来定义要操作的引用数据类型。

泛型通常在集合框架中很常见,在使用java提供的对象时,只要见到<>就要定义泛型。<>是用来接收类型的。

当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。

泛型代码示例:

<pre name="code" class="html">import java.util.*;
class Generic
{ 
	public static void main(String[] args)
	{
		TreeSet<String> ts = new TreeSet<String>(new Comparator<String>()
		{
			public int compare(String s1,String s2)
			{
				int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
				if(num==0)
					return s1.compareTo(s2);
				return num;
			}
		});

		ts.add("haha");
		ts.add("nihao");
		ts.add("zhu");
		ts.add("aliluya");
		ts.add("aliluyaamen");
		ts.add("xuxiaoyu");
		ts.add("lisi");
		
		for(Iterator<String> it=ts.iterator(); it.hasNext();  )
		{
			System.out.println(it.next());
		}
	}
}




泛型类:当类中要操作的引用数据类型不确定的时候,就定义泛型来完成扩展。泛型类定义的泛型在整个类中有效,如果被方法使用,泛型类对象明确要操作的具体类型后,要操作的类型就固定了。代码演示:

class Tool<HH> //定义的泛型类。
{
	private HH h;

	public void setObject(HH h)
	{
		this.h = h;
	}
	public HH getObject()
	{
		return h;
	}
}



泛型方法:为了让不同方法可以操作不同类型,且类型还不确定,可以将泛型定义在方法上,<>要写在返回值类型的前面。示例: public <T> void show(T t){ }

泛型方法代码演示:

class GenericMethod
{
	public <T> void show(T t) //泛型方法。
	{
		System.out.println("show:"+t);
	}
	public <E> void print(E e) //泛型方法。
	{
		System.out.println("print:"+e);
	}
	public <W> void function(W w) //泛型方法。
	{
		System.out.println("function:"+w);
	}
}

静态方法泛型:静态方法不可以访问类上定义的泛型,因为静态是优先于对象的存在。如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。示例:public static <W> void method(W w){ }

静态方法泛型代码示例:

class Generic
{
	public static <T> void show(T t) //静态方法泛型。
	{
		System.out.println("show:"+t);
	}
	public static <E> void print(E e) //静态方法泛型。
	{
		System.out.println("print:"+e);
	}
	public static <W> void function(W w) //静态方法泛型。
	{
		System.out.println("function:"+w);
	}
}

泛型的限定:?是通配符或占位符。? extends E:上限,可以接收E类型或E的子类型。? super E:下限,可以接收E类型或者E的父类型。代码示例:

import java.util.*;
class  GenericDemo2
{
	public static void main(String[] args) 
	{
		ArrayList<Person> al = new ArrayList<Person>();
		al.add(new Person("abcd01"));
		al.add(new Person("abcd03"));
		al.add(new Person("abcd04"));

		ArrayList<Student> al1 = new ArrayList<Student>();
		al1.add(new Student("bcd01"));
		al1.add(new Student("bcd03"));
		al1.add(new Student("bcd04"));

		printColl(al1);
	}

	public static void printColl(ArrayList<? extends Person> al)
	{
		for(Iterator<? extends Person> it = al.iterator(); it.hasNext(); )
		{
			System.out.println(it.next().getName());
		}
	}
}

class Person
{
	private String name;

	Person(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
}
class Student extends Person
{
	Student(String name)
	{
		super(name);
	}
}
/*
泛型的限定用于泛型的扩展。super E:下限,可以接收E类型或者E的父类型。
*/
import java.util.*;
class  GenericDemo3
{
	public static void main(String[] args) 
	{
		TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());

		ts.add(new Student("xyz06"));
		ts.add(new Student("xyz08"));
		ts.add(new Student("xyz03"));
		ts.add(new Student("xyz04"));
		for(Iterator<Student> it = ts.iterator(); it.hasNext(); )
		{
			System.out.println(it.next().getName());
		}


		TreeSet<Worker> st = new TreeSet<Worker>(new MyComparator());

		st.add(new Worker("wxyz 05"));
		st.add(new Worker("wxyz 08"));
		st.add(new Worker("wxyz 02"));
		st.add(new Worker("wxyz 04"));
		for(Iterator<Worker> it = st.iterator(); it.hasNext(); )
		{
			System.out.println(it.next().getName());
		}
	}
}
class MyComparator implements Comparator<Person>
{
	public int compare(Person p1,Person p2)
	{
		return p2.getName().compareTo(p1.getName());
	}
}

class Person
{
	private String name;

	Person(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
}
class Worker extends Person
{
	Worker(String name)
	{
		super(name);
	}
}
class Student extends Person 
{
	Student(String name)
	{
		super(name);
	}
}



泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说

明的集合时会去除掉"类型"信息,使程序运行效率不受影响。对于参数化的泛型类型,getClass()方法的返回值和原始类

型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器就可以往某个泛型集合中加入其他类型的

数据。例如:用泛型得到集合,再调用其add方法即可。

用反射的方式往实际类型参数是Integer的ArrayList集合中存入一个字符串元素,代码示例:

import java.util.*;
class Demo
{
	public static void main(String[] args) throws Exception
	{
		ArrayList<Integer> al = new ArrayList<Integer>();
		
		//通过反射跳过编译器往某个泛型集合中加入其他类型的元素。
		al.getClass().getMethod("add",Object.class).invoke(al,"amen");

		System.out.println(al.get(0));
	}
}

泛型中的术语:

ArrayList<E> 称为泛型类型。 

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

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

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

ArrayList 称为原始类型。<>读成typeof 。

参数化类型可以引用一个原始类型的对象,编译器会报出警告。例如:ArrayList<Integer> al = new ArrayList()。

原始类型也可以引用一个参数化类型的对象,编译器会报出警告。例如:ArrayList al = new ArrayList<Integer>()。

参数化类型不考虑类型参数的继承关系。

使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调 

用与参数化有关的方法。 只有引用类型才能作为泛型方法的实际参数-->> <int>不可以<T>。

泛型的限定:

?是通配符或占位符。? extends E:上限,可以接收E类型或E的子类型。

示例:Vector<? extends Number> v = new Vector<Integer>();

? super E:下限,可以接收E类型或者E的父类型。示例: Vector<? super Integer> v = new Vector<Number>();

通过反射的方式获得泛型的实际类型参数:

import java.util.*;
import java.lang.reflect.*;
class Test
{ 
	public static void main(String[] args) throws Exception
	{	
		Method applyMethod = Test.class.getMethod("apply",HashSet.class);
		
		//得到该方法上的泛型的实际类型参数数组。
		Type[] types = applyMethod.getGenericParameterTypes();

		//知道只有一个元素,就是参数化类型
		ParameterizedType pType = (ParameterizedType)types[0];
		
		//获取方法参数的原始类型。
		System.out.println(pType.getRawType());

		//获取方法参数化类型上的实际类型参数。
		System.out.println(pType.getActualTypeArguments()[0]);

	}
	public static void apply(HashSet<String> hs)
	{
	}
}

ParameterizedType 表示参数化类型,如 Collection<String>。  

getActualTypeArguments():返回表示此类型实际类型参数的Type对象的数组。

getRawType():返回Type对象,表示声明此类型的类或接口。