【问题标题】:Primitive wrappers and static "TYPE" Class object原始包装器和静态“TYPE”类对象
【发布时间】:2013-11-26 03:47:04
【问题描述】:

请参阅Boolean#TYPE 了解我所指的示例。

所有包装类(Boolean、Double、Integer 等)都有一个与之关联的静态 Class 字段,称为 TYPE。这是什么意思?

具体来说,这里有一些软测试:

System.out.println(Boolean.class == Boolean.TYPE);
System.out.println(Boolean.TYPE.isInstance(Boolean.valueOf(true)));

两者都评估为假。 (附带说明,.equals 比较是不必要的,因为 Class 不会覆盖 Object 的 equals。)

Boolean.classBoolean.TYPE 都是 Class<Boolean>,因为它们是 == 可比较而没有错误的。比较具有不同声明的泛型类型的两个对象是非法的。

进一步检查,TYPE 字段是通过调用包私有本机方法 Class#getPrimitiveClass 检索到的,如下所示:

public static final Class<Boolean> TYPE = Class.getPrimitiveClass("boolean");

对方法本身的评论也不是特别有用。它说它为该类型返回 VM 的类对象,这是相当明显的,因为它是一个本地方法。

除了 Java 文档对“表示原始类型”的模糊暗示之外,我找不到任何关于此的文档。这个领域有什么用途吗?它在包装类本身中未使用。

(已编辑)

System.out.println(boolean.class == Boolean.TYPE);

是真的。

反射也是一种用途:

try {
    Constructor ctor = Boolean.class.getConstructor(Boolean.class);
} catch (Exception e) {
    System.out.println("NoSuchMethodException gets thrown");
}

try {
    Constructor ctor = Boolean.class.getConstructor(Boolean.TYPE);
    System.out.println(ctor.newInstance(true));
} catch (Exception e) {
    // (no exception thrown)
}

我发现了一些引用该内容的 SO 线程,例如 this one。我想我来自谷歌的“错误结局”,可以说是找不到任何结果。

但考虑到“原始类”(boolean.classint.class 等)的存在并不能真正解释 TYPE 字段的存在。基本上它“就在那里”?我还是不太明白。

【问题讨论】:

    标签: java class types wrapper primitive


    【解决方案1】:

    表示原始类型的类在指定或检查采用或返回原始类型的方法时很有用。例如,如果你的类有一个看起来像这样的方法

    class Test {
        static int round(float val) {...}
    }
    

    如果您希望通过反射访问此方法,则需要这样做:

    Method round = Test.class.getMethod("round", Float.TYPE);
    

    您也可以检查返回类型:

    if (round.getReturnType == Integer.TYPE) {
        System.out.println("Method 'round' returns an int.");
    }
    

    改用Float.class

    Method round = Test.class.getMethod("round", Float.class);
    

    行不通,因为那会采用不同的方法 - 这个:

    static int round(Float val) {...}
    

    【讨论】:

    • +1 所以换句话说,Float.TYPE 指的是实际的原始类,但Float.class 返回扩展Object 的包装类型。
    • @mellamokb 正确,就是这样。
    • 您知道Float.TYPEfloat.class 之间是否有任何区别?我的意思是技术上,而不仅仅是在使用中,因为它们在运行时显然是同一个对象。
    • @Radiodef 它们不可能是同一个对象 - 你的第一个例子完美地展示了它。
    • 我的意思是小写的“f”。根据评价float.class == Float.TYPE。我对此进行了一些编辑。
    【解决方案2】:

    (没有代表发表评论,所以必须回答。)

    简而言之:Float.TYPE == float.classFloat.class != float.class。考虑:

    class Test {
        void func() {
            Class clazz;
            // The two statements do the same thing.  On my system, they even compile
            //   to the same bytecode.
            clazz = Integer.TYPE;    // explicitly asking for this
            clazz = int.class;       // must yield the same object as above.
    
            // Both of these below are valid, as the `true' is autoboxed.  In 
            //   Java < 1.5, both had to be explicitly boxed
            Test.class.getMethod("test", Boolean.class).invoke(this, true);
                // calls method A
            Test.class.getMethod("test", boolean.class).invoke(this, true);
                // calls method B.  Could also use getMethod("test", Boolean.TYPE) 
        }
    
        void test(Boolean b) { System.out.println("Method A"); }
        void test(boolean b) { System.out.println("Method B"); }
    }
    

    我认为int.classInteger.TYPE 从 Java 开始就已经存在,尽管我可能错了。 Integer.TYPE 可以初始分配为Class.getPrimitiveClass("int")

    【讨论】:

    • 在进行了更多搜索后,我发现 .class 文字基本上只是 .TYPE 字段的快捷方式。它们都是使用反射 API (Java 1.1) 同时添加的,并且在编译过程中(可能)会替换文字,类似于自动装箱。
    • "...在编译期间(可能)替换了文字..." 我想编译成相同的字节码证明了这一点。
    猜你喜欢
    • 2012-07-02
    • 2021-09-11
    • 1970-01-01
    • 2018-06-26
    • 1970-01-01
    • 2011-09-05
    • 2014-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多