I metodi statici sono ereditati in Java?


143

Stavo leggendo la Guida di un programmatore alla certificazione SCJP Java ™ di Khalid Mughal.

Nel capitolo Ereditarietà, questo spiega

L'eredità dei membri è strettamente legata alla loro accessibilità dichiarata. Se un membro della superclasse è accessibile con il suo nome semplice nella sottoclasse (senza l'uso di alcuna sintassi aggiuntiva come super), quel membro viene considerato ereditato

Indica anche che i metodi statici non sono ereditati. Ma il codice qui sotto è perfettamente perfetto:

class A
{
    public static void display()
    {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A
{
    public void show()
    {
        // This works - accessing display() by its simple name -
        // meaning it is inherited according to the book.
        display();
    }
}

Come posso utilizzare direttamente display()in classe B? Ancora di più, B.display()funziona anche.

La spiegazione del libro si applica solo ai metodi di istanza?


stackoverflow.com/questions/4716040/… ha informazioni interessanti.
Mat

Non è quello che dice nella mia copia, prima edizione. Si prega di fornire un preventivo effettivo.
Marchese di Lorne,

Risposte:


180

Tutti i metodi accessibili sono ereditati da sottoclassi.

Dai tutorial Java Sun :

Una sottoclasse eredita tutti i membri pubblici e protetti del suo genitore, indipendentemente dal pacchetto in cui si trova la sottoclasse. Se la sottoclasse si trova nello stesso pacchetto del suo genitore, eredita anche i membri pacchetto-privati ​​del genitore. È possibile utilizzare i membri ereditati così come sono, sostituirli, nasconderli o integrarli con nuovi membri

L'unica differenza con i metodi statici (di classe) ereditati e i metodi non statici (di istanza) ereditati è che quando si scrive un nuovo metodo statico con la stessa firma, il vecchio metodo statico viene semplicemente nascosto, non ignorato.

Dalla pagina sulla differenza tra ignorare e nascondere.

La distinzione tra nascondere e ignorare ha importanti implicazioni. La versione del metodo ignorato che viene invocato è quella nella sottoclasse. La versione del metodo nascosto che viene invocato dipende dal fatto che sia invocato dalla superclasse o dalla sottoclasse


così ereditato si riferisce alla possibilità di sovrascrivere quel membro nella sottoclasse?
Algorithmist

Bene, questo fa parte dell'eredità, ma non tutto. Direi che le altre parti principali dell'ereditarietà sono il riutilizzo del codice e il polimorfismo.
yincrash,

La ridefinizione ha anche alcune regole come l'override?
Surender Thakran,

2
@Algorithmist no non esattamente. Tutte le cose che la tua sottoclasse vede più in alto nella gerarchia, sono cose che la tua classe ha ereditato. Ma i metodi statici ereditati non possono essere ignorati, ma solo nascosti ("redeclared" con la stessa firma). Pertanto, puoi anche dichiarare i tuoi metodi statici come definitivi, non importa. Quale metodo statico che verrà invocato è noto al momento della compilazione. Con metodi di istanza non finali, la risoluzione deve essere rinviata al runtime poiché potrebbero essere sovrascritti.
Martin Andersson,

1
Il tuo ultimo paragrafo è completamente compromesso !!! "La versione del metodo overriden che viene invocato è quella nella sottoclasse" questo non è vero: diciamo: la versione del metodo overriden che viene invocato è determinata solo in fase di esecuzione dalla JVM relativa a quale oggetto ha creato il chiama :)
mounaim,

14

Se è quello che dice davvero il libro, è sbagliato. [1]

La specifica del linguaggio Java # 8.4.8 afferma:

8.4.8 Ereditarietà, sostituzione e occultamento

Una classe C eredita dalla sua superclasse diretta tutti i metodi concreti m (sia statici che di istanza) della superclasse per i quali sono vere tutte le seguenti condizioni:

  • m è un membro della superclasse diretta di C.

  • m è pubblico, protetto o dichiarato con accesso al pacchetto nello stesso pacchetto di C.

  • Nessun metodo dichiarato in C ha una firma che è una sottoscrizione (§8.4.2) della firma di m.

[1] Non lo dice nella mia copia, prima edizione, 2000.


13

Puoi notare la differenza nel seguente codice, che è leggermente modificato rispetto al tuo codice.

class A {
    public static void display() {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A {
    public void show() {
        display();
    }

    public static void display() {
        System.out.println("Inside static method of this class");
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        // prints: Inside static method of this class
        b.display();

        A a = new B();
        // prints: Inside static method of superclass
        a.display();
    }
}

Ciò è dovuto ai metodi statici sono metodi di classe.

A.display () e B.display () chiameranno il metodo delle rispettive classi.


1
Richiamare un metodo statico su un'istanza come quella che stai provando non funzionerà in Java.
Lucas C. Feijo,

Ecco cosa spiega questo programma, non è possibile creare un'istanza dell'oggetto B e aspettarsi che l'ereditarietà funzioni con i membri statici. Prova a prendere lo stesso codice nella tua eclissi / qualsiasi ide o compila usando javac ed eseguilo
Gaurav

2
@ LucasC.Feijo in realtà io funziona. Almeno nel mio IDE (eclissi). Ho appena ricevuto un avviso. Potrebbe non essere un buon stile però ... ma questa è una storia diversa.
dingalapadum,

2
@ LucasC.Feijo non è consigliabile chiamare un metodo statico su un'istanza. Ma funziona come chiamare un metodo statico su un nome di classe.
Ziyang Zhang,

5

B.display () funziona perché la dichiarazione statica fa sì che il metodo / membro appartenga alla classe e non a nessuna istanza di classe particolare (aka Object). Puoi leggere di più qui .

Un'altra cosa da notare è che non puoi ignorare un metodo statico, puoi far dichiarare alla tua sottoclasse un metodo statico con la stessa firma, ma il suo comportamento potrebbe essere diverso da quello che ti aspetteresti. Questo è probabilmente il motivo per cui non è considerato ereditato. Puoi controllare lo scenario problematico e la spiegazione qui .


3

I metodi statici in Java sono ereditati, ma non possono essere ignorati. Se si dichiara lo stesso metodo in una sottoclasse, si nasconde il metodo della superclasse invece di sovrascriverlo. I metodi statici non sono polimorfici. Al momento della compilazione, il metodo statico sarà collegato staticamente.

Esempio:

public class Writer {
    public static void write() {
        System.out.println("Writing");
    }
}

public class Author extends Writer {
    public static void write() {
        System.out.println("Writing book");
    }
}

public class Programmer extends Writer {

    public static void write() {
        System.out.println("Writing code");
    }

    public static void main(String[] args) {
        Writer w = new Programmer();
        w.write();

        Writer secondWriter = new Author();
        secondWriter.write();

        Writer thirdWriter = null;
        thirdWriter.write();

        Author firstAuthor = new Author();
        firstAuthor.write();
    }
}

Otterrai quanto segue:

Writing
Writing
Writing
Writing book

2

I metodi statici sono ereditati in Java ma non prendono parte al polimorfismo. Se tentiamo di sovrascrivere i metodi statici, nasconderanno semplicemente i metodi statici della superclasse invece di sovrascriverli.


Non vedo un motivo per il voto negativo di questa risposta. È nitido e chiaro, almeno nella prima parte. La seconda parte non dovrebbe essere presa troppo tecnicamente, altrimenti va bene. Per chiarire, nei metodi di sostituzione il tipo restituito può cambiare (in sottotipo) mentre non è il caso dei metodi statici. Tecnicamente il "tentativo di ignorare" non si applica ai metodi statici, quindi tutto ciò che possiamo dire è che non possiamo.
Sharhp,

2

Questo concetto non è così semplice come sembra. Possiamo accedere ai membri statici senza ereditarietà, che è relazione HasA. Possiamo accedere ai membri statici estendendo anche la classe genitore. Ciò non implica che si tratti di una relazione ISA (ereditarietà). I membri statici in realtà appartengono alla classe e static non è un modificatore di accesso. Finché i modificatori di accesso consentono di accedere ai membri statici, possiamo usarli in altre classi. Come se fosse pubblico, sarà accessibile all'interno dello stesso pacchetto e anche al di fuori del pacchetto. Per privati ​​non possiamo usarlo da nessuna parte. Per impostazione predefinita, possiamo usarlo solo all'interno del pacchetto. Ma per proteggere dobbiamo estendere la super classe. Quindi ottenere il metodo statico su un'altra classe non dipende dall'essere statico. Dipende dai modificatori di accesso. Quindi, secondo me, I membri statici possono accedere se i modificatori di accesso lo consentono. Altrimenti, possiamo usarli come usiamo dalla relazione Hasa. E ha una relazione non ereditaria. Ancora una volta non possiamo ignorare il metodo statico. Se possiamo usare un altro metodo ma non possiamo ignorarlo, allora è relazione HasA. Se non riusciamo a sovrascriverli non sarà eredità, quindi lo scrittore era corretto al 100%.


L'estensione della classe genitore è una relazione "is-a". Se l'accesso è privato puoi usarlo all'interno della classe. 'protetto' include le classi e le classi derivate nel pacchetto corrente. Troppi errori qui.
Marchese di Lorne,

0

Il metodo statico è ereditato in una sottoclasse ma non è polimorfismo. Quando si scrive l'implementazione del metodo statico, il metodo della classe del genitore viene nascosto, non sovrascritto. Pensa, se non è ereditato, come puoi accedere senza classname.staticMethodname();?


0

Tutti i membri pubblici e protetti possono essere ereditati da qualsiasi classe, mentre i membri predefiniti o del pacchetto possono anche essere ereditati dalla classe all'interno dello stesso pacchetto di quello della superclasse. Non dipende se si tratta di un membro statico o non statico.

È anche vero che la funzione di membro statico non prende parte all'associazione dinamica. Se la firma di quel metodo statico è la stessa sia nella classe genitore che in quella figlio, si applica il concetto di Shadowing, non il polimorfismo.


0

Puoi sovrascrivere i metodi statici, ma se provi a usare il polimorfismo, allora funzionano secondo lo scopo della classe (Contrariamente a quanto normalmente ci aspettiamo).

public class A {

    public static void display(){
        System.out.println("in static method of A");
    }
}

public class B extends A {

    void show(){
        display();
    }

     public static void display(){
        System.out.println("in static method of B");
    }

}
public class Test {

    public static void main(String[] args){
        B obj =new B();
        obj.show();

        A a_obj=new B();
        a_obj.display();


    }


}

Nel primo caso, o / p è il "nel metodo statico di B" # override riuscito Nel 2 ° caso, o / p è "nel metodo statico di A" # Metodo statico - non prenderà in considerazione il polimorfismo


-1

Possiamo dichiarare metodi statici con la stessa firma nella sottoclasse, ma non è considerato prioritario in quanto non ci sarà alcun polimorfismo di runtime. Poiché tutti i membri statici di una classe vengono caricati al momento del caricamento della classe, quindi decide al momento della compilazione time (override in run time) Quindi la risposta è 'No'.


2
Non so perché la gente voti sempre in negativo e non dia il motivo del voto negativo.
surajs1n

Questa risposta riguarda l'override. La domanda riguarda l'eredità.
Marchese di Lorne,

-1

Molti hanno espresso la loro risposta a parole. Questa è una spiegazione estesa nei codici:

public class A {
    public static void test() {
        System.out.println("A");
    }
    public static void test2() {
        System.out.println("Test");
    }
}

public class B extends A {
    public static void test() {
        System.out.println("B");
    }
}

// Called statically
A.test();
B.test();
System.out.println();

// Called statically, testing static inheritance
A.test2();
B.test2();
System.out.println();

// Called via instance object
A a = new A();
B b = new B();
a.test();
b.test();
System.out.println();

// Testing inheritance via instance call
a.test2();
b.test2();
System.out.println();

// Testing whether calling static method via instance object is dependent on compile or runtime type
((A) b).hi();
System.out.println();

// Testing whether null instance works
A nullObj = null;
nullObj.hi();

risultati:

A
B

Test
Test

A
B

Test
Test

A

A

Pertanto, questa è la conclusione:

  1. Quando chiamiamo lo statico in modo statico tramite., Cercherà lo statico definito in quella classe, o la classe più vicina a quella nella catena di ereditarietà. Ciò dimostra che i metodi statici sono ereditati.
  2. Quando viene chiamato un metodo statico da un'istanza, chiama il metodo statico definito nel tipo di tempo di compilazione.
  3. Il metodo statico può essere chiamato da nullun'istanza. La mia ipotesi è che il compilatore utilizzerà il tipo di variabile per trovare la classe durante la compilazione e tradurla nella chiamata del metodo statico appropriato.

1
Il semplice codice non è una spiegazione, è una dimostrazione. Una risposta a questa domanda dovrebbe citare riferimenti normativi, non solo mostrare il comportamento di un'implementazione non dichiarata.
Marchese di Lorne,

-2

I membri statici sono membri universali. Sono accessibili da qualsiasi luogo.


4
è possibile accedervi da qualsiasi punto preso letteralmente, che è sbagliato: static! = scope. potresti voler chiarire :-)
Kleopatra l'

In realtà, questa risposta va bene se presa alla lettera. Non riesco a pensare a una singola posizione nel codice in cui il codice può andare che non si può accedere a un membro statico di classe. Puoi accedervi con inizializzatori statici, costruttori statici, costruttori di istanze, metodi, proprietà, in diverse classi, in qualsiasi ambito. Finché la classe e il metodo statico sono pubblici, è possibile accedervi da qualsiasi luogo, supponendo che non vi siano dipendenze circolari sugli inizializzatori statici. In sostanza, i membri statici non sono ereditati, sono solo metodi a livello di classe (cioè universali) accessibili da qualsiasi luogo.
Triynko,

@Triynko La risposta è errata nel caso di metodi privati ​​o protetti da pacchetti accessibili dall'esterno del pacchetto.
Marchese di Lorne,

@kleopatra - fuori tema. Java swing? la gente lo usa davvero in questi giorni?
MasterJoe

@Pavan prova a chiamare statica privata dall'esterno della classe. Non funzionerà
Rakesh Yadav,

-2

I membri statici non verranno ereditati nella sottoclasse perché l'ereditarietà è solo per i membri non statici. I membri statici verranno caricati all'interno del pool statico dal caricatore di classi. L'ereditarietà è solo per quei membri che sono caricati all'interno dell'oggetto


Completamente errato. Vedi JLS # 8.4.8 .
Marchese di Lorne,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.