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对象,表示声明此类型的类或接口。