相关疑难解决方法(0)

在Java Lambda中,为什么getClass()在捕获的变量上调用

如果你看一下字节码

Consumer<String> println = System.out::println;
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

getClass()正在调用该方法System.out,结果被忽略.

这是间接空引用检查吗?

当然,如果你跑

PrintStream out = null;
Consumer<String> println = out::println;
Run Code Online (Sandbox Code Playgroud)

这会触发NullPointerException.

java lambda bytecode javac java-8

34
推荐指数
1
解决办法
964
查看次数

为什么lambda在引用最终的String字段时需要捕获封闭的实例?

这是基于这个问题.考虑这个示例,其中方法Consumer基于lambda表达式返回:

public class TestClass {
    public static void main(String[] args) {
        MyClass m = new MyClass();
        Consumer<String> fn = m.getConsumer();

        System.out.println("Just to put a breakpoint");
    }
}

class MyClass {
    final String foo = "foo";

    public Consumer<String> getConsumer() {
        return bar -> System.out.println(bar + foo);
    }
}
Run Code Online (Sandbox Code Playgroud)

我们知道,在进行函数式编程时引用lambda中的当前状态并不是一个好习惯,原因之一是lambda将捕获封闭的实例,在lambda本身超出范围之前不会进行垃圾收集.

但是,在这个与final字符串相关的特定场景中,似乎编译器可能只是在返回的lambda中包含了constant(final)字符串foo(来自常量池),而不是MyClass在调试时将所有实例括起来,如下所示(放置在的System.out.println).是否与lambdas编译为特殊invokedynamic字节码的方式有关?

在此输入图像描述

java string lambda java-8

12
推荐指数
2
解决办法
646
查看次数

最终类变量的初始化之间的区别

我只是试着设置一个变量,告诉我超级构造函数已经完成而没有浪费我的代码.所以我记得如何初始化类变量; 在超级构造函数之后但在类构造函数之前.但是如果你看一下这个例子,有一些奇怪的事情:

public class Init {

    public Init() {
        System.out.println("Init instance of " + this.getClass().getSimpleName());
        System.out.println("syso Init:");
        this.syso(false);
    }

    protected void syso(boolean childCall) {
        System.out.println("should not be printed because the method is overwitten");
    }

    public static class Child extends Init {

        private final boolean finalTrueA = true;
        private final boolean finalTrueB;
        private final boolean finalTrueC;

        private boolean nonFinalTrueA = true;
        private boolean nonFinalTrueB;
        private boolean nonFinalTrueC;

        {
            this.finalTrueB = true;
            this.nonFinalTrueB = true;
        }

        public Child() {
            super();
            this.finalTrueC = …
Run Code Online (Sandbox Code Playgroud)

java variables final initialization class

5
推荐指数
1
解决办法
180
查看次数

为什么字节码在直接访问字段时调用 Object-&gt;getClass()

我反编译了 Java(实际上是 Dalvik)字节码。在方法的开头,我直接访问实例成员的字段(即不通过 getter)。

似乎 Java 调用Object.getClass()了访问的实例成员 ( mOther),但没有在任何地方使用结果。这是某种检查吗?为什么需要这个电话?我怀疑这是因为我直接访问了一个字段(在该类中定义),但我没有看到连接。

Java代码和反编译后的字节码如下。

(请注意,最后一条指令lifeTime作为常量加载,0x0001因为 in MyOtherClass,我有lifeTime一个public final字段,并且当前是从代码初始化的。)

MyOtherClass other = mOther;
if (mAge >= other.lifeTime) { // lifeTime is initialized to 0x0001
   end();
   return;
}

.line 53
move-object/from16 v0, p0
iget-object v0, v0, Lcom/example/engine/MyClass1;->mOther:Lcom/example/engine/MyOtherClass;
move-object/from16 v16, v0

.line 54
.local v16, other:Lcom/example/engine/MyOtherClass;
move-object/from16 v0, p0

iget v0, v0, Lcom/example/engine/MyClass1;->mAge:I
move/from16 v18, v0

// Why is Object->getClass() called?
invoke-virtual/range {v16 .. v16}, …
Run Code Online (Sandbox Code Playgroud)

java android bytecode dalvik

3
推荐指数
1
解决办法
498
查看次数

标签 统计

java ×4

bytecode ×2

java-8 ×2

lambda ×2

android ×1

class ×1

dalvik ×1

final ×1

initialization ×1

javac ×1

string ×1

variables ×1