实例初始化VS私有成员
我有以下代码: -实例初始化VS私有成员
public class Test5 {
private int value ;
public static void main(String[] args) {
Test5 a, b;
a = new Test5();
b = new Test5(){{ value = 1 ;}};
}
}
下面的行显示了一个错误: -
b = new Test5(){{ value = 1 ;}};
非静态变量不能从静态上下文中引用。
双大括号表示第二个大括号是匿名类的实例初始值设定项。那么为什么它不能初始化私有成员变量?
线
b = new Test5(){{ value = 1 ;}};
创建扩展Test5
匿名类的一个实例。但是,因为value
是私有的,匿名类无法访问其超类的实例变量。
因为没有变量value
对Test5
的匿名子类可见,所以编译器会在下一个作用域中查找替代项。在这种情况下,下一个范围属于静态main
方法。编译器发现实例变量Test5
,并且它发出警告,因为实例变量不能从静态上下文中引用。
你这里有两种选择:
要么使匿名类的实例变量访问: 保护 int值;
或使变量访问静态
main
方法: 私人静态 int值;
我把它从你的问题的第一选择是你真正想做的事情。
@Tom:问题是而不是首先搜索静态范围。如果是这种情况,则替代方法(1)将不起作用,因为实例变量value
仍然是第一个找到的,并且仍然不能被引用。
@Ken:你的instanceMethod()
没有做,你期望它做什么!看看下面的代码:
class Test5A {
private int value;
public void instanceMethod() {
Test5A a = new Test5A() {{ value = 1; }}; // (A)
System.out.println(this.value);
System.out.println(a.value);
}
public static void main(String[] args) {
new Test5A().instanceMethod();
}
}
这个例子代码模仿你的类的行为。如果您编译并执行它,您将看到输出为“1 0”。
尽管(A)中匿名子类的实例初始值设定项看起来像是为其自己的value
实例变量赋值,但实际上该变量实际上只在匿名类的超类中可见。相反,在行(A)处,名为value
的唯一可见变量是调用instanceMethod()
的Test5A
实例的实例变量。因此,它被改为一个。
现在让我们增加value
知名度:
class Test5B {
protected int value;
public void instanceMethod() {
Test5B a = new Test5B() {{ value = 1; }};
System.out.println(this.value);
System.out.println(a.value);
}
public static void main(String[] args) {
new Test5B().instanceMethod();
}
}
这一次的输出为 “0 1”。实例变量value
是由匿名子类继承,它的是对其实例初始值设定项可见。因此,它被分配给正确的实例变量。
由于您试图设置属于原始Test5类的值字段,并且此类的任何实例在静态上下文中都不可用。考虑下面的代码
public class Test5 {
private int value = 0;
public static void main(String[] args) {
(new Test5()).foo();
}
void foo(){
Test5 b = new Test5(){
{
value = 1;
}
};
System.out.println(value);
}
}
输出为1.如果您想设置匿名类的价值,必须与THIS.VALUE引用它,但是这也会给你一个编译错误,因为值是私有的。
区别是在实例的上下文中创建一个匿名子类与静态上下文。比较:
public class InnerClasses {
int pack;
private int priv;
static private int stat;
private class NotStatic {
{
pack = 1;
priv = 1;
stat = 1;
}
}
private static class IsStatic {
{
pack = 1; // Static member class not tied to outer instance
priv = 1; // Ditto
stat = 1;
}
}
public void instanceMethod() {
InnerClasses a = new InnerClasses() {
{
pack = 1;
priv = 1;
stat = 1;
}
};
}
public static void main(String[] args) {
InnerClasses s = new InnerClasses() {
{
pack = 1;
priv = 1; // Anonymous subclass in static context
stat = 1;
}
};
}
}
带注释的行不能编译。 IsStatic
的那些很容易理解,但instanceMethod
中的匿名类与静态main
之间的区别更加微妙。
请注意,private
确实具有“仅在封闭*类别中可见”和“不在该类别中可见”的效果。 (我记得,后者是JVM级别的实际机制,并且获得前者效果的方式是通过综合访问器方法。)这就是NotStatic
可以如何访问priv
。
所以显然不同的是,当在静态上下文中创建一个匿名子类时,它不被认为是“封闭的”。更熟悉JLS的人可能能够澄清。
是的,你的匿名类在instanceMethod()可以参考priv实例变量。但是,它不是你可能期望它引用的变量。看看我的扩展答案。 – janko 2009-09-29 08:25:55
不,它实际上是可以访问的。 javac的报告错误是关于静态上下文,而不是访问修饰符。 – 2009-09-29 04:21:13
汤姆是对的!值是可访问的......并且如前所述,其静态问题被报告为错误! – Ajay 2009-09-29 04:24:32
如果我让价值“保护”而不是“私人”,那么Ajay的例子根本没有显示任何警告。也就是说,问题在于匿名类看不到变量,而编译器认为非静态变量是从main的上下文访问的。 – janko 2009-09-29 05:01:37