为什么无法从子类访问受保护的方法?

时间:2015-06-01 07:35:48

标签: java oop inheritance encapsulation access-specifier

请考虑以下代码段:

package vehicle;

public abstract class AbstractVehicle {
    protected int speedFactor() {
        return 5;
    }
}

package car;

import vehicle.AbstractVehicle;

public class SedanCar extends AbstractVehicle {
    public static void main(String[] args) {
        SedanCar sedan = new SedanCar();
        sedan
                .speedFactor();
        AbstractVehicle vehicle = new SedanCar();
        // vehicle //WON'T compile
        // .speedFactor();
    }
}

SedanCarAbstractVehicle的子类,其中包含protected方法speedFactor。如果它被同一个类引用,我可以调用方法speedFactor。当超类用于引用时,无法访问方法speedFactor

隐藏方法的原因是什么?

5 个答案:

答案 0 :(得分:4)

因为protected对类本身(如私有)及其子类实例可见。它不公开。

例如,

package vehicles;

public abstract class AbstractVehicle {
    protected int speedFactor() {
        return 5;
    }

    public int getSpeed() {
        return 10*speedFactor(); //accessing speedFactor() "privately"
    }
}

package vehicles.cars;

public class SedanCar extends AbstractVehicle {
    @Override
    protected int speedFactor() { //overriding protected method (just to show that you can do that)
        return 10;
    }

    @Override
    public int getSpeed() {
        return 20*speedFactor(); //this is part of the instance (!!!) therefore it can access speedFactor() protected method too
    }
}

package vehicles.main;

public class Main {
    public static void main(String[] args) {
        AbstractVehicle vehicle = new SedanCar();
        int speed = vehicle.getSpeed(); //accessing public method
        vehicle.speedFactor(); //cannot access protected method from outside class (in another package)
    }
}

静态main()方法不是实例的一部分,这就是它无法访问受保护方法的原因。

答案 1 :(得分:4)

您的SedanCar课程与AbstractVehicle课程不同。 protected方法只能从相同的包或从子类访问。

如果是SedanCar

SedanCar sedan = new SedanCar();
sedan.speedFactor();

您正在从同一个包中调用protected方法:好的。 SedanCar包在car包中,而main()方法位于包car中的类中(实际上是同一个类)。

如果是AbstractVehicle

AbstractVehicle vehicle = new SedanCar();
vehicle.speedFactor();

您尝试从另一个包中调用protected方法:不行。您尝试调用它的main()方法位于包car中,而AbstractVehicle位于包vehicle中。

基本了解这一点:

您有一个AbstractVehicle类型的变量,它在另一个包(vehicle)中声明。它可能包含也可能不包含SedanCar的动态类型。在你的情况下它确实如此,但它也可以包含另一个包中定义的任何其他子类的实例,例如在sportcar。由于您使用的是car包(main()方法),因此不允许您调用vehicle.speedFactor()(受保护的AbstractVehicle.speedFactor())。

答案 2 :(得分:2)

protected修饰符指定只能在自己的包中访问该成员(与package-private一样),此外,还可以在另一个包中通过其类的子类访问。

这就是为什么你不能直接在车辆对象的main方法中调用方法的原因。

请参阅:https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

答案 3 :(得分:1)

不同包中的子类无法使用超类引用从超类访问受保护的方法和受保护的变量。 在子类中访问超类的受保护数据的唯一方法是通过继承

下面是两个代码段

package nee;
import parentdata.Parent;

class Child extends Parent{

        public void testIt(){
        System.out.println(x);  // able to access protected x defined in Parent
        }

    }


package nee;
import parentdata.Parent;

        class Child extends Parent {

        public void testIt(){
        Parent p=new Parent();
        System.out.println(p.x) //  results in compile time error
        }

    }

在语言规范中 6.6.2.1访问受保护的成员

设C是声明受保护成员m的类。仅允许在C的子类S的主体内进行访问。此外,如果Id表示实例字段或实例方法,则:

If the access is by a qualified name Q.Id, where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S.
If the access is by a field access expression E.Id, where E is a Primary expression, or by a method invocation expression E.Id(. . .), where E is a Primary expression, then the access is permitted if and only if the type of E is S or a subclass of S.

深入了解详情 http://www.jot.fm/issues/issue_2005_10/article3.pdf

答案 4 :(得分:0)

回到我的SCJP for Java 1.5天,我曾经记得的一件事是警惕超类引用变量。现在看到这一点并不令人惊讶,并且有一个原因让人感到困惑的是,受保护的规则对于子类或相同的包是可见的。如果它既是子类又是不同的包呢?

如果您创建另一个包,请执行

package yetAnotherPackage;

import car.SedanCar;

public class Main {

    public static void main(String[] args) {
        new SedanCar().speedFactor();
    }

}

你会看到

The method speedFactor() from the type AbstractVehicle is not visible

看起来规则只是传播。只要你有一个子类并尝试访问子类包中的受保护方法(或者如果没有子类,那么父类的包),你应该是好的。