是否可以从任何子protected
访问parentObject
的{{1}}变量?或者只能由特定的Object
访问?我的情景清楚地表达了我的怀疑。
我有两个班级childObject
和ParentClass
。 ChildClass
是ParentClass
的父级。我在ChildClass
中有一个名为protected
的{{1}}变量。它的类型为ParentClass
。然后,我创建了两个protVar
,如下所示。
Object
现在,我可以从Object
访问ParentClass p1 = new ParentClass();
ChildClass c1 = new ChildClass();
c1.callMethod(p1); // Here I want to access protected variable of p1 which is a separate object and Not initialized within c1 as super()
protVar
了吗?
答案 0 :(得分:8)
免责声明:答案是从my answer of another question复制的。但是,该问题没有得到答案。我相信它也适合这个问题,因此我将这些内容复制到这里进行一些小编辑。
protected
在Java中有点有趣。虽然我们总是说“protected”允许访问不同包的子类,但它不是全局。
例如,如果Child
延长Parent
,则Parent
中有受保护的成员。您在Child
中可以执行的操作是访问Child
的受保护成员,但不会访问Parent
的受保护成员。听起来有点奇怪,虽然它们听起来是一样的吗?
引自Core Java 9th Edition:
但是,Manager类方法可以窥视hireDay字段 仅限Manager对象,而不是其他Employee对象。这个 制定限制,以便您不会滥用受保护机制 形成子类只是为了获得对受保护字段的访问
(类经理扩展了Employee,Employee中有一个hireDay受保护的成员,而Manager和Employee位于 DIFFERENT 包中)
例如,
public class Manager extends Employee {
// accessing protected member of itself
public void foo1() {
System.out.println("" + this.hireDay); // OK
}
// access protected member of instance of same type
public void foo2(Manager manager) {
System.out.println("" + manager.hireDay); // OK
}
// access protected member of instance of super-class
public void foo3(Employee employee) {
System.out.println("" + employee.hireDay); // NOT ALLOWED!
}
}
这意味着,受保护的成员允许来自另一个包的子类通过该子类的引用(this
或另一个子类的引用)来访问
并且,具体到OP的答案:如果在callMethod
中声明ChildClass
,那么NO,你不能这样做,甚至不会编译。但是,如果在callMethod
中声明了ParentClass
,那么一切都很好,因为它只是ParentClass
访问ParentClass
实例的受保护成员。
更新
鉴于评论中的批评,我认为值得去JLS看看它说的是什么:
(引自http://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.1关于访问受保护成员,第二个子弹)
如果访问是通过字段访问表达式E.Id或方法 调用表达式E.Id(...),或方法引用表达式E :: Id,其中E是主表达式(第15.8节),然后是访问权限 当且仅当E的类型是S或S的子类
时才允许
这基本上就是我在答案中提供的内容:
在Manager
类中,manager.hireDay
有效,因为manager
是主要表达式,并且允许访问,因为manager
的类型是Manager
或子类Manager
。
因此,基于JLS,为什么manager.hireDay
工作 DOES 与manager
的类型(属于同一类型)有关系。
答案 1 :(得分:1)
是的,派生类可以通过'super'和对基类的另一个引用来访问基类中的受保护变量。
编辑应该注意的是,我在这里假设相同的包,因为你没有说明任何关于不同的包。否则规则就不同了。
答案 2 :(得分:0)
如果你的子类和父类在同一个包中,你可以直接访问这个对象[如果你愿意],否则你有两个选项。
1 - 在Parent类中创建一个公共getter方法并访问你的受保护使用该方法的字段
2 - Inside子类使用如下面给出的反射来获取Parent protected字段
public void callMethod(ParentClass o) {
try {
Field f = o.getClass().getDeclaredField("protVar");
f.setAccessible(true);
Object value = f.get(o);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
答案 3 :(得分:-1)
尽管问题已经过去了,但我正在尽力解释,因为对于java新手来说这是一个相当普遍的问题。
考虑包p1中的Employee类。
package p1;
public class Employee{
protected String hireDay = "hireday";
}
Manager扩展了Employee,并且位于不同的包中。
package p2;
public class Manager extends p1.Employee {
//now even Manager class has hireDay protected variable that was defined in Employee class.
//Since Manager class has protected variable hireDay , for any manager m1 , we can access hireDay as m1.hireDay ONLY within package p2.
}
Enterprenur类扩展了Manager,位于包p3。
package p3;
public class Enterpreneur extends p2.Manager{
//now Enterpreneur class has inherited hireDay protected variable that Employee class had. (see comments in Employee class.)
//Since Enterpreneur class has protected variable hireDay , for any Enterpreneur e , we can access hireDay as e.hireDay ONLY within package p3.
//the following will work because using Enterpreneur reference e , we can access e.hireday within package p3 , this has nothing to do with
//the fact that right now our code is present in Enterpreneur class , like the other answer said. Note the method is static.
public static void printhireDay(Enterpreneur e){
System.out.println("hireday is :" + e.hireDay);
}
//this will work because using this reference we can only access protected variable in the same class(Enterpreneur) or in a subclass.
public void printhireDay(){
System.out.println("hireday is :" + this.hireDay);
}
// This shouldn't work because using manager reference , we can only access protected field within package p2.
/* public printhireDay(Manager m){
System.out.println("hireday is :" + m.hireDay)
}*/
}
现在在root包中,我们要测试这个类。
public class HelloWorld{
public static void main(String []args){
p3.Enterpreneur e = new p3.Enterpreneur();
//both of these work.
e.printhireDay();
//printing by passing the reference e.
p3.Enterpreneur.printhireDay(e);
}
}