Java 为什么匿名类可以访问封闭类的非最终类成员
我们知道在匿名类中只能访问最终的局部变量,这里有一个很好的理由: 但是,我发现匿名类仍然可以访问非final变量,如果该变量是封闭类的成员字段: 我很困惑。我们确保在匿名类中只能访问最终的局部变量,因为我们不希望该变量在匿名类和局部函数之间不同步。如果我们试图访问匿名类中的非最终封闭类成员,同样的原因也应该适用于这种情况Java 为什么匿名类可以访问封闭类的非最终类成员,java,closures,final,anonymous-class,Java,Closures,Final,Anonymous Class,我们知道在匿名类中只能访问最终的局部变量,这里有一个很好的理由: 但是,我发现匿名类仍然可以访问非final变量,如果该变量是封闭类的成员字段: 我很困惑。我们确保在匿名类中只能访问最终的局部变量,因为我们不希望该变量在匿名类和局部函数之间不同步。如果我们试图访问匿名类中的非最终封闭类成员,同样的原因也应该适用于这种情况 为什么这不是一个问题 对于局部变量,匿名类实例接收的是该变量的副本。因此,在匿名类中使用局部变量之前,必须将其设置为final,以便以后不会更改其值 对于封闭类的成员字段,没有
为什么这不是一个问题 对于局部变量,匿名类实例接收的是该变量的副本。因此,在匿名类中使用局部变量之前,必须将其设置为
final
,以便以后不会更改其值
对于封闭类的成员字段,没有副本。相反,匿名类获取对封闭类的引用,从而访问外部类的任何/所有成员字段和方法。因此,即使字段的值更改,更改也会反映在匿名类中,因为它是相同的引用
我很困惑。我们确保只有一个最终的局部变量可以
在匿名类中访问,因为我们不希望该变量
匿名类和本地函数之间应不同步。这个
如果我们试图访问非最终版本,同样的理由也应适用于该案例
在匿名类中封闭类成员
如你所见,情况并非如此。复制只针对局部变量,而不针对封闭类的成员字段原因当然是,匿名类拥有对封闭类的隐式引用,通过该引用,它可以访问外部类的任何/所有成员字段和方法。
引用以下链接:
成员变量在封闭对象的生存期内存在,因此内部类实例可以引用它。但是,局部变量仅在方法调用期间存在,编译器处理方式不同,因为它的隐式副本是作为内部类的成员生成的。在不声明局部变量final的情况下,可以对其进行更改,从而导致细微的错误,因为内部类仍然引用该变量的原始值
参考文献:
1。非静态/内部类有一个对封闭实例的引用。因此,它们可以隐式引用实例变量和方法 如果它是一个参数,即使是封闭类也不知道它的任何信息,因为它只能从定义此变量的方法访问 正如Y.S.已经指出的:
对于局部变量,该变量的副本是匿名类实例获得的
反过来说,匿名实例之外的局部变量,比如
x
,只要方法调用有效,它就会存在。其对象引用存储在调用堆栈上;x==包含对象引用的堆栈上的地址。匿名实例中的x
是一个副本,因为它的生存期不同、更长甚至更短
由于现在有两个变量,因此决定不允许分配到x
(执行起来很奇怪),并要求变量为“有效的最终变量”
访问外部成员是因为匿名实例属于内部类,也包含外部类。请参阅此引用。考虑以下示例
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();
}
}
这不会在Java1.8或更高版本中产生任何错误。但在以前的版本中,这会生成一个错误,要求您将内部类中访问的局部变量显式声明为final。
因为编译器所做的是保留内部类访问的局部变量的副本,这样即使方法/块结束且局部变量超出范围,副本也会存在。它要求我们声明它final,因为如果在声明本地内部类或匿名类之后,变量在程序中动态更改其值,编译器创建的副本不会更改为其新值,并且可能会由于不生成预期输出而在内部类中引起问题。因此,它建议我们明确宣布它为最终版本
但在Java1.8中,它不会生成错误,因为编译器隐式地声明访问的局部变量为final。
在Java文档中说明如下
匿名类无法访问其封闭类中的局部变量
未声明为最终或有效最终的范围
让我解释一下“有效最终”是什么意思。考虑下面修改的版本
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;
}
}
即使在Java1.8中,这也会产生错误。这是因为aLocal是在程序中动态分配的。这意味着编译器不能有效地将变量视为最终变量。据我所知,编译器将未动态更改的变量声明为final。这称为变量is有效地为final
因此,建议您显式声明本地内部类或匿名类访问的本地变量,以避免任何错误 您可以通过解释为什么可以使用引用而不是副本来改进您的答案。虽然这可能很明显。“相反,匿名类实例获得了对实际成员字段的引用。”不。它们只对封闭实例进行了引用。
如果我们尝试访问匿名类中的非最终实例变量,同样的原因也可能适用于这种情况。
。。。。那叫acces