在Java Lambda中,为什么getClass()在捕获的变量上调用 [英] In Java Lambda's why is getClass() called on a captured variable

查看:81
本文介绍了在Java Lambda中,为什么getClass()在捕获的变量上调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果你查看字节代码

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
}

参见 JDK-8073550

我们类库中的一些地方使用了使用object.getClass()检查无效的奇怪技巧。
虽然这个看起来很聪明,但实际上却让人误以为这是一个经过批准的
无效检查的做法。

A few places in our class library use the weird trick of using object.getClass() to check for nullity. While this make seem a smart move, it actually confuses people into believing this is an approved practice of null checking.

使用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()在捕获的变量上调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆