Generic array creation java类型系统

首先说一下问题:

java中不能创建泛型数组,否则会报错

应该如何使用?


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class JavaGenericTypeTest {

    /**
     * 先说结论
     * java泛型不支持数组
     * 泛型和数组不能同时使用,
     * 但是因为我们要创建数组,所以只能舍弃泛型,使用原生类型 raw type
     * 即不带尖括号的类型
     * 或者是使用原生类型创建数组后,强转为泛型类型
     *
     * 原因:
     * 数组支持协变,而协变是错误的
     */
    public void createGenericType(){
        //创建list
        List<Integer> list = new ArrayList<>();

        //创建泛型 list数组 (去掉泛型,使具体化reifiable)第一种使用方式
        //是因为原生类ArrayList不是泛型,所以它是"物化(reifiable)"的。
        List<Integer>[] ll = new ArrayList[10];
        ll[0] = new ArrayList<Integer>();

        //方式2,类型更确定,也是创建泛型数组
        List<Integer>[] ll2 = (List<Integer>[]) new ArrayList[10];
        ll2[0] = new ArrayList<Integer>();

        //创建泛型数组,会提示"泛型数组创建 generic array create"
//        List<Integer> l = new ArrayList<Integer>[10];

    }


    //======================================================

    public class A{

    }

    public void test(){
        //强制转型原生类型数组
        List<String>[] stringList = (ArrayList<String>[])new ArrayList[10];
        Object[] objArray = new Object[10];
        objArray = stringList;
        objArray[0] = new ArrayList<Integer>(); // OPPS!!! 编译器不报错
    }

    public void test2(){
        //强制转型原生类型数组,此处Object为原生类型
        List<A>[] aList = (ArrayList<A>[])new ArrayList[10];
        Object[] objArray = new Object[10];
        objArray = aList;
        objArray[0] = new ArrayList<Integer>(); // OPPS!!! 编译器不报错
    }

    public void test3(){
        String[] a = new String[2];
        Object[] b = a;
        a[0] = "hi";
        b[1] = Integer.valueOf(42);
    }

//    public void test4(){
//        String[] a = (String[]) new Object[2];
//        a[0] = "hi";
//        a[1] = Integer.valueOf(42);
//    }

//    public void test5(){
//        List<String> a = new ArrayList<>();
//        List<Object> b = a;
//        a[0] = "hi";
//        b[1] = Integer.valueOf(42);
//    }

//    public void test6(){
//        List<? extends String> d = new ArrayList<>();
//        d.add("d");
//    }

    public void test7(){
        //报错
        /**
         * ?通配符,不可以用于创建实例
         */
//        List<?> l = new ArrayList<?>();
        //不报错
        List<Object> l2 = new ArrayList<Object>();

    }

    public void test8(List<?> l){
        //只可以读,不可以添加,null除外
        //报错
//        l.add(1);
        l.add(null);
    }

    public void test9(List<Object> l){

    }

    public void test10(){
        test8(new ArrayList<String>());
    }

    public void test11(){
        //报错
//        test9(new ArrayList<String>());
    }


    /**
     * super和extends 都限定了,只能存放A以及A的子类
     * 只不过,
     * (extends)一个不允许放(null除外),取出来为A以及Object(A的基类)
     * (super)一个允许放入A以及A的子类,但是取出来必须是A的基类
     * 允许放的,只能放A以及A的子类
     * 关键点为,只可以为一种未知类型,如果该未知类型为A,那么只能是A,如果是B,只能是B,而不可以又是A,又是B,而Object就可以
     */
    public void test12(){
        List<? super A> l = new ArrayList<>();
        l.add(new A());

        List<? extends A> l2 = new ArrayList<>();
        l2.add(null);
        //报错
//        l2.add(new A());
    }

    public void test13(){
        Object[] strList = new String[10];
        Object[] intList = new Integer[10];
        intList[0] = 1;
        Object[] x = strList; // 系统默认x为String类型数组
        x[0] = intList[0]; // 运行报错
    }

}

下面说一下原因:

根本原因为:java的数组协变是错误的(个人感觉),

比如:

Object[] o = new Object[5];

Integer[] i = new Integer[5];

o[0] = new A();

相当于Object[]类中有个方法add,该方法参数为Object,返回值为[Object,

即 [Object add(Object o)

Integer[]也类似

而程序语言的类型系统中,最主要是子类型关系,比如如何判断一个函数是另一个函数的子函数,我们都知道一个函数的参数为A,那么传入该函数的实例,必须是<:A(其中<:为类型系统中的子类型,详情看见https://en.wikipedia.org/w/index.php?search=subtype+system&title=Special%3ASearch&go=Go&ns0=1)

那根据子类型的公式

C <: A 并且 B <: D  那么 A ---> B <: C ---> D (其中--->代表函数,或者是一个操作,输入为A,输出为B)

如果c为a的子类型,并且b为d的子类型,那么函数a->b为c->d的子类型。

应用到数组中也是一样

Integer为Object的子类,[Integer为[Object的子类,

要想Object[]数组add方法为Integer[]的add方法的父类,那么应该为:

[Object  add(Integer)  为 [Integer add(Object)方法的父类。

例如:

声音 f(狗)

汪汪 g(动物)

那么函数f为g的父类

参考资料:

逆变与协变

创建泛型数组报错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值