class A {
private int foo;
void bar(B b) { b.foo = 42; }
}
class B extends A { }
Run Code Online (Sandbox Code Playgroud)
这无法编译错误:
A.java:3: error: foo has private access in A
void bar(B b) { b.foo = 42; }
^
1 error
Run Code Online (Sandbox Code Playgroud)
将强制转换添加到基类使其工作.
void bar(B b) { ((A) b).foo = 42; }
Run Code Online (Sandbox Code Playgroud)
有人能指出我为什么第一个片段是非法的解释?它被禁止的原因是什么?以下是JLS所说的内容:
否则,声明成员或构造函数
private,当且仅当它发生在包含成员或构造函数声明的顶级类(第7.6节)的主体内时才允许访问.
我可以说,我的代码符合这一措辞.那么这是Java编译器的错误,还是我对JLS的解释不正确?
(注意:我不是在寻找变通方法,比如制作变量protected.我知道如何解决这个问题.)
Nik*_*lay 16
错误消息"在A中具有私有访问权限"是一个很长时间的java错误.
JDK 1.1:
JDK-4096353:JLS 6.6.1:当使用子类引用来访问超类的私有时
包含的代码片段完全符合问题一
class X{
private static int i = 10;
void f() {
Y oy = new Y();
oy.i = 5; // Is this an error? Is i accessable through a reference to Y?
}
}
class Y extends X {}
Run Code Online (Sandbox Code Playgroud)
他们试图修复它并导致它
JDK-4122297:javac的错误消息不适用于私有字段.
======TP1======
1 class C extends S {
2 void f(){
3 java.lang.System.out.println("foo");
4 }
5 }
6
7 class S {
8 private int java;
9 }
======
% javac C.java
C.java:3: Variable java in class S not accessible from class C.
java.lang.System.out.println("foo");
^
C.java:3: Attempt to reference field lang in a int.
java.lang.System.out.println("foo");
^
2 errors
======
Run Code Online (Sandbox Code Playgroud)
但是规范java不是在C中继承的,而且这个程序应该编译.
它固定在1.2,但再次出现在1.3中
JDK-4240480:name00705.html:JLS6.3私有成员不应从超类继承
JDK-4249653:新的javac假定私有字段由子类继承
当泛型来的时候
JDK-6246814:类型变量的私有成员可以错误地访问
JDK-7022052:私有方法和泛型上的编译器错误无效
但是,通过JLS,此成员在继承的类型中根本不存在.
JLS 8.2.班级成员
声明为private的类的成员不会被该类的子类继承.
所以b.foo是非法的,因为类B没有命名的字段foo.它没有限制,它是一个缺席的领域B.
Java具有强类型,B即使它们存在于超类中,我们也无法访问不存在的字段A.
Cast (A) b是合法的,因为B是它的子类A.
A有一个名为的字段foo,我们可以访问这个私有字段,因为即使是由于,它b(B b)也是类中的一个函数Ab != this
JLS 6.6.1.确定可访问性
否则,如果成员或构造函数被声明为private,则当且仅当它发生在包含成员或构造函数声明的顶级类(第7.6节)的主体内时才允许访问.
如果我们写的话
class A {
private int foo;
void baz(A b) { b.foo = 42; }
}
class B extends A { }
class T {
void x() {
B b = new B();
b.baz(b);
}
}
Run Code Online (Sandbox Code Playgroud)
它将编译,因为Java推断多态调用的类型参数.
JLS 15.12.2.7.根据实际参数推断类型参数:
超类型约束T:> X意味着解决方案是X的超类型之一.在T上给出了几个这样的约束,我们可以交叉每个约束隐含的超类型集合,因为类型参数必须是所有约束的成员.他们.然后我们可以选择交叉点中最具体的类型
Tar*_*rik 13
你不能说b.foo因为foo是私有的,因此不会被继承,因此B类无法看到foo变量并且不知道名为foo甚至存在的变量- 除非它被标记为受保护(如你所说)或默认(如他们在我猜的同一个包中或公开.
如果你想使用foo不使用像第二个例子那样的显式转换,你必须使用this.foo或只是foo隐含的this.正如Javadocs指定的那样,this关键字的主要原因是为了防止:
使用this关键字的最常见原因是因为字段被方法或构造函数参数遮蔽.
当你使用((A) b)时,你正在构建A引用类型,编译器会看到它就像你使用引用变量类型,换句话说,类似的东西A a,并且a.foo是完全合法的.
可见性和对超类私有实例变量的访问的说明性摘要: 
| 归档时间: |
|
| 查看次数: |
2957 次 |
| 最近记录: |