lambda 捕获的引用是否保存在捕获前存在的堆栈中?

Are the references captured by a lambda kept in the stack where they where present before capture?

如果引用在方法执行时存储在堆栈中,要么通过声明,要么通过方法参数由它们先前的相邻方法堆栈传递的值。

当引用被 lambda 表达式捕获时,如果 lambda 的方法体将在未来某个时间执行并且它邻近的前一个方法堆栈(执行 lambda 方法的那个)将最可能会忽略引用对象(堆中的对象)的位置??。

在一些解释引用的教程中,暗示当一个对象有另一个对象作为字段(实例变量)时,引用直接存储在对象本身的堆中。

问题是功能接口是不可变的,所以假设有一些字段存储引用是不可能的。

现在:让我们假设下一个 class:

public class ReferenceSupplier<T> implements Supplier<T> {

    private Supplier<T> supplier;

    @SuppressWarnings("unchecked")
    public ReferenceSupplier() {
        supplier = () -> (T) new Object();
    }

    public ReferenceSupplier(Supplier<T> supplier) {
        this.supplier = supplier;
    }

    @Override
    public T get() {
        return supplier.get();
    }

    public void set(Supplier<T> value) {
        supplier = value;
    }
}

假设 set 方法在现场创建了一个匿名 Supplier,目的是获取一些参考(我知道它可以用于更有用的东西,在这种情况下 Supplier 函数有点浪费。)

private final ReferenceSupplier<Consumer<Boolean>> attacher = new ReferenceSupplier<>();

private final BiConsumer<U, BiConsumer<T, U>> attacherBuilder = (observer, acceptor) -> {
    Consumer<Boolean> attacherRef = attached -> {
        U tempObserver;
        if (attached) {
            tempObserver = observer;
            state.setValue(() -> State.active);
        } else {
            tempObserver = null;
            state.setValue(() -> State.inactive);
        }
        isAttached.set(attached);
        dispatcherBuilder.accept(tempObserver, acceptor);
    };
    attacher.set(() -> attacherRef);
};

attachRef 是对堆中消费者对象的引用。 当在attacher.set()方法中创建一个新的Supplier时,一个新的Supplier Object被存储在Heap中。 然后将匿名Supplier对象的引用(这本身就需要另一个问题了。。。)传值给ReferenceSupplierclasssetter,这意味着ReferenceSupplierclass不会被直接持有 Consumer 引用,而不是持有对堆中充当代理的不可变供应商对象的引用,而不是对堆中 Consumer 对象的引用(就像字段实例引用在可变 classes 中所做的那样) ),而是指向堆栈中引用堆中消费者对象的引用(“attachRef”)。

这是否可以防止发生这种情况的堆栈(attacherBuilder biConsumer lambda 的方法体)被弹出?或者是 lambda () -> attacherRef 的方法体,包括它在其他地方存储的捕获引用?在哪里?

如果某些东西'prevent the stack from being popped',那么方法就不能return; return 到的地方也在栈上。您可以查看堆栈,但如果您 return 那么您 return 将覆盖您存储在那里的内容,让我们回到:您无法阻止堆栈被弹出,所以使用这个反向逻辑,很明显堆栈没有被弹出。

唯一可以存在于堆栈中的是:

  • 基元
  • 引用(我过于简单化了,但可以说:64 位内存指针指向对象存储的堆内存开始。它比这更复杂,但对于堆栈上有什么,这有效)。
  • 执行指针(在您调用方法时存储;这些用于从方法 return 并且根本无法通过 java 代码访问;如果您尝试破解 class 文件获取它们,验证器将拒绝加载 class 文件)。

this means that the ReferenceSupplier class will not be holding the Consumer reference directly, instead it will be holding the reference to an immutable Supplier Object in the Heap that serves as a proxy, NOT to the Consumer object in the Heap (like field instances references would do in mutable classes), but instead to the reference in the Stack ("attachRef") that references the Consumer object in the Heap.

如果您有一个对象 on-heap 又引用其他对象,则该引用因此是该对象的一个​​字段,因此也是 on-heap。