【发布时间】:2020-06-15 21:44:53
【问题描述】:
众所周知,匿名内部类和捕获 lambda 在某些情况下都隐式添加了私有字段。对于实例字段匿名类,它是对外部类实例的引用,而对于本地和静态匿名实例则没有。但是本地实例 lambda 不同:它有一个捕获变量类型的字段。如果最终它们以相同的方式使用,为什么它们会有这种差异?为什么不能在本地匿名类的精确副本中构建本地 lambda?
UPD:
一个小样本
类来测试匿名类的字段
public class AnonymousExample {
private Runnable instanceRunnable = new Runnable() {
@Override
public void run() { }
};
private static Runnable staticRunnable = new Runnable() {
@Override
public void run() { }
};
public static void main(String[] args) throws IllegalAccessException {
Runnable localRunnable = new Runnable() {
@Override
public void run() { }
};
System.out.println("-- local anonymous class --");
print(localRunnable.getClass(), localRunnable);
System.out.println("\n-- instance anonymous class --");
AnonymousExample em = new AnonymousExample();
print(em.instanceRunnable.getClass(), em.instanceRunnable);
System.out.println("\n-- static member anonymous class --");
print(staticRunnable.getClass(), staticRunnable);
}
public static void print(Class<?> c, Object instance) throws IllegalAccessException {
System.out.println("- constructors -");
for (Constructor<?> constructor : c.getDeclaredConstructors()) {
System.out.println(constructor.toGenericString());
}
System.out.println("- fields -");
for (Field field : c.getDeclaredFields()) {
System.out.printf(" field name: %s,%n field type: %s,%n field value: %s%n",
field.getName(),
field.getType(),
field.get(instance));
}
}
}
输出:
-- local anonymous class --
- constructors -
field.AnonymousExample$3()
- fields -
-- instance anonymous class --
- constructors -
field.AnonymousExample$1(field.AnonymousExample)
- fields -
field name: this$0,
field type: class field.AnonymousExample,
field value: field.AnonymousExample@79fc0f2f
-- static member anonymous class --
- constructors -
field.AnonymousExample$2()
- fields -
类来测试捕获 lambda 的字段
public class CapturingLambdaExample {
private int x = 10;
private static int y = 20;
private Runnable instanceRunnable = () -> { System.out.println(x);};
private static Runnable staticRunnable = () -> { System.out.println(y);};
public static void main(String[] args) throws IllegalAccessException {
int z = 20;//effectively final
Runnable localRunnable = () -> { System.out.println(z);};
System.out.println("-- local capturing lambda --");
print(localRunnable.getClass());
System.out.println("\n-- instance capturing lambda --");
CapturingLambdaExample em = new CapturingLambdaExample();
print(em.instanceRunnable.getClass());
System.out.println("\n-- static capturing lambda --");
print(staticRunnable.getClass());
}
public static void print(Class<?> c) throws IllegalAccessException {
System.out.println("- constructors -");
for (Constructor<?> constructor : c.getDeclaredConstructors()) {
System.out.println(constructor.toGenericString());
}
System.out.println("- fields -");
for (Field field : c.getDeclaredFields()) {
System.out.printf(" field name: %s,%n field type: %s,%n ",
field.getName(),
field.getType());
}
}
}
输出:
-- local capturing lambda --
- constructors -
private field.CapturingLambdaExample$$Lambda$15/0x0000000840065440(int)
- fields -
field name: arg$1,
field type: int,
-- instance capturing lambda --
- constructors -
private field.CapturingLambdaExample$$Lambda$25/0x0000000840068840(field.CapturingLambdaExample)
- fields -
field name: arg$1,
field type: class field.CapturingLambdaExample,
-- static capturing lambda --
- constructors -
private field.CapturingLambdaExample$$Lambda$14/0x0000000840064c40()
- fields -
【问题讨论】:
-
好吧,匿名类是实际的类,而 lambdas 的设计是为了在需要/需要时无需使用类即可实现它们。
-
你确定本地匿名类不捕获
this? -
您能否分享您所描述的场景示例和这些领域的证据?
-
@Savior 嗨,我添加了描述问题的简短示例
-
@markspace,我知道。它使这个问题变得更加有趣。为什么本地捕获 lambda 需要隐式添加字段而匿名类不需要?