在 java 中的这个引用

我想把一个匿名类转换成一个 lambda 表达式,但是这个匿名类使用了 this关键字。

例如,我写了这个简单的观察者/观察者模式:

import java.util.ArrayList;
import java.util.Collection;


public static class Observable {
private final Collection<Observer> notifiables = new ArrayList<>();


public Observable() { }


public void addObserver(Observer notifiable) { notifiables.add(notifiable); }
public void removeObserver(Observer notifiable) { notifiables.add(notifiable); }


public void change() {
notifiables.forEach(notifiable -> notifiable.changed(this));
}
}


public interface Observer {
void changed(Observable notifier);
}

以及具有匿名类的示例代码(使用 this 关键字) :

public class Main {


public static void main(String[] args) {
Observable observable = new Observable();
observable.addObserver(new Observer() {
@Override
public void changed(Observable notifier) {
notifier.removeObserver(this);
}
});
observable.change();
}
}

但是当我把它转换成一个 lambda 表达式:

public class Main {


public static void main(String[] args) {
Observable observable = new Observable();
observable.addObserver(notifier -> { notifier.removeObserver(this); });
observable.change();
}
}

我得到这个编译错误:

Cannot use this in a static context and in a non `static` context






public class Main {
public void main(String[] args) {
method();
}


private void method() {
Observable observable = new Observable();
observable.addObserver(notifier -> {
notifier.removeObserver(this);
});
observable.change();
}
}

编译错误是:

The method removeObserver(Main.Observer) in the type Main.Observable is not applicable for the arguments (Main)

有没有办法用 this引用 lambda 对象?

30678 次浏览

不能在 lambda 表达式中引用 thisthis的语义已经更改为仅从 lambda 内引用周围类的实例。没有办法从 lambda 内部引用 lambda 表达式的 this

问题是在 main()方法中使用 this。Main 方法是静态的,没有对表示 this的对象的引用。

当您在内部类的实例中使用 this时,您正在引用内部类的实例。 Lambda 表达式不是内部类,this不引用 lambda 表达式的实例。它引用您在其中定义 lambda 表达式的类的实例。在您的例子中,它是 Main 的一个实例。但是由于您处于静态方法中,因此没有实例。

这是第二个编译错误告诉您的。将 Main 的实例移交给方法。但是您的方法签名需要观察者的实例。

更新:

返回文章页面 Java 语言规范15.27.2说:

与匿名类声明中出现的代码不同,lambda 主体中出现的名称、 this 和 super 关键字的含义以及引用声明的可访问性与周围上下文中的相同(除了 lambda 参数引入了新名称)。

在 lambda 表达式的主体中,这个(显式和隐式)的透明性——也就是说,在周围的上下文中对待它一样——允许实现更多的灵活性,并防止主体中不限定名称的含义依赖于重载解析。

实际上,lambda 表达式需要讨论它自己(或者递归地调用它自己,或者调用它的其他方法)的情况并不常见,而更常见的情况是,希望使用名称来引用封闭类中的事物,否则这些事物将被隐藏(This,toString ())。如果 lambda 表达式需要引用自己(就像通过 这个一样) ,那么应该使用方法引用或匿名内部类。

解决方案1

您的 change()方法无论如何都会抛出 ConcurrentModificationException

public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
final Observer[] a = new Observer[1];
final Observer o = er -> er.removeObserver(a[0]); // !!
a[0] = o;
observable.addObserver(o);
observable.change();
}
}
public class Observable {
private final java.util.Collection<Observer> n
= java.util.new ArrayList<>();
public void addObserver(Observer notifiable) {
n.add(notifiable);
}
public void removeObserver(Observer notifiable) {
n.add(notifiable);
}
public void change() {
for (final Observer o : n.toArray(new Observer[n.size()])) {
o.changed(this);
}
}
}
public interface Observer {
void changed(Observable notifier);
}

解决方案2

我把 changed(Observable)改成了 changed(Observable, Observer),这样观察者就可以自己处理了。

public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
final Observer o = (er, ee) -> er.removeObserver(ee); // !!
observable.addObserver(o);
observable.change();
}
}
public class Observable {
private final java.util.Collection<Observer> n
= new java.util.ArrayList<>();
public void addObserver(Observer notifiable) {
n.add(notifiable);
}
public void removeObserver(Observer notifiable) {
n.add(notifiable);
}
public void change() {
for (final Observer o : n.toArray(new Observer[n.size()])) {
o.changed(this, o);
}
}
}
public interface Observer {
void changed(Observable notifier, Observer notifiee);
}