java泛型详解

来源:互联网 发布:软件ui设计 编辑:程序博客网 时间:2024/05/11 09:36

1.首先要明白泛型的概念

所谓泛型,就是允许在定义接口、类、方法时使用类型形参,这个类型形参将在声明变量、创建对象、调用方法时动态的指定,即传入实际的类型参数。Java 5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型参数;例如List<String>,ArrayList<String>等等。

下面是Java5改写后List接口、Iterator接口、Map的代码片段

当我们使用List类型时,为E形参传入String类型实参,则产生了一个新的类型:List<String>类型,我们可以把List<String>想象成形参E被替换成实参String的特殊List子接口。


//List<String>等同于如下接口

public interface ListString extends List{

//原来的形参E全部变成实参String

void  add(String x);

Iterator<String> iterator();

...

}

2.泛型的应用场所

需要指出的是,我们可以为任何类、接口增加泛型声明,并不是只有集合类才可以使用泛型声明,尽管集合类是泛型的重要使用场所。

看一例子:


//定义类时使用了泛型声明
public class Apple<T> {

//使用T类型形参定义实例变量
private T info;

public Apple(T info) {
this.info = info;
}


public void setInfo(T info) {
this.info = info;
}


public T getInfo() {
return info;
}

public static void main(String[] args) {

//传入String类型实参,构造器参数只能是String类型
Apple<String> ap1=new Apple<String>("苹果");
System.out.println(ap1.getInfo());

//传入Double类型实参,构造器参数只能是Double类型 和double类型
Apple<Double> ap2=new Apple<Double>(3.14);
System.out.println(ap2.getInfo());
}

}

输出结果:

-------------------------------

苹果
3.14

-------------------------------

这里需要说明3点:

第一,尽管一个类使用了泛型声明,其构造方法的声明不会因此而改变,但在调用时必须为类型形参指定实际的类型(看代码红色标记处的区别)

第二,类型形参T并没有什么实际意义,它可以是任何合法标识符,只是T和E比较常用,为了提高代码的可读性,也就延续了下来成为了一种编码习惯。在使用Apple<T>类时,类型形参T可以被任何实际存在的类型代替。

第三,java7中增加了菱形语法,允许省略<>中的类型实参。比如:Apple<String> ap1=new Apple<>("苹果");


由此,我们也可以看出使用泛型最大的好处——带来了极大的灵活性。


3.从泛型类派生子类

标准的格式应该是这样的:public class A extends Apple<String>{...}

而不是public class A extends Apple<T>{...},你应该明白在调用一个方法时,要把在定义该方法时用到的形参变成实参传入方法而完成调用。比如定义时:int  add(int x, int y){...};在调用时应该是add(1,2);这里道理也是一样的,只有在定义泛型接口、类、方法时用的是形参T,在使用时也要换成实际类型,当然继承也是一种使用方式。

4.并不存在泛型类

前面提到可以把ArrayList<String>类当成ArrayList的子类,但实际上系统并没有为ArrayList<String>生成新的class文件,而且也不会把ArrayList<String>当成新类来处理;

如果在代码中加入System.out.println(ap1.getClass()==ap2.getClass());,它的执行结果并不是false而是true。也验证了这一点。

因此在静态方法、静态初始化块或者静态变量的声明和初始化中不允许使用类型形参。

1 0
原创粉丝点击