【问题标题】:Obtaining the array Class of a component type获取组件类型的数组Class
【发布时间】:2011-06-21 12:42:41
【问题描述】:

如果我有Class 的实例,有没有办法为其数组类型获取Class 实例?我本质上要求的是方法 getArrayType 的等价物,它是 getComponentType() 方法的逆方法,这样:

array.getClass().getComponentType().getArrayType() == array.getClass()

【问题讨论】:

    标签: java arrays


    【解决方案1】:

    想到的一件事是:

    java.lang.reflect.Array.newInstance(componentType, 0).getClass();
    

    但它会创建一个不必要的实例。

    顺便说一句,这似乎有效:

    Class clazz = Class.forName("[L" + componentType.getName() + ";");
    

    这里是测试。它打印true:

    Integer[] ar = new Integer[1];
    Class componentType = ar.getClass().getComponentType();
    Class clazz = Class.forName("[L" + componentType.getName() + ";");
    
    System.out.println(clazz == ar.getClass());
    

    The documentation of Class#getName()严格定义了数组类名的格式:

    如果该类对象表示一类数组,则名称的内部形式由元素类型的名称组成,前面有一个或多个“[”字符,表示数组嵌套的深度。

    Class.forName(..) 方法不能直接用于基元 - 对于它们,您必须在名称 (int) 和数组简写 - (I) 之间创建一个映射

    【讨论】:

    • 第一个版本(使用Array.newInstance(...).getClass()确实适用于原语。
    • 这非常有用,谢谢。出于我的目的,我不需要处理原语,因此任何一种方法都可以使用。
    • Class.forName() 方法还为字符串连接生成临时对象(例如 new StringBuilder().append("[L").append(componentType.getName()).append(";" ).toString())。所以我想第一种方法会产生更少的分配,即使是不必要的。
    • 你可能想使用 Class.forName("[L" + componentType.getName() + ";", false, componentType.getClassLoader())
    • 正如@ɲeuroburɳ所说,Class.forName(…) 方法会创建更多的临时对象,成本更高(类名越长,成本越高),此外,零大小的数组有更好的机会被优化器删除,但更糟糕的是,Class.forName(…) 方法不仅不适用于原始类型,也不适用于数组类型(当尝试获取多维数组类型时)。而Array.newInstance(componentType, 0).getClass() 只是完成这项工作。对于 Java 12+,您可以只使用 componentType.arrayType();猜猜它在引擎盖下做了什么……
    【解决方案2】:

    其实由于ClassLoader,原语和多维数组,答案稍微复杂一点:

    public static Class<?> getArrayClass(Class<?> componentType) throws ClassNotFoundException{
        ClassLoader classLoader = componentType.getClassLoader();
        String name;
        if(componentType.isArray()){
            // just add a leading "["
            name = "["+componentType.getName();
        }else if(componentType == boolean.class){
            name = "[Z";
        }else if(componentType == byte.class){
            name = "[B";
        }else if(componentType == char.class){
            name = "[C";
        }else if(componentType == double.class){
            name = "[D";
        }else if(componentType == float.class){
            name = "[F";
        }else if(componentType == int.class){
            name = "[I";
        }else if(componentType == long.class){
            name = "[J";
        }else if(componentType == short.class){
            name = "[S";
        }else{
            // must be an object non-array class
            name = "[L"+componentType.getName()+";";
        }
        return classLoader != null ? classLoader.loadClass(name) : Class.forName(name);
    }
    

    【讨论】:

    • 在最后一行中,您还可以使用带有类加载器参数的 forName 方法(这也适用于null,从而避免区分大小写)。
    • 最后一行对我没有用,但是使用类加载器作为参数的 forName 对我有用。
    【解决方案3】:

    您可以执行以下操作

    array.getClass() == 
        Array.newInstance(array.getClass().getComponentType(), 0).getClass()
    

    通常不需要知道类型,只需要创建数组即可。

    【讨论】:

      【解决方案4】:

      另一种可能的重构是使用泛型超类并将两个类对象传递给构造函数。

      protected AbstractMetaProperty(Class<T> valueClass, Class<T[]> valueArrayClass) {
        this.valueClass = valueClass;
        this.valueArrayClass = valueArrayClass;
      }
      

      然后在子类中:

      public IntegerClass() {
        super(Integer.class, Integer[].class);
      }
      

      然后在抽象类中可以使用valueClass.cast(x)valueArrayClass.isInstance(x)

      【讨论】:

        【解决方案5】:

        Java 12 引入arrayType()

        String.class.arrayType() == String[].class;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-11
          • 2014-01-28
          相关资源
          最近更新 更多