泛型generic

郝峰
2023-12-01

为什么要使用泛型

作用一

思考一个简单的问题:在java中一切都是对象,因此例如ArrayList也是一个对象。但由于必须支持ArrayList用来存各种各样的数据,因此ArrayList中存储的对象必然只能是基类Object。在这种情况下,编译时无法对其中存储的对象做任何检查,但运行时可能由于其中的对象不是认为的那种而出现运行时错误,因此这是不安全的。而泛型出现后:

new ArrayList<Dog>(); 这样的声明就表明该collection只能用于存储Dog,或Dog的子类对象,存储其他对象则导致编译错误,从而避免了运行时错误。

最简单的理解泛型的方式是,想一想类型转换的问题:

List<Apple> box = ...;
Apple apple = box.get(0);

这段代码是自解释的:box是一个对list对象的引用;list中的对象是apple。从list中取出对象时,不再需要类型转换。

因此,当我们使用泛型(其实就是在代码中加入了类型变量)时,就等于告诉编译器:请帮我做类型检查,并在必要的时候自动进行类型转换。

作用二

泛型的另外一个作用是,当我们在写方法时,传入的参数可以是任何primitive types或object,例如:public int testMethod(int x, int y){...}  。此时如果也需要支持输入参数是String的话,就要实现另外一个method,这样非常麻烦。但如果用public int testMethod(Object x, Object y){...} 这样也不好,因为完全不能检查输入参数是否合法。泛型可以解决这个问题:

public class GenericTest {

    public static void main(String[] args) {

        Box<String> name = new Box<String>("corn");
        //如果不用泛型,而是在实现构造函数时使用输入参数为Object,以此来支持多种类型的输入参数, 
        //这样实例化出来的name中什么都可以存。但用泛型后,实例化出来的name只能用于String。因此即 
        //增加了灵活性,又没有损害安全性。
        Box<Integer> age = new Box<Integer>(712);
        Box<Number> number = new Box<Number>(314);

        getData(name);
        getData(age);
        getData(number);
    }

    public static void getData(Box<?> data) {
        System.out.println("data :" + data.getData());
    }

}

class Box<T> { //这是一个泛型类。在java中我们可以定义泛型类,泛型方法和泛型接口。

    private T data; //这是一个泛型类型。

    public Box() {

    }

    public Box(T data) { //可以看到在声明构造函数的时候,使用泛型T就可以了。在使用构造函数时
                         //Box<String>('test'); 或Box<Integer>(5);都是合法的。

        setData(data);
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

}

参考下面这个帖子:

http://stackoverflow.com/questions/2001755/using-int-as-a-type-parameter-for-java-util-dictionary

所以我们得知道java中常见的primitive types以及对应的object。其实在java中,就像类的名字总是首字母大写的规律一样,如果类型的名字是小写的,那么就是primitive types:

int -- Integer

char -- Character

boolean -- Boolean

而String原本就不是primitive type,而是一个对象,S是大写的。

 

 类似资料: