Pet*_*rey 34 java lambda bytecode javac java-8
如果你看一下字节码
Consumer<String> println = System.out::println;
Java 8更新121生成的字节代码是
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
getClass()正在调用该方法System.out,结果被忽略.
这是间接空引用检查吗?
当然,如果你跑
PrintStream out = null;
Consumer<String> println = out::println;
这会触发NullPointerException.
Hol*_*ger 31
是的,调用getClass()已经成为一种规范的"测试null"成语,因为getClass()预期它是一种廉价的内在操作,并且我认为,HotSpot可能能够检测到这种模式并将操作减少到内在的检查null操作,如果结果是getClass()未使用.
另一个例子是创建一个内部类实例,其外部实例不是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
}
另见JDK-8073550:
我们类库中的一些地方使用了使用object.getClass()检查无效的奇怪技巧.虽然这看起来很聪明,但实际上却让人们相信这是一种经过批准的空检查实践.
使用JDK 7,我们有Objects.requireNonNull,它提供正确的空值检查,并正确声明目标.
这是否应该适用于编程语言内在检查可能是有争议的,因为Objects.requireNonNull为此目的使用将创建java.lang对源代码中不可见的包外的类的依赖性.在这种特殊情况下,只有那些查看字节代码的人才能看到这个技巧.但是已经决定用Java 9改变行为.
这是jdk1.9.0b160编译相同测试类的方法:
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
}
| 归档时间: | 
 | 
| 查看次数: | 964 次 | 
| 最近记录: |