当前位置: 首页 > 知识库问答 >
问题:

为什么lambda和anonymous类有不同的隐式添加字段?

陈弘厚
2023-03-14
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 -

共有1个答案

梁丘俊材
2023-03-14

匿名类和Lambda确实有一些不同。

>

  • 匿名类可以扩展另一个类,也可以有多个方法。所以关键字,this和super需要分别用来访问它自己的成员和它的超类成员。此外,如果匿名类需要访问封闭类&封闭类的父成员,它必须使用限定的this和super关键字。示例:encursingClass.this.ToString()

    另一方面,Lambda只能用一种方法实现一个接口。它没有其他成员,所以关键字this和super可以用来引用封闭类及其父类的成员。

    public class EnclosingClass {
    
        public static void main(String[] args) {
            new EnclosingClass().start();
        }
    
        private void run(Runnable runnable) {
            runnable.run();
        }
    
        private void start() {
            System.out.println("--- Lambda ---");
            run(() -> {
                System.out.println(this.toString());
                System.out.println(super.toString()); // Use Object.toString
            });
    
            System.out.println("---Anonymous class---");
            run(new AnonymousSuperClass() {
                @Override
                public void run() {
                    super.commonMethod();
                    System.out.println(this.toString());
                    System.out.println(super.toString());
                    System.out.println(EnclosingClass.this.toString());
                    System.out.println(EnclosingClass.super.toString()); // Use Object.toString
                }
    
                @Override
                public String toString() {
                    return "Anonymous Class";
                }
            });
        }
    
        @Override
        public String toString() {
            return "Enclosing Class";
        }
    
        private static abstract class AnonymousSuperClass implements Runnable {
            protected void commonMethod() {
                System.out.println("Some common processing");
            }
    
            @Override
            public String toString() {
                return "Anonymous Super Class";
            }
        }
    }
    
    --- Lambda ---
    Enclosing Class
    EnclosingClass@eed1f14
    ---Anonymous class---
    Some common processing
    Anonymous Class
    Anonymous Super Class
    Enclosing Class
    EnclosingClass@eed1f14
    

    为什么本地捕获lambda需要隐式添加字段,而匿名类不需要?这不是真的。在您的示例中,匿名类没有使用封闭方法中的任何字段。

    对于下面的代码片段,

    private static void start() throws IllegalAccessException {
            int x = 5;
            System.out.println("---- Anonymous class ----");
            print(new Runnable() {
    
                @Override
                public void run() {
                    System.out.println(x);
                }
            }.getClass());
    
            System.out.println("---- Lambda class ----");
            Runnable r = () -> System.out.println(x);
            print(r.getClass());
        }
    

    这是输出:

    ---- Anonymous class ----
    - constructors -
    EnclosingClassV2$1(int)
    - fields -
     field name: val$x,
     field type: int,
     ---- Lambda class ----
    - constructors -
    private EnclosingClassV2$$Lambda$1/455659002(int)
    - fields -
     field name: arg$1,
     field type: int,
    
      null

  •  类似资料:
    • 问题内容: 根据JLS: 15.9.5匿名类声明编译器会自动从类实例创建表达式派生匿名类声明。 匿名类从不抽象(第8.1.1.1节)。匿名类始终是内部类(第8.1.3节);它永远不是静态的(第8.1.1节,第8.5.2节)。 匿名类始终是隐式最终的(第8.1.1.2节) 。 这似乎是一个特定的设计决定,所以它有一定的历史。 如果我选择上这样的课: 如果选择的话,为什么不允许我再次对其进行子类化?

    • 问题内容: 我正在使用jQuery SVG。我无法向对象添加或删除类。有人知道我的错误吗? SVG: 不会添加该类的jQuery: 我知道SVG和jQuery可以很好地协作,因为我 可以 定位对象并在单击对象时发出警报: 问题答案: 阅读以下两个答案。 jQuery 3修复了潜在的问题 Vanilla JS:可在现代浏览器中使用 jQuery(小于3)无法将类添加到SVG。 与SVG一起使用,因此

    • 我正在尝试与selenium webDrive同步,但某些东西无法隐含地使用等待()。 我隐含理解的方式等待(...)是代码正在等待,直到元素在最大时间内可用。 以下代码因错误而崩溃: 系统。out ist打印:-- 我也用Geckodriver试过了,结果也一样。 我也增加了等待时间,但结果相同。 使其工作的唯一方法是使用Thread.sleep()(上面评论) 编辑请注意,我没有看到任何重复与

    • 为什么我可以将Lambda用于类java。lang.Thread,但不用于MyThread? 链接以检查此示例:https://try.kotlinlang.org/#/UserProjects/tbs79qfkh50psp7r3qrdrinrmt/sfkpjq1bjvg4r6d5rmnu6mp4a8

    • 我有一个通过Interface Builder定义的布局约束视图。由于它们无法暂时停用,我决定通过拨打以下电话有选择地删除它们: 但是,之后约束仍然驻留在视图中。约束。此外,我还希望以编程方式添加约束(同样,因为我无法(取消)激活它们): 对我的方法的任何调用都会导致变量wasAdded的值NO。这也反映在用户界面上,它根本没有改变。 最后,我既不能以编程方式添加约束,也不能删除添加到情节提要的约

    • 错误: 代码: 自<代码>列表