2015-06-01 93 views
6

考虑下面的代码片断:为什么受保护的方法不能从子类访问?

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不可访问。

隐藏该方法的原因是什么?

+1

因为'protected'对类本身是可见的(比如'private')及其子类。它是**不公开**。 – EpicPandaForce

+1

受保护的实例方法对类本身以及对子类的_instances_可见,但对子类中的静态方法不可见。 – khelwood

+0

但SedanCar是AbstractVehicle的子类。 – MinusInfinity

回答

4

SedanCar类是在不同的包比AbstractVehicle类。 protected方法只能从相同包或从子类访问。

SedanCar情况:

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

要调用来自同一封装的protected方法:OK。 SedanCar在包carmain()方法是在包car(实际上是相同的类)中的类。

AbstractVehicle情况:

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

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

基本上明白这一点:

您有其在另一封装(vehicle)声明AbstractVehicle类型的变量。它可能会或可能不会保持动态类型SedanCar。在你的情况下,它可以包含另一个包中定义的任何其他子类的实例,例如在​​。并且由于您处于包carmain()方法)中,因此不允许调用vehicle.speedFactor()(这是受保护的AbstractVehicle.speedFactor())。

+1

声明我有点惊讶,它可以不会从扩展AbstractVehicle的类中调用。是的,它在一个静态方法中,但该方法由扩展AbstractVehicle的类包围。它有点合理,因为静态方法不参与继承,但它仍然让我感到惊讶。 – markspace

+0

@markspace由于您尝试调用的方法不是'SedanCar.speedFactor()',而是'AbstractVehicle.speedFactor()'。是的,实际上它将是'SedanCar.speedFactor()',但是您指的是'AbstractVehicle.speedFactor()',它是另一个包中的'protected'方法。 – icza

+0

回到我的SCJP 1.5天,我曾经记住的一件事是对超类参考变量保持警惕。现在看到这一点并不令人惊讶。 – prabugp

4

因为protected对于类本身(如private)及其子类实例是可见的。它不公开。

例如,

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()方法不是实例的一部分,这就是为什么它不能访问受保护的方法。

+0

w.r.t最后一行 - “静态main()方法不是实例的一部分,这就是为什么它不能访问受保护的方法。” - 即使我无法从非静态方法访问它。 – Ouney

+0

@Ouney如果它是'SedanCar'中的非静态方法,那么你应该可以访问它。 – EpicPandaForce

+0

这就是我的预期,但它不是这样的:( – Ouney

2

受保护的修饰符指定该成员只能在其自己的包内访问(与包私有一样),另外还可以在其他包中的类的子类中访问。

这就是为什么你不能直接调用车辆对象上主方法的方法。

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

+0

但代码的作品,SedanCar轿车=新SedanCar(); sedan.speedFactor()作品 – MinusInfinity

+1

,因为它是在同一个java包 –

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 

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

0

不同包中的子类不能使用超类引用访问来自超类的受保护方法和受保护变量。 只有访问子超的受保护数据的方式是通过继承

下面是两个代码段

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 IN另外的主体允许的,并且,当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

相关问题