Java中的泛型问题小记

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/xiao_dondon/article/details/77944038
看一段简单的代码:
public class Main {
    public static void main(String[] args) {
        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        //list1 = list2; compile error
        Object obj = list2;
    }

我们可以看到,虽然String是Object的祖先类,但是list2却不能赋值给list1(编译出错).

原因是,假如可以赋值的话,我们往list2中添加Object对象会破坏list1的类型安全;另外,当从list2中取出元素时无法判断元素类型。

当然,Object是所有类的祖先类,所有list2可以赋给obj。



为了解决上面的问题,Java中提供了通配符(?)

我们再看一段代码:

List<? extends String> list3 = new ArrayList<>();
        List<? extends Object> list4 = new ArrayList<>();
        //list3 = list4;compile error
        list4 = list3;
        obj = list3;
        obj = list4;
使用通配符之后,list3就可以赋给list4了。


继续看代码:

String s = list3.get(0);
        String ss = list4.get(0);//   1    compile error
        obj = list4.get(0);
使用通配符之后,集合中的元素都会以通配的类型存储,取出来的元素也将是通配的类型,所以代码1出编译出错


通配符的好处:

fon(list1);
        fon(list2);
        fon(list3);
        fon(list4);
    public static void fon(List<?> list){
    	
    }


还有一点,Java中的泛型不能作为方法重载的依据。

public static void fon(List<? extends String> list){
    	
    }
    public static void fon(List<? extends Object> list){
    	
    }
当一个类中出现上述2个方法时,编译出错。


我们接下来看一个类似的结构:数组

Object[] o = new Object[10];
        String[] str = new String[10];
        o = str;
        o[0] = new Object();
上述代码在编译期间是不报任何错误的。这是数组与集合泛型的区别,我们可以将子类数组对象赋给父类。

但是在运行时时会报错的: java.lang.ArrayStoreException;

虽然我们把str数组付给了o数组,但是当我们往数组中插入非String类型的元素时,会报上述异常。


继续:

o[0] = new String("123");
        Object s1 = o[0];
        System.out.println(s1);
上述代码编译运行都是正常的。也就是说,尽管我们把str数组赋给了o数组,但是我们只能插入String元素,而取出来的元素默认却是Object类型的。


原因: 

Java中集合的泛型是伪泛型,就是说,泛型只作用于编译阶段,一旦编译成.class文件之后,泛型信息就会被擦除,这时候,无论往集合中插入什么类型的元素都是没有问题的;

而数组不同,即使编译过后,在运行阶段仍然能够判断数组类型,不允许非数组类型元素的插入。


猜你喜欢

转载自blog.csdn.net/xiao_dondon/article/details/77944038