Java 1.5发行版本中增加了泛型(Generic),在没有泛型之前,从集合中读取到的每一个对象都必须进行强制类型转换,结果就是,如果在操作过程中不小心插入了类型错误的对象,在运行时转换处理就会出错,这样的错误很难发现和纠正,但是,自从有了泛型之后,就可以告诉编译器每个集合可以接受哪些对象,如果不小心插入了错的对象,编译器此时就会暴红,这样就使得程序更加安全也更加清楚。在Java List等集合中都添加了泛型方法,聪明的你也会发现,在Java中,你即可以写List list,也可以写List String>list这样的方法;这里的list叫做原型,后者叫做泛型,会什么会出现这种情况呢,是因为在泛型出现在集合以前,程序大量的使用了List原型,为了兼容性,List方法没有被取消掉,如果你在细心一点,你也许就可以发现,不管是List,还是泛型方法,最后在jvm中出现的都是List原型,并没有泛型方法,这是为什么呢?别急,我们慢慢来,集合的泛型方法相信大家早已烂熟于心,我们先学习一个自定义的方法,代码如下:
package Generic;
import java.util.List;
/**
* Created by jiangph on 16-1-17.
*/
public class generictest {
public static void main(String[]args)
{
GenericTest11<String>name=new GenericTest11<String>("jiangph");
System.out.println("name:" + name.getData());
/***
* 泛型的类型擦除,作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
*/
GenericTest11<Integer>num=new GenericTest11<Integer>(11);
System.out.println(name.getClass()==num.getClass()); //return true
}
}
class GenericTest11<T>{
private T data;
public GenericTest11()
{
}
//定义一个带参数的构造方法
public GenericTest11(T data)
{
this.data=data;
}
//定义一个获得数据的方法
public T getData()
{
return data;
}
}
了解到泛型的好处,和自定义泛型,这里有两个东西是我们必须知道的:
一,泛型擦除
Java中的泛型只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
public class GenericTest {
//代码摘自互联网
public static void main(String[] args) {
Box<String> name = new Box<String>("corn");
Box<Integer> age = new Box<Integer>(712);
System.out.println("name class:" + name.getClass()); // com.qqyumidi.Box
System.out.println("age class:" + age.getClass()); // com.qqyumidi.Box
System.out.println(name.getClass() == age.getClass()); // true
}
}
二,泛型继承
看这段代码
public class GenericTest {
public static void main(String[] args) {
Box<Number> name = new Box<Number>(99);
Box<Integer> age = new Box<Integer>(712);
getData(name);
//The method getData(Box<Number>) in the type GenericTest is
//not applicable for the arguments (Box<Integer>)
getData(age); // 1
}
public static void getData(Box<Number> data){
System.out.println("data :" + data.getData());
}
}
代码在1这个地方报了错,这里编辑器告诉我们,Number和Integer逻辑上不能视为父子类;为什么呢?这不是跟多态作对么?,但是我们从反面过来看一下,如果程序是对的,那么getdata()这个函数,获得的是int?还是float?,所以我们必然是不能这样写的,那么我们要怎么做呢?第三个概念,通配符即“?”
package Generic;
/**
* Created by jiangph on 16-1-18.
*/
public class GenericWildCard {
public static void main(String[]args)
{
WildCard test1=new WildCard("111");
WildCard test2=new WildCard(111);
test1.getWildCardData(test1);
}
}
class WildCard<T>{
private T data;
public WildCard()
{
}
public WildCard(T data)
{
this.data=data;
}
public T getData()
{
return data;
}
public Object getWildCardData(WildCard<?>data)
{
return data.getData();
}
}
类型通配符一般是使用 ? 代替具体的类型实参。注意了,此处是类型实参,而不是类型形参。慢慢理解代码,至于通配符上限,下限;类型通配符上限通过形如Class ? extends Number>形式定义,相对应的,类型通配符下限为Class ? super Number>形式。对类型做进一步的限制,即只能是Number及其子类或是父类。