第1节:泛型
1.泛型概念和泛型类应用
泛型是JavaSE1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法
泛型是类型的“类型参数”,它们也被称为参数化类型。
Java语言引入泛型的好处是安全简单。可以将运行时类型相关错误提前到编译时错误
没有泛型的情况下,通过对类型Object的引用来实现参数的“任意化”(Java中的所有类型都是Object类的子类),“任意化”带来的缺点是要做显式的强制类型转换
public class NormalGen {
private Object ob;
public NormalGen() {
// TODO Auto-generated constructor stub
}
public NormalGen(Object ob) {
// TODO Auto-generated constructor stub
this.ob = ob;
}
public Object getOb() {
return ob;
}
public void setOb(Object ob) {
this.ob = ob;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
NormalGen ng = new NormalGen(new Integer(12));
System.out.println("value="+ng.getOb());
Integer i = (Integer)ng.getOb();
System.out.println("value="+i);
String s = (String)ng.getOb();
System.out.println("value="+s);
}
}
如以上代码,虽然可以通过编译,但是在运行的时候会产生java.lang.ClassCastException异常。
以下是使用泛型的代码
泛型类的定义:
**[修饰符] class 类名 < T > **
public class NormalGen<T> {
private T ob;
public NormalGen() {
// TODO Auto-generated constructor stub
}
public NormalGen(T ob) {
// TODO Auto-generated constructor stub
this.ob = ob;
}
public T getOb() {
return ob;
}
public void setOb(T ob) {
this.ob = ob;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
NormalGen<Integer> ngi = new NormalGen<Integer>(new Integer(12));
System.out.println("value="+ngi.getOb());
NormalGen<String> ngs = new NormalGen<String>("123");
System.out.println("value="+ngs.getOb());
}
}
所以泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
注意:
在实例化泛型类的过程中需要使用应用类型
简单来说。泛型就是不确定参数类型时,使用一个名字为T(或者其他)来代替,等到泛型被创造时才确定变量类型!!
2.泛型方法
泛型方法的定义: [public] [static]< T > 返回值类型 方法名(T 参数)
public class Generic {
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer[] is = {1,2,3,4,5,6};
String[] ss = {"a","b","c"};
display(is);
System.out.println();
display(ss);
}
public static <T> void display(T[] t){
for(int i=0;i<t.length;i++)
System.out.print(t[i]+" ");
}
}
只有在返回值或者传递参数的参数类型不确定的时候我们会使用泛型方法,不过大部分在返回值和参数都一致时使用泛型会比较好
3.协变
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Fruit{}
class Apple extends Fruit{
int a;
public Apple() {}
public Apple(int a) {this.a=a;}
public int geta(){return a;}
}
class Jonathan extends Apple{}
class Orange extends Fruit{}
public class XieBian {
public static void main(String[] args) {
// TODO Auto-generated method stub
Fruit[] f1 = new Apple[10];
f1[0]=new Apple();
f1[1]=new Jonathan();
f1[2]=new Fruit();//失败
f1[3]=new Orange();//失败
}
}
在以上代码中我们创建了一个Apple数组并将其赋值给一个Fruit数组,这样的行为叫做协变。但是这样有一个缺陷那就是,在f1中只能添加Apple类或其子类对象,不能添加Fruit或者除Apple之外的子类(如Orange类)
泛型不支持协变,如以下代码会出现报错
ArrayList<Fruit> af = new ArrayList<Apple>();//报错
所以为了建立类似的“向上转型” 我们需要使用<? extends Fruit> 形式
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Fruit{}
class Apple extends Fruit{
int a;
public Apple() {}
public Apple(int a) {this.a=a;}
public int geta(){return a;}
}
class Jonathan extends Apple{}
class Orange extends Fruit{}
public class XieBian {
public static void main(String[] args) {
ArrayList<Apple> as = new ArrayList<Apple>();
as.add(new Apple(1));
List<? extends Fruit> f3 = as;
Apple a = (Apple)f3.get(0);
System.out.println(f3.contains(new Apple()));
System.out.println(f3.indexOf(new Apple()));
System.out.println(a.geta());
//f3.add(null); 运行报错
//f3.add(new Apple()); 运行报错
}
}
在本代码中,我们先创建一个ArrayList类as 将其赋给f3,实现类似于“向上转型”的功能。但采用?通配符创建泛型对象,只能获取或删除其中的信息,不可以添加新的信息。
在f3对象中,我们也只能使用 返回值和参数是Object类的方法,泛型方法不能使用!
4.限制泛型的可用类型
语法如下:class ClassName < T extends anyClass>
其中anyClass表示某一个类或者接口
T必须时anyClass类或者是其子类(或实现了anyClass接口)
public class GeneralType <T extends Number>{
private T t;
public GeneralType() {
// TODO Auto-generated constructor stub
}
public GeneralType(T t) {
// TODO Auto-generated constructor stub
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
GeneralType<Integer> g1 = new GeneralType<Integer>(12);//可以自动装包成 Integer
GeneralType<String> g2 = new GeneralType<String>(12);//出现错误
}
}
根据以上代码,Integer是Number的子类所以可以创造对象 g1,String 并不是Number的子类所以无法创造对象g2。
5.泛型类的类型通配符和泛型数组的应用
在泛型中还提供了通配符“?”,其主要出现在两个地方
1.用在泛型类创建泛型对象的时候
2.是在方法的参数中
主要作用是在创建一个泛型类时,限制这个泛型类的类型是某个类或者该类的子类或是实现该接口的类。
声明语句:<? extends T> O = null
“? extends T” 表示是T或T的子类或是实现T的接口。所以在创建泛型对象o的时候一定要满足这个条件。
所以以下语句是正确的:
GeneralType<? extends List> x = null;
x = new GeneralType<LinkedList>();
GeneralType<? extends List> y = null;
y = new GeneralType<ArrayList>();
以下语句是错误的:
GeneralType<? extends List> = new GeneralType<HashMap>();//HashMap 并不是List的子类
以下是使用?通配符实现方法showObj
import java.util.LinkedList;
public class GeneralType <T>{
private T t;
public GeneralType() {
// TODO Auto-generated constructor stub
}
public GeneralType(T t) {
// TODO Auto-generated constructor stub
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public static void showObj(GeneralType<? extends String> o){
System.out.println(o.getT());
}
public static void main(String[] args) {
// TODO Auto-generated method stub
GeneralType<String> g1 = new GeneralType<String>();
g1.setT("我是String 所以可以出现哦");
showObj(g1);
}
}
如果是使用Integer类的话就会出现错误,实现限制功能
在创建泛型类的时候也可以使用?
public static void main(String[] args) {
// TODO Auto-generated method stub
GeneralType<String> g1 = new GeneralType<String>();
GeneralType<?> g2 = null;
g2=g1;//?通配符可以被其他类型赋值;
//g1=g2 反之不可以
}