java – 最终字段和匿名类

前端之家收集整理的这篇文章主要介绍了java – 最终字段和匿名类前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
关于匿名课和最终字段的解释我仍然不满意.有很多问题试图解释明显的问题,但我没有找到所有问题的答案:-)

假设以下代码

public void method(final int i,int j) {
    final int z = 6;
    final int x = j;
    int k = 5;
    new Runnable() {
        public void run() {
            System.out.print(i);
            System.out.print(x);
            System.out.print(z);
            System.out.print(k);
        }
    };
}

>由于“不完整”的k属性,无法编译此代码.
>我理解编译器可以在编译期间用声明的值替换z属性.

当我搜索解决方案时,我和x的确切可行,我发现这个answer说:

The compiler can then just replace the use of lastPrice and price in the anonymous class with the values of the constants (at compile time,ofcourse),and you won’t have the problem with accessing non-existent variables anymore

如果它们是方法的参数,它如何适用于字段i和x?在编译期间不知道它们?这种方法适用于z.

另一方面,有关于stack issues的解释:

This allows the Java compiler to “capture” the value of the variable at run-time and store a copy as a field in the inner class. Once the outer method has terminated and its stack frame has been removed,the original variable is gone but the inner class’s private copy persists in the class’s own memory

我会理解匿名类在创建过程中以某种方式复制了所有必需的内容(字段).缺少final有明显的问题,如果匿名类声明下面的某些代码会改变值,则执行使用可能的陈旧值.

但是,这可以解决当匿名类’方法在使用的属性范围之外执行时的问题.

但这种方法即使没有最终声明也应该有效,因为它只复制所有字段.

这两种方法对我来说都是独立的.说到哪 – 它可以解决我的问题 – 我还没有找到工作最终方法领域.即使方法完成,它们也不会从堆栈中删除?对我来说似乎是胡说八道,但它会解释很多事情:-)

什么是正确的答案?

解决方法

在我看来,你在被宣告为final的变量和它是一个常量之间感到困惑.

编译器不会用常量替换对局部变量的所有引用 – 但是当构造匿名类的实例时,每个相关变量的当前值将传递给构造函数,并存储在匿名类中的变量中.这对于参数和任何其他类型的局部变量一样好.

所以这段代码

public static void method(final int x) {
    Runnable r = new Runnable() {
        @Override public void run() {
            System.out.println(x);
        }
    };
    r.run();
}

大致相当于:

public static void method(final int x) {
    Runnable r = new AnonymousRunnable(x);
    r.run();
}

private static class AnonymousRunnable implements Runnable {
    private final int x;

    AnonymousRunnable(int x) {
        this.x = x;
    }

    @Override public void run() {
        System.out.println(x);
    }
}

我已经将方法和嵌套类都设置为静态,以避免担心这是否被捕获.

当捕获局部变量时必须是最终的,以避免可能引起混淆的情况.假设情况并非如此 – 请考虑以下示例:

void method() {
    int x = 10;
    Runnable r = new Runnable() {
        @Override public void run() {
            System.out.println(x);
        }
    };
    x = 20;
    r.run(); // Should this print 10 or 20?
}

使用匿名类的当前工作方式,但只删除最终限制,它将打印10 …但开发人员可能希望它打印20.同样,您应该考虑如果在run方法修改x会发生什么. (如Joop的回答所述,在Java 8中,捕获的局部变量是“有效的最终” – 所以它们表现得好像你已经宣布它们是最终的,但没有明确地这样做.)

作为一种不同方法的示例,C#以不同的方式处理闭包(对于匿名函数),将局部变量提升为一种匿名类,以便可以对它们进行修改.这是一种更复杂的方法,但更灵活一点.您可能会发现我的article about closures in Java and C#很有用.

原文链接:https://www.f2er.com/java/126608.html

猜你在找的Java相关文章