2015-06-01 19 views
6

Si consideri il seguente frammenti di codice:Perché il metodo protetto non è accessibile dalla sottoclasse?

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 è una sottoclasse di AbstractVehicle che contiene un metodo speedFactorprotected. Sono in grado di chiamare il metodo speedFactor se viene fatto riferimento dalla stessa classe. Quando la super classe viene utilizzata come riferimento, il metodo speedFactor non è accessibile.

Qual è il motivo per nascondere il metodo?

+1

Perché 'protected' è visibile alla classe stessa (come 'private') e alle sue sottoclassi. È ** non pubblico **. – EpicPandaForce

+1

I metodi di istanza 'protected' sono visibili alla classe stessa e alle _istanze_ delle sottoclassi, ma non ai metodi statici nelle sottoclassi. – khelwood

+0

Ma SedanCar è una sottoclasse di AbstractVehicle. – MinusInfinity

risposta

4

La vostra classe SedanCar è in un pacchetto differente rispetto alla classe AbstractVehicle. I metodi protected sono accessibili solo dallo stesso pacchetto o da sottoclassi.

In caso di SedanCar:

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

si chiama un metodo di protected dallo stesso package: OK. SedanCar è nel pacchetto car e main() il metodo è in una classe che si trova nel pacchetto car (in realtà la stessa classe).

In caso di AbstractVehicle:

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

Si tenta di chiamare un metodo protected ma da un altro pacchetto: NON OK. Il metodo main() da cui si tenta di chiamarlo è nel pacchetto car mentre AbstractVehicle è nel pacchetto vehicle.

Fondamentalmente capire questo:

Hai una variabile di tipo AbstractVehicle che è dichiarato in un altro pacchetto (vehicle). Può o non può contenere un tipo dinamico di SedanCar. Nel tuo caso lo fa, ma potrebbe anche contenere un'istanza di qualsiasi altra sottoclasse definita in un altro pacchetto, ad es. in sportcar. E poiché si è nel pacchetto car (il metodo main()), non è consentito invocare vehicle.speedFactor() (che è il AbstractVehicle.speedFactor() protetto).

+1

Sono quasi sorpreso che possa essere chiamato da una classe che estende AbstractVehicle.Sì, è all'interno di un metodo statico, ma il metodo è racchiuso da una classe che estende AbstractVehicle. Ha un senso, perché i metodi statici non partecipano all'eredità, ma mi ha comunque sorpreso. – markspace

+0

@markspace Perché il metodo che si tenta di chiamare non è 'SedanCar.speedFactor()' ma 'AbstractVehicle.speedFactor()'. Sì, virtualmente sarà 'SedanCar.speedFactor()' ma ti riferisci a 'AbstractVehicle.speedFactor()' che è un metodo 'protected' in un altro pacchetto. – icza

+0

Nel mio SCJP per 1,5 giorni, una cosa che ricordavo era di diffidare delle variabili di riferimento della superclasse. Non è così sorprendente vederlo ora. – prabugp

4

Perché protected è visibile alla classe stessa (come privata) e alle sue istanze di sottoclasse. Non è pubblico

Ad esempio,

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) 
    } 
} 

Il metodo statico main() non fa parte dell'istanza, ecco perché non può accedere al metodo protetto.

+0

w.r.t l'ultima linea - "Il metodo statico main() non fa parte dell'istanza, ecco perché non può accedere al metodo protetto." - Anche io non sono in grado di accedervi da un metodo non statico. – Ouney

+0

@Ouney bene se si tratta di un metodo non statico all'interno di 'SedanCar', quindi dovresti essere in grado di accedervi. – EpicPandaForce

+0

Questo è quello che mi aspettavo, ma non è così :( – Ouney

2

Il modificatore protetto specifica che è possibile accedere al membro solo all'interno del proprio pacchetto (come con package-private) e, inoltre, da una sottoclasse della relativa classe in un altro pacchetto.

Questo è il motivo per cui non è possibile chiamare direttamente il metodo all'interno del metodo principale sull'oggetto veicolo.

Vedi: https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

+0

Ma il codice funziona, SedanCar sedan = new SedanCar(); sedan.speedFactor() funziona – MinusInfinity

+1

perché è dichiarato nello stesso pacchetto java –

0

Nel mio SCJP per Java 1,5 giorni, una cosa che ricordavo era di diffidare delle variabili di riferimento della superclasse. Non è così sorprendente vederlo ora e una cosa per cui ciò crea confusione è che la regola è protetta è visibile alla sottoclasse o allo stesso pacchetto. Cosa succede se è sia sottoclasse che pacchetto diverso?

Se si crea un altro pacchetto, e fare

package yetAnotherPackage; 

import car.SedanCar; 

public class Main { 

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

} 

vedrai che

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

Sembra che la regola si propaga solo. Finché hai una sottoclasse e provi ad accedere al metodo protetto all'interno del pacchetto della sottoclasse (o se non ci sono sottoclassi, quindi il pacchetto del genitore), dovresti essere bravo.

0

Le sottoclassi in pacchetti diversi non possono accedere a metodi protetti e variabili protette dalla superclasse utilizzando il riferimento superclasse. L'unico modo per accedere ai dati protetti della superclasse in sottoclasse è attraverso l'eredità

di seguito sono due frammenti di codice

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 
     } 

    } 

In specifica del linguaggio 6.6.2.1 L'accesso a un membro protetto

sia C il classe in cui è dichiarato un membro protetto m. L'accesso è consentito solo all'interno del corpo di una sottoclasse S di C. Inoltre, se Id indica un campo di istanza o un metodo esempio, allora:

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. 

per i dettagli in profondità visitano http://www.jot.fm/issues/issue_2005_10/article3.pdf

Problemi correlati