Java泛型:泛型类、泛型接口和泛型方法

根据《Java编程思想 (第4版)》中的描述,泛型出现的动机在于:java

有许多缘由促成了泛型的出现,而最引人注意的一个缘由,就是为了建立容器类编程

泛型类

容器类应该算得上最具重用性的类库之一。先来看一个没有泛型的状况下的容器类如何定义:dom

public class Container {
    private String key;
    private String value;

    public Container(String k, String v) {
        key = k;
        value = v;
    }
    
    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

Container类保存了一对key-value键值对,可是类型是定死的,也就说若是我想要建立一个键值对是String-Integer类型的,当前这个Container是作不到的,必须再自定义。那么这明显重用性就很是低。ide

固然,我能够用Object来代替String,而且在Java SE5以前,咱们也只能这么作,因为Object是全部类型的基类,因此能够直接转型。可是这样灵活性仍是不够,由于仍是指定类型了,只不过此次指定的类型层级更高而已,有没有可能不指定类型?有没有可能在运行时才知道具体的类型是什么?ui

因此,就出现了泛型。this

public class Container<K, V> {
    private K key;
    private V value;

    public Container(K k, V v) {
        key = k;
        value = v;
    }

    public K getKey() {
        return key;
    }

    public void setKey(K key) {
        this.key = key;
    }

    public V getValue() {
        return value;
    }

    public void setValue(V value) {
        this.value = value;
    }
}

在编译期,是没法知道KV具体是什么类型,只有在运行时才会真正根据类型来构造和分配内存。能够看一下如今Container类对于不一样类型的支持状况:code

public class Main {

    public static void main(String[] args) {
        Container<String, String> c1 = new Container<String, String>("name", "findingsea");
        Container<String, Integer> c2 = new Container<String, Integer>("age", 24);
        Container<Double, Double> c3 = new Container<Double, Double>(1.1, 2.2);
        System.out.println(c1.getKey() + " : " + c1.getValue());
        System.out.println(c2.getKey() + " : " + c2.getValue());
        System.out.println(c3.getKey() + " : " + c3.getValue());
    }
}

输出:接口

name : findingsea
age : 24
1.1 : 2.2

泛型接口

在泛型接口中,生成器是一个很好的理解,看以下的生成器接口定义:内存

public interface Generator<T> {
    public T next();
}

而后定义一个生成器类来实现这个接口:get

public class FruitGenerator implements Generator<String> {

    private String[] fruits = new String[]{"Apple", "Banana", "Pear"};

    @Override
    public String next() {
        Random rand = new Random();
        return fruits[rand.nextInt(3)];
    }
}

调用:

public class Main {

    public static void main(String[] args) {
        FruitGenerator generator = new FruitGenerator();
        System.out.println(generator.next());
        System.out.println(generator.next());
        System.out.println(generator.next());
        System.out.println(generator.next());
    }
}

输出:

Banana
Banana
Pear
Banana

泛型方法

一个基本的原则是:不管什么时候,只要你能作到,你就应该尽可能使用泛型方法。也就是说,若是使用泛型方法能够取代将整个类泛化,那么应该有限采用泛型方法。下面来看一个简单的泛型方法的定义:

public class Main {

    public static <T> void out(T t) {
        System.out.println(t);
    }

    public static void main(String[] args) {
        out("findingsea");
        out(123);
        out(11.11);
        out(true);
    }
}

能够看到方法的参数完全泛化了,这个过程涉及到编译器的类型推导和自动打包,也就说原来须要咱们本身对类型进行的判断和处理,如今编译器帮咱们作了。这样在定义方法的时候没必要考虑之后到底须要处理哪些类型的参数,大大增长了编程的灵活性。

再看一个泛型方法和可变参数的例子:

public class Main {

    public static <T> void out(T... args) {
        for (T t : args) {
            System.out.println(t);
        }
    }

    public static void main(String[] args) {
        out("findingsea", 123, 11.11, true);
    }
}

输出和前一段代码相同,能够看到泛型能够和可变参数很是完美的结合。

以上,泛型的第一部分的结束。

相关文章
相关标签/搜索