可以在Child Class或Child Object中访问受保护的变量

时间:2014-03-03 05:45:12

标签: java inheritance protected

是否可以从任何子protected访问parentObject的{​​{1}}变量?或者只能由特定的Object访问?我的情景清楚地表达了我的怀疑。

我有两个班级childObjectParentClassChildClassParentClass的父级。我在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了吗?

4 个答案:

答案 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);


     }
}