从匿名类到Lambda表达式

3
使用下面的匿名类时,变量x可以正常调用。
interface Age { 
    int x = 21; 
    void getAge(); 
} 

class AnonymousDemo  { 
    public static void main(String[] args) { 
        Age oj1 = new Age() { 
            @Override
            public void getAge() { 
                // printing age 
                System.out.print("Age is "+x); 
            } 
        }; 
        oj1.getAge(); 
    } 
} 

但是当我使用下面的lambda表达式相同的代码时,发生了异常:
interface Age { 
    int x = 21; 
    void getAge(); 
} 

class AnonymousDemo { 
    public static void main(String[] args) { 
        Age oj1 = () -> { System.out.print("Age is "+x); };
        oj1.getAge(); 
    } 
} 

这里可能存在什么问题呢?要知道,Lambda表达式只是实现匿名类的一种简写方式。

1
这是什么异常? - matt freake
@mattfreake 错误:异常为 -> 错误:找不到符号。 - CheBoss
1
请注意,“接口体中的每个字段声明都隐式地是publicstaticfinal”,详见JLS § 9.3 - MC Emperor
1
这意味着它是一个常量,因此根据Java命名约定,应该写成UPPER_SNAKE_CASE。 - MC Emperor
2个回答

5
实际上,lambda表达式并不仅仅是“实现匿名类的缩写”。使用lambda表达式的好处在于它直接访问调用它的类(即从哪个类调用它)的实例,而匿名类则没有(它有自己的实例)。换句话说,匿名类引入了一个新的作用域,因此名称从它们的超类和接口中解析,并且可以遮蔽在词法封闭环境中出现的名称。对于lambda表达式,所有名称都是按词法解析的。 https://dev59.com/cWEh5IYBdhLWcg3wPhZT#22640484 还有

匿名类的Lambda性能表现

应用程序启动时,每个类文件都必须被加载和验证。

编译器将匿名类处理为给定类或接口的新子类型,因此将为每个类生成一个新的类文件。

Lambda在字节代码生成方面有所不同,它们更有效率,使用了JDK7带来的invokedynamic指令。

对于Lambda,该指令用于延迟将lambda表达式转换为字节码直到运行时。(该指令仅在第一次调用时被调用)

作为结果,Lambda表达式将成为静态方法(在运行时创建)。(在无状态和有状态情况下有一些小差异,它们通过生成的方法参数来解决)

https://dev59.com/cWEh5IYBdhLWcg3wPhZT#33874965

例如:
interface Supplier {
   void foo();
}

class A {

   private String name;

   public void doSome() {
      baz(() -> System.out.println(this.name));
   }

   private void baz(Supplier sup){
     sup.foo();
   }
}

或者

class A {

   private String name;

   public void doSome() {
      baz(new Supplier() {
         void foo() {
            System.out.println(A.this.name);
         }
      });
   }

   private void baz(Supplier sup){
     sup.foo();
   }
}

我建议阅读这篇文章:Java8 Lambdas vs Anonymous classes


3

x没有被识别为Age接口中的一个字段。你需要进行静态导入(import static Age.x)或明确指定x的来源:

Age oj1 = () -> System.out.print("Age is "+ Age.x);

谢谢你的回答。通过使用静态导入方法,这是否意味着我需要在主类中声明x变量为静态变量?如果是这样,我是否需要保持你提到的Age.X方法? - CheBoss
3
@CheBoss 不是的,他的意思是在你的其他导入语句中加入 import static Age.x - Omid.N

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接