2015-06-01 7 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(); 
    } 
} 

SedanCar является подклассом AbstractVehicle, который содержит protected метод speedFactor. Я могу вызвать метод speedFactor, если на него ссылается тот же класс. Когда суперкласс используется для ссылки, метод speedFactor недоступен.

Что является причиной скрытия метода?

+1

Поскольку 'protected' видна самому классу (например, 'private') и его подклассам. Это не публично **. – EpicPandaForce

+1

Методы экземпляра 'protected' видны самому классу и _instances_ подклассов, но не статическим методам в подклассах. – khelwood

+0

Но SedanCar является подклассом AbstractVehicle. – MinusInfinity

ответ

4

SedanCar Ваш класс в другом пакете, чем AbstractVehicle класса. protected могут быть доступны только из того же пакета или из подклассов.

В случае SedanCar:

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

Вы вызываете protected метод из того же пакета: OK. SedanCar в пакете car и main() метод находится в классе, который находится в пакете car (фактически тот же класс).

В случае AbstractVehicle:

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

Вы пытаетесь вызвать метод protected но из другого пакета: NOT OK. Метод main(), с которого вы пытаетесь позвонить, находится в пакете car, а AbstractVehicle находится в пакете vehicle.

В основном это понимают:

У вас есть переменная типа AbstractVehicle, который объявлен в другом пакете (vehicle). Он может содержать или не содержать динамический тип SedanCar. В вашем случае это так, но оно также может содержать экземпляр любого другого подкласса, определенного в другом пакете, например. в sportcar. А так как вы в пакете car (метод main()), вам не разрешено вызывать vehicle.speedFactor() (который является защищенным AbstractVehicle.speedFactor()).

+1

Я очень удивлен, что он может вызывается из класса, который расширяет AbstractVehicle.Да, он находится в статическом методе, но метод заключен в класс, который расширяет AbstractVehicle. Это имеет смысл, потому что статические методы не участвуют в наследовании, но меня это все еще удивляет. – markspace

+0

@markspace Поскольку метод, который вы пытаетесь вызвать, не является 'SedanCar.speedFactor()', а 'AbstractVehicle.speedFactor()'. Да, фактически это будет 'SedanCar.speedFactor()', но вы имеете в виду 'AbstractVehicle.speedFactor()', который является «защищенным» методом в другом пакете. – icza

+0

Назад в мой SCJP в течение 1,5 дней, одна вещь, которую я когда-то помнил, была осторожна с опорными переменными суперкласса. Не удивительно видеть это сейчас. – prabugp

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() метод не является частью экземпляра, поэтому он не может получить доступ к защищенному методу.

+0

w.r.t вашей последней строки - «Метод static main() не является частью экземпляра, поэтому он не может получить доступ к защищенному методу». - Даже я не могу получить к нему доступ из нестатического метода. – Ouney

+0

@ Нужно хорошо, если это нестатический метод в '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 для 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 Доступ к защищенному члену

Пусть С класс, в котором объявлен защищенный член m. Доступ разрешается только в пределах тела подкласса S С. Кроме того, если идентификатор обозначает поле экземпляра или метод экземпляра, то:

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

Смежные вопросы