java为什么自动装箱在通过反射调用时不使用valueOf()?
据我所知,下面的代码应该打印"true"
,但当我运行它时,它会打印"false"
public class Test {
public static boolean testTrue() {
return true;
}
public static void main(String[] args) throws Exception {
Object trueResult = Test.class.getMethod("testTrue").invoke(null);
System.out.println(trueResult == Boolean.TRUE);
}
}
根据JLS §5.1.7. Boxing Conversion:
If the value
p
being boxed istrue
,false
, abyte
, or achar
in the range\u0000
to\u007f
, or anint
orshort
number between-128
and127
(inclusive), then letr1
andr2
be the results of any two boxing conversions ofp
. It is always the case thatr1 == r2
.
然而,在通过反射调用方法的情况下,装箱值总是通过new PrimitiveWrapper()
创建的
请帮助我理解这一点
# 1 楼答案
invoke将始终返回一个新的
Object
。所有返回的原语都被装箱您的问题是适当地证明术语的模糊性。i、 e.在包装过程中,它不使用Boolean.valueOf(boolean)
# 2 楼答案
一,
具体
不在您所引用的JLS部分中。你引用的部分是关于类型转换,当你有一个类型的值作为另一个类型传递时。在这里,您正在考虑将布尔值转换为布尔值
但是类型转换意味着做类似的事情:
或
反射不是应用类型转换的机制
当反射方法调用需要将布尔返回值包装到布尔对象中时,您引用的JLS部分不涉及它
这就解释了为什么这里没有违反JLS
2.
至于为什么反射没有选择与此行为保持一致:
这是因为在旧版本的Java中,反射在泛型之前就存在了。泛型是自动装箱突然变得方便的原因,而自动装箱是不复制包装原语的“公共”值似乎很明智的原因
所有这些都是在反射已经存在一段时间之后定义的,并且已经以一种特定的方式表现出来。这意味着已经存在使用反射的Java代码,并且很可能存在一些错误地依赖于现有行为的现有代码。更改现有行为会破坏现有代码,因此避免了这种情况
# 3 楼答案
如Is caching of boxed Byte objects not required by Java 13 SE spec?中所述,引用的部分已重写多次
您已经引用了使用到Java 7的版本:
注意,它忘了提到
long
在Java 8中,规范说明:
仅适用于文字
由于Java 9,规范中说
这现在指的是常量表达式,包括
long
和忘记byte
(已在第14版中重新添加)。虽然这不是坚持使用文本值,但反射方法调用不是常量表达式,因此不适用即使我们使用旧规范的措辞,也不清楚实现反射方法调用的代码是否具有装箱转换。原始代码源于装箱转换不存在的时期,因此它执行包装器对象的显式实例化,只要代码包含显式实例化,就不会有装箱转换
简而言之,反射操作返回的包装器实例的对象标识是未指定的
从实现者的角度来看,处理第一次反射调用的代码是本机代码,它比Java代码更难更改。但自JDK1.3以来,当调用次数超过阈值时,这些本机方法访问器将被生成的字节码所取代。由于重复调用是性能关键的调用,因此查看这些生成的访问器非常重要。自JDK 9以来,这些生成的访问器使用与装箱转换等效的方法
因此,运行以下经过调整的测试代码:
将在Java 9及更新版本下打印:
注意,您可以使用JVM选项
-Dsun.reflect.inflationThreshold=number
改变阈值,以及-Dsun.reflect.noInflation=true
让反射立即使用字节码# 4 楼答案
正如您在
java.lang.reflect.Method
类中所看到的,invoke
方法具有如下签名:返回一个对象作为结果
此外,
Boolean.TRUE
被定义为:它是
true
值的装箱对象通过计算代码中的
trueResult == Boolean.TRUE
,可以检查trueResult
和Boolean.TRUE
的引用是否相等。因为==
计算值相等,如果是引用,这意味着内存中有两个引用指向一个Object
吗很明显,这两个对象是不同的(它们是两个独立的对象,并在内存的不同部分实例化),因此
trueResult == Boolean.TRUE
的结果是false