为什么方法引用可以使用非最终变量? [英] Why can method reference use non-final variables?

查看:27
本文介绍了为什么方法引用可以使用非最终变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对内部类和 lambda 表达式有些困惑,我试着问一个 问题 ,但随后又出现了另一个疑问,与评论前一个问题相比,发布另一个问题可能更好.

I had some confusion about inner classes and lambda expression, and I tried to ask a question about that, but then another doubt arose, and It's probable better posting another question than commenting the previous one.

直截了当:我知道(谢谢乔恩) 这样的东西不会编译

Straight to the point: I know (thank you Jon) that something like this won't compile

public class Main {
    public static void main(String[] args) {
        One one = new One();

        F f = new F(){      //1
            public void foo(){one.bar();}   //compilation error
        };

        one = new One();
    }
}

class One { void bar() {} }
interface F { void foo(); }

由于 Java 管理闭包的方式,因为 one 不是 [有效地] final 等等.

due to how Java manages closures, because one is not [effectively] final and so on.

但是,为什么允许这样做?

But then, how come is this allowed?

public class Main {
    public static void main(String[] args) {
        One one = new One();

        F f = one::bar; //2

        one = new One();
    }
}

class One { void bar() {} }
interface F { void foo(); }

//2 不等于 //1 吗?在第二种情况下,我不是面临使用过时变量"的风险吗?

Is not //2 equivalent to //1? Am I not, in the second case, facing the risks of "working with an out-of-date variable"?

我的意思是,在后一种情况下,在 one = new One(); 执行后 f 仍然有一个过时的 one(即引用旧对象).这不是我们试图避免的那种歧义吗?

I mean, in the latter case, after one = new One(); is executed f still have an out of date copy of one (i.e. references the old object). Isn't this the kind of ambiguity we're trying to avoid?

推荐答案

方法引用不是 lambda 表达式,尽管它们可以以相同的方式使用.我认为这就是造成混乱的原因.下面是 Java 工作原理的简化,这不是它真正的工作原理,但已经足够接近了.

A method reference is not a lambda expression, although they can be used in the same way. I think that is what is causing the confusion. Below is a simplification of how Java works, it is not how it really works, but it is close enough.

假设我们有一个 lambda 表达式:

Say we have a lambda expression:

Runnable f = () -> one.bar();

这相当于实现了Runnable的匿名类:

This is the equivalent of an anonymous class that implements Runnable:

Runnable f = new Runnable() {
    public void run() {
       one.bar();
    }
}

这里的规则与匿名类(或方法本地类)相同.这意味着 one 需要有效地结束它才能工作.

Here the same rules apply as for an anonymous class (or method local class). This means that one needs to effectively final for it to work.

另一方面是方法句柄:

Runnable f = one::bar;

更像是:

Runnable f = new MethodHandle(one, one.getClass().getMethod("bar"));

MethodHandle 为:

public class MethodHandle implements Runnable {
    private final Object object;
    private final Method method;

    public MethodHandle(Object object, java.lang.reflect.Method method) {
        this.object = Object;
        this.method = method;
    }

    @Override
    public void run() {
        method.invoke(object);
    }
}

在这种情况下,分配给 one 的对象被分配为创建的方法句柄的一部分,因此 one 本身不需要有效地最终工作.

In this case, the object assigned to one is assigned as part of the method handle created, so one itself doesn't need to be effectively final for this to work.

这篇关于为什么方法引用可以使用非最终变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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