java 泛型

来源:互联网 发布:xperia touch 知乎 编辑:程序博客网 时间:2024/06/13 07:29

泛型是jdk1.5以后出来的新特性,Java中的泛型是个假泛型,仅仅只是在编译期做了语法检查。基本上,不管在list<>里面写什么类型,编译通过后运行时全部都是object。泛型做了语法、类型编译期间的检查,避免了在运行时出现ClassCastException。


先了解几个问题?

(1)List<Object>和原始类型List之间的区别:

在编译时编译器不会对原始类型进行类型安全检查,却会对带参数的类型进行检查,通过使用Object作为类型,可以告知编译器该方法可以接受任何类型的对象,比如String或Integer。你可以把任何带参数的类型传递给原始类型List,但却不能把List<String>传递给接受List<Object>的方法,因为会产生变异错误


(2)Java中List<?>和List<Object>之间的区别

List<?> 是一个未知类型的List,而List<Object>其实是任意类型的List。你可以把List<String>, List<Integer>赋值给List<?>,却不能把List<String>赋值给List<Object>。 

  

(3)Java的泛型是如何工作的 ? 什么是类型擦除 ?

泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如List<String>在运行时仅用一个List来表示。这样做的目的,是确保能和Java 5之前的版本开发二进制类库进行兼容。你无法在运行时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型。


(4)可以把List<String>传递给一个接受List<Object>参数的方法吗?

不可以,因为List<Object>可以存储任何类型的对象包括String, Integer等等,而List<String>却只能用来存储Strings。


(5)什么是泛型中的限定通配符和非限定通配符?

限定通配符对类型进行了限制。有两种限定通配符,一种是<? extends T>它通过确保类型必须是T的子类来设定类型的上界,可以接受任何继承自T的类型的List;例如List<? extends Number>可以接受List<Integer>或List<Float>。另一种是<? super T>它通过确保类型必须是T的父类来设定类型的下界。泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。另一方面<?>表示了非限定通配符,因为<?>可以用任意类型来替代


*泛型的使用:java泛型的两种用法:List<T>是泛型方法,List<?>是限制通配符

1>泛型类

先看一个没有泛型的情况下的容器类如何定义:

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


    public Text (String k, String v) {
        key = k;
        value = v;
    }
}

Text类保存了一对key-value键值对,但是类型是定死的,也就说如果我想要创建一个键值对是String-Integer类型的,当前这个Text是做不到的,必须再自定义。那么这明显重用性就非常低。

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

泛化:

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


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

在编译期,是无法知道KV具体是什么类型,只有在运行时才会真正根据类型来构造和分配内存。可以看一下现在Text类对于不同类型的支持情况:

public class Main {
    public static void main(String[] args) {
        Text<String, String> c1 = new Text<String, String>("name", "findingsea");
        Text<String, Integer> c2 = new Text<String, Integer>("age", 24);
        Text<Double, Double> c3 = new Text<Double, Double>(1.1, 2.2);
    }
}


2>泛型接口

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

列1:

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

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());
    }
}

列2:

interface Show<T,U>{  
    void show(T t,U u);  
}  
  
class ShowTest implements Show<String,Date>{  
    @Override  
    public void show(String str,Date date) {  
        System.out.println(str);  
        System.out.println(date);  
    }  
}  

public static void main(String[] args) throws ClassNotFoundException {  
        ShowTest showTest=new ShowTest();  
        showTest.show("Hello",new Date());  
    }  


3>泛型方法

如果使用泛型方法可以取代将整个类泛化,那么应该优先采用泛型方法。下面来看一个简单的泛型方法的定义:

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);
    }
}

0 0
原创粉丝点击