问题描述
如果你查看字节代码
Consumer<String> println = System.out::println;
Java 8更新121生成的字节代码是
the byte code generates by Java 8 update 121 is
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
DUP
INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
POP
INVOKEDYNAMIC accept(Ljava/io/PrintStream;)Ljava/util/function/Consumer; [
// handle kind 0x6 : INVOKESTATIC
java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
// arguments:
(Ljava/lang/Object;)V,
// handle kind 0x5 : INVOKEVIRTUAL
java/io/PrintStream.println(Ljava/lang/String;)V,
(Ljava/lang/String;)V
]
ASTORE 1
在 System.out
上调用 getClass()
方法,结果是忽略。
The getClass()
method is being called on the System.out
and the result is ignored.
这是间接空引用检查吗?
Is this an indirect null reference check?
当然如果你运行
PrintStream out = null;
Consumer<String> println = out::println;
这会触发NullPointerException。
This triggers a NullPointerException.
推荐答案
是的,调用 getClass()
已经成为规范的测试 null
成语,因为 getClass()
预计是一个廉价的内在操作,我想,HotSpot可能能够检测到这种模式并将操作减少到内在的 null
-check操作,如果未使用 getClass()
的结果。
Yes, calling getClass()
has become a canonical "test for null
" idiom, as getClass()
is expected to be a cheap intrinsic operation and, I suppose, HotSpot might be capable of detecting this pattern and reduce the operation to an intrinsic null
-check operation, if the result of getClass()
is not used.
另一个例子是创建一个内部类实例,其外部实例不是这个
:
Another example is creating an inner class instance with an outer instance that is not this
:
public class ImplicitNullChecks {
class Inner {}
void createInner(ImplicitNullChecks obj) {
obj.new Inner();
}
void lambda(Object o) {
Supplier<String> s=o::toString;
}
}
编译为
Compiled from "ImplicitNullChecks.java"
public class bytecodetests.ImplicitNullChecks {
public bytecodetests.ImplicitNullChecks();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
void createInner(bytecodetests.ImplicitNullChecks);
Code:
0: new #23 // class bytecodetests/ImplicitNullChecks$Inner
3: dup
4: aload_1
5: dup
6: invokevirtual #24 // Method java/lang/Object.getClass:()Ljava/lang/Class;
9: pop
10: invokespecial #25 // Method bytecodetests/ImplicitNullChecks$Inner."<init>":(Lbytecodetests/ImplicitNullChecks;)V
13: pop
14: return
void lambda(java.lang.Object);
Code:
0: aload_1
1: dup
2: invokevirtual #24 // Method java/lang/Object.getClass:()Ljava/lang/Class;
5: pop
6: invokedynamic #26, 0 // InvokeDynamic #0:get:(Ljava/lang/Object;)Ljava/util/function/Supplier;
11: astore_2
12: return
}
参见:
我们类库中的一些地方使用了使用object.getClass()检查无效的奇怪技巧。
虽然这个看起来很聪明,但实际上却让人误以为这是一个经过批准的
无效检查的做法。
使用JDK 7,我们有Objects.requireNonNull提供正确的空值检查,并正确声明
意图。
With JDK 7, we have Objects.requireNonNull that provide the proper null checking, and declare the intent properly.
这是否应该适用于编程语言内在检查,如使用 Objects.requireNonNull
那样可能有争议目的是创建一个依赖于源代码中不可见的 java.lang
包之外的类。在这种特殊情况下,只有那些查看字节代码的人才能看到这个技巧。但是已经决定用Java 9改变行为。
It might be debatable whether this should apply to programming language intrinsic checks as well, as using Objects.requireNonNull
for that purpose would create a dependency to a class outside the java.lang
package not visible in the source code. And in this specific case, the trick is only visible to those who look at the byte code. But it has been decided to change the behavior with Java 9.
这是 jdk1.9.0b160
编译的方式相同的测试类:
This is how jdk1.9.0b160
compiles the same test class:
Compiled from "ImplicitNullChecks.java"
public class bytecodetests.ImplicitNullChecks {
public bytecodetests.ImplicitNullChecks();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
void createInner(bytecodetests.ImplicitNullChecks);
Code:
0: new #26 // class bytecodetests/ImplicitNullChecks$Inner
3: dup
4: aload_1
5: dup
6: invokestatic #27 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
9: pop
10: invokespecial #28 // Method bytecodetests/ImplicitNullChecks$Inner."<init>":(Lbytecodetests/ImplicitNullChecks;)V
13: pop
14: return
void lambda(java.lang.Object);
Code:
0: aload_1
1: dup
2: invokestatic #27 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
5: pop
6: invokedynamic #29, 0 // InvokeDynamic #0:get:(Ljava/lang/Object;)Ljava/util/function/Supplier;
11: astore_2
12: return
}
这篇关于在Java Lambda中,为什么getClass()在捕获的变量上调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!