我有以下两个文件:
Fruit.java:
package superClass;
public class Fruit {
protected static void printName() {
System.out.println("My name is Khan");
}
}
Apple.java:
package food;
import superClass.*;
public class Apple {
public static void main(String[] args) {
int i, j;
for(i = 0; i < 5; i++) {
for(j = 0; j < i; j++) {
System.out.print("*");
}
System.out.println();
}
printName(); // Call inherited member - NO ERROR, expected
Fruit f = new Fruit();
f.printName(); // Call instantiated member - ERROR, expected
}
}
正如预期的那样,我无法访问Apple类中受保护的方法printName,因为它们位于不同的包中。我收到以下错误:
printName() has protected access in superClass.Fruit
完全正确。但是,如果我从类superClass继承如下,我不会得到任何错误!
package food;
import superClass.*;
public class Apple extends Fruit {
public static void main(String[] args) {
int i, j;
for(i = 0; i < 5; i++) {
for(j = 0; j < i; j++) {
System.out.print("*");
}
System.out.println();
}
printName(); // Call inherited member - NO ERROR, expected
Fruit f = new Fruit();
f.printName(); // Call instantiated member - NO ERROR, WHAT????
}
}
为什么允许我通过引用访问另一个包中另一个类的受保护成员?这应该是非法访问,不是吗?
我很困惑!有人请帮忙。
代码是使用Java 1.6.0_18编译的。
答案 0 :(得分:4)
您观察到的行为是因为printName是静态的。 protected修饰符提供子类中该方法的可见性,但如果方法是非静态的,则只能通过子类的实例调用该方法(您提出的问题) “如果我从类superClass继承如下,我不会得到任何错误!”)。 JLS section 6.6.2.1简明扼要地定义了这一点。
答案 1 :(得分:3)
protected modifier允许在继承的类中进行访问。如果你只需要在某个包中限制对类的访问,你需要一个“包”修饰符,它只是一个空修饰符,即这样的写方法:
static void printName()
它将具有包可见性。
答案 2 :(得分:3)
这是protected
访问权限的定义:protected
成员可以从子类访问,无论是否在不同的包中。
注意:在Java中,约定是使用小写包名,即superClass
不符合此约定。您可能会对此感到困惑 - 特别是如果您在* nix平台上开发文件和目录名称区分大小写。
答案 3 :(得分:3)
可以从子类访问超类的受保护成员,即使超类位于另一个包中,但我们可以通过引用使用受保护成员的类来使用,因为此时该类是受保护成员的所有者。 假设
中的受保护成员com.pack1 class A { protected int i;}
com.pack2 class D { System.out.println(i); System.out.println(a1.i); }
i
很完美但a1.i
不完美,给出错误。
在D类中,我们可以通过参考d而不是A类的引用来使用受保护的成员
答案 4 :(得分:1)
可以从子类访问超类的protected
成员,即使超类在另一个包中也是如此。请参阅本页的第二部分和附表/图表:
http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html
答案 5 :(得分:1)
当你说
时,就是这样的printName(); // Call inherited member - NO ERROR, expected
Fruit f = new Fruit();
f.printName(); // Call instantiated member - NO ERROR, WHAT????
请记住,printName是一个静态方法,因此即使编译器接受表单
f.printName();
真实形式将永远是
Fruit.printName(); // protected accesor allows the use of the method
Apple.printName(); // or just
printName(); // at the end everything is the same to this call
所以最后你得到了继承的静态方法,你只是对静态方法如何工作感到困惑,它们是类方法而不是实例,即使编译器没有抱怨写表单
f.printName();
内部发生的真实事情是类访问。但是确定编译器会发出类似的警告:
应该以静态方式访问Fruit类型的静态方法printName()
答案 6 :(得分:0)
您是否因使用默认(aka包)修饰符而受到保护?后者限制访问同一个包的成员。
受保护限制对从相关类继承的包和成员的访问权限。
有关详细信息,请参阅http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#62587
答案 7 :(得分:0)
Aye,dat很好,你没有得到任何错误......这可能是Java语言规范中的违规或错误...无论如何,这是正确的。这是受保护的访问修饰符的定义。受保护的类似于来自外部或来自其他类的类成员的可访问性的中间级别。这是私人和公众之间的假设。受保护的类成员是可访问的(来自类的子类)和(来自其他类,只要它们属于同一个包)。只是一个想法!