简体   繁体   English

为什么匿名类可以访问封闭类的非final类成员

[英]Why can an anonymous class access non-final class member of the enclosing class

We know that only final local variables can be accessed in an anonymous class, and there is a good reason here: Why are only final variables accessible in anonymous class? 我们知道只能在匿名类中访问最终的局部变量,这里有一个很好的理由: 为什么在匿名类中只能访问最终变量? .

However, I found that an anonymous class can still access a non-final variable if the variable is an member field of the enclosing class: How can I access enclosing class instance variables from inside the anonymous class? 但是,我发现如果变量是封闭类的成员字段,匿名类仍然可以访问非final变量: 如何从匿名类内部访问封闭的类实例变量?

I am confused. 我很迷惑。 We ensure that only a final local variable can be accessed in anonymous class because we don't want that the variable should be out-of-sync between anonymous class and local function. 我们确保只能在匿名类中访问最终的局部变量,因为我们不希望变量在匿名类和本地函数之间不同步。 The same reason should apply to the case if we try to access a non-final enclosing class member in anonymous class. 如果我们尝试访问匿名类中的非最终封闭类成员,则同样的理由应该适用于该情况。

Why would it not be a concern? 为什么不关注呢?

In the case of a local variable, a copy of the variable is what the anonymous class instance receives. 在局部变量的情况下,变量的副本是匿名类实例接收的内容。 For this reason, the local variable has to be made final before it can be used within the anonymous class, so that its value may not change later. 因此,必须先将局部变量设置为final然后才能在匿名类中使用它,以便以后可能不会更改其值。

In the case of a member field of the enclosing class, there is no copy . 对于封闭类的成员字段, 没有副本 Rather, the anonymous class gets a reference to the enclosing class, and thereby it accesses any/all member fields and methods of the outer class. 相反,匿名类获取对封闭类的引用,从而访问外部类的任何/所有成员字段和方法。 So even if the value of the field changes, the change is reflected in the anonymous class as well, because it is the same reference. 因此,即使字段的值发生更改,更改也会反映在匿名类中,因为它是相同的引用。

I am confused. 我很迷惑。 We ensure that only a final local variable can be accessed in anonymous class because we don't want that the variable should be out-of-sync between anonymous class and local function. 我们确保只能在匿名类中访问最终的局部变量,因为我们不希望变量在匿名类和本地函数之间不同步。 The same reason should apply to the case if we try to access a non-final enclosing class member in anonymous class. 如果我们尝试访问匿名类中的非最终封闭类成员,则同样的理由应该适用于该情况。

As you see, that is not the case. 如你所见,情况并非如此。 The copying happens only for local variables, not for member fields of the enclosing class. 复制仅针对局部变量,而不针对封闭类的成员字段。 The reason is, of course, that an anonymous class holds an implicit reference to the enclosing class, and through that reference it can access any/all member fields & methods of the outer class. 当然,原因是匿名类包含对封闭类的隐式引用,并且通过该引用它可以访问外部类的任何/所有成员字段和方法。

To quote the link below: 引用以下链接:

A member variable exists during the lifetime of the enclosing object, so it can be referenced by the inner class instance. 成员变量在封闭对象的生命周期中存在,因此可以由内部类实例引用。 A local variable, however, exists only during the method invocation, and is handled differently by the compiler, in that an implicit copy of it is generated as the member of the inner class. 但是,局部变量仅在方法调用期间存在,并且由编译器以不同方式处理,因为它的隐式副本是作为内部类的成员生成的。 Without declaring the local variable final, one could change it, leading to subtle errors due to the inner class still referring to the original value of that variable. 在不声明局部变量fi​​nal的情况下,可以更改它,导致细微的错误,因为内部类仍然引用该变量的原始值。

References: 参考文献:

1. Why a non-final “local” variable cannot be used inside an inner class, and instead a non-final field of the enclosing class can? 1. 为什么非最终的“局部”变量不能在内部类中使用,而是封闭类的非最终字段可以? .

Non-Static / Inner classes have a reference to there enclosing instance. 非静态/内部类具有对封闭实例的引用。 So they can implicitly refer to instance variables and methods. 所以他们可以隐含地引用实例变量和方法。

If it is a Parameter, even the enclosing class doesn't know anything about it, because it is only accessible from the Method which has defined this variable. 如果它是一个参数,即使是封闭类也不知道它的任何内容,因为它只能从定义了这个变量的方法中访问。

Like YS already pointed out: 像YS已经指出:

In the case of a local variable, a copy of the variable is what the anonymous class instance gets 在局部变量的情况下,变量的副本是匿名类实例获得的

It is more the other way around, a local variable, say x outside the anonymous instance lives as long as the method call. 反过来说,一个局部变量,即匿名实例外的x ,只要方法调用就存在。 Its object reference is stored on the call stack; 它的对象引用存储在调用堆栈中; x == address on the stack containing an object reference. x ==包含对象引用的堆栈上的地址。 The x inside the the anonymous instance is a copy as its lifetime is different, longer or even shorter. 匿名实例中的x是一个副本,因为它的生命周期不同,更长甚至更短。

As there now are two variables, it was decided not to allow assignment to x (weirdly to implement) and require the variable to be "effectively final." 由于现在有两个变量,因此决定不允许赋值给x (奇怪地实现)并要求变量“有效地最终”。

Access to an outer member, is because the anonymous instance is of an inner class also containing an OuterClass.this reference. 访问外部成员是因为匿名实例是一个内部类,也包含一个OuterClass.this引用。

Consider following example 考虑以下示例

class InnerSuper{
    void mInner(){}
}
class Outer{
    int aOuter=10;
    InnerSuper mOuter(){
        int aLocal=3999;
        class Inner extends InnerSuper{
            int aInner=20;
            void mInner(){
                System.out.println("a Inner : "+aInner);
                System.out.println("a local : "+aLocal);
            }
        }
        Inner iob=new Inner(); 
        return iob;
    }
}

class Demo{
    public static void main(String args[]){
        Outer ob=new Outer();
        InnerSuper iob=ob.mOuter(); 
        iob.mInner();
    }
}

This won't generate any error in Java 1.8 or above. 这不会在Java 1.8或更高版本中生成任何错误。 But in previous version this generates an error asking you to explicitly declare the local variable accessed within the inner class as final . 但在以前的版本中,这会产生一个错误,要求您显式声明在内部类中访问的本地变量为final Because what the compiler does is it will keep a copy of the local variable accessed by the inner class so that the copy will exist even if the method/block ends and the local variable goes out of scope. 因为编译器所做的是它将保留内部类访问的局部变量的副本,以便即使方法/块结束且局部变量超出范围,副本也将存在。 It asks us to declare it final because if the variable changes its value dynamically later in the program after the local inner class or anonymous class is declared, the copy created by the compiler won't change to its new value and could cause problems within the inner class by not producing expected output. 它要求我们声明它是final的,因为如果变量在声明本地内部类匿名类之后在程序中稍后动态更改其值,则编译器创建的副本将不会更改为其新值并且可能导致问题内部阶级,不产生预期的产出。 Hence it advises us to declare it explicitly final. 因此,它建议我们明确宣布最终结果。

But in Java 1.8 it won't generate an error as the compiler declares the accessed local variable implicitly final. 但是在Java 1.8中,它不会产生错误,因为编译器会隐式地声明最终访问的本地变量。 It is stated as follows in Java Docs 它在Java Docs中声明如下

An anonymous class cannot access local variables in its enclosing scope that are not declared as final or effectively final. 匿名类无法访问其封闭范围中未声明为final或者有效final的局部变量。

Let me explain what is meant by effectively final. 让我解释一下有效最终的含义。 Consider the following altered version of the above program 请考虑以上程序的以下更改版本

class Outer{
    int aOuter=10;
    InnerSuper mOuter(){
        int aLocal=3999;
        class Inner extends InnerSuper{
            int aInner=20;
            void mInner(){
                System.out.println("a Inner : "+aInner);
                System.out.println("a local : "+aLocal);
            }
        }
        aLocal=4000;
        Inner iob=new Inner(); 
        return iob;
    }
}

Even in Java 1.8 this will produce an error. 即使在Java 1.8中,这也会产生错误。 This is because aLocal is dynamically assigned within the program. 这是因为aLocal是在程序中动态分配的。 This means the variable cannot be considered effectively final by the compiler. 这意味着编译器无法有效地认为变量是最终的。 As from what I've understood the compiler declares the variables that aren't changed dynamically as final. 从我所理解的情况来看,编译器将未动态更改的变量声明为final。 This is called the variable is effectively final . 这被称为变量实际上是最终的

Hence it is recommended that you declare the local variables accessed by a Local inner class or an anonymous class explicitly final to avoid any errors. 因此,建议您将Local内部类或匿名类访问的局部变量声明为final,以避免任何错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么非最终的“局部”变量不能在内部类中使用,而是封闭类的非最终字段可以? - Why a non-final “local” variable cannot be used inside an inner class, and instead a non-final field of the enclosing class can? 引用Java中匿名内部类中的封闭类的非final字段 - Referring to non-final fields of an enclosing class inside an anonymous inner class in Java 为什么匿名内部类可以访问和更新外部类的非final实例变量? - Why the non-final instance variable of the outer class can be accessed and updated in the anonymous inner class? 具有非最终成员的不可变Java类 - Immutable Java class with non-final member 本地类可以访问java 8中的非final变量 - Local class can access non-final variable in java 8 匿名类中的非最终非本地变量 - non-final non-local variable inside anonymous class 非最终类可以完全不可变吗? - Can a non-final class be fully immutable? 如果非最终字段的值可以更改,那么如何在非匿名字段类中使用非最终字段? - How can non-final fields be used in a anonymous class class if their value can change? 在匿名内部类中访问非最终值 - Accessing non-final values inside anonymous inner class 是否可以将非最终变量传递给匿名类的方法? - Is it possible to pass a non-final variable to a method of an anonymous class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM