2015-08-04 23 views
29

Il compilatore non consente a un metodo statico di chiamare un metodo non statico. Capisco che lo faccia perché un metodo non statico di solito finisce usando una variabile di istanza.Ha senso avere un metodo non statico che non usa una variabile di istanza?

Ma ha senso avere un metodo non statico che non utilizza una variabile di istanza. Se abbiamo un comportamento che non influisce o non è influenzato dallo stato dell'istanza, non dovrebbe essere contrassegnato come statico.

risposta

24

Spesso, n. Se il metodo non tocca nessuno stato di istanza, non c'è motivo di legarlo a un'istanza.

Ovviamente, i metodi statici non possono essere ereditati o sovrascritti, quindi è un momento ovvio che si vorrebbe avere un metodo di istanza che non utilizza lo stato dell'istanza. Il strategy pattern è un classico esempio di questo.

Un altro caso in cui è possibile legarlo a un'istanza è se questa è un'API pubblica e si immagina che si desideri collegare il metodo allo stato dell'istanza in futuro. In tal caso, i problemi di compatibilità con le versioni precedenti per le persone che utilizzano la tua API potrebbero rendere difficile (o impossibile) trasformare tale metodo statico in un metodo di istanza.

+3

L'argomento API è il punto più importante qui. Un metodo 'static' non può implementare metodi da interfacce ereditate. Un metodo 'statico' non è soggetto al polimorfismo. I metodi 'static' sono in effetti molto limitati per quanto riguarda le loro capacità. –

+0

@BoristheSpider Certo, è sia una benedizione che una maledizione. Molti linguaggi funzionali si basano pesantemente su funzioni "statiche": in pratica, qualsiasi cosa che non deve essere esplicitamente legata a un'istanza (ad esempio, implementazioni di interfacce polimorfiche) tenderà ad essere statica. In un certo senso è un ritorno ai giorni C della vecchia scuola, ma è piuttosto rinfrescante. Dal momento che la programmazione funzionale tende a favorire piuttosto la composizione piuttosto che l'ereditarietà, ciò ha perfettamente senso. – Luaan

3

Capisco che lo faccia perché un metodo non statico di solito finisce usando una variabile di istanza.

Anche se il metodo di istanza non utilizza una variabile di istanza, è ancora associato all'istanza della classe. Infatti, ha un riferimento a this implicitamente negli argomenti del metodo.

In altre parole, nel metodo seguente:

public void foo() { 

} 

this viene implicitamente passato come prima variabile locale nel metodo.

EDIT:

Rileggendo la questione, è più di una vasta domanda che dipende dalla situazione. Generalmente, se il metodo non ha bisogno dell'istanza (e sei abbastanza sicuro che non lo farà), fallo semplicemente su static.

+0

ho capito. Ma nelle applicazioni reali scriviamo tali metodi di istanza (che è indipendente dalle variabili di istanza) – Chiseled

+1

@Twister Questo è un problema diverso. Qui stai considerando le decisioni logiche prese dal programmatore sul fatto che il metodo debba essere statico o meno. Il compilatore non si preoccupa di questo: deve far rispettare le regole. – manouti

+0

E questa risposta domanda come? – John

30

Beh, certo! Supponiamo di avere in interface IMyCollection. Ha un metodo boolean isMutable().

Ora si dispone di due classi, class MyMutableList e class MyImmutableList, che implementano entrambi IMyCollection. Ciascuno di essi sovrascrive il metodo di istanza isMutable(), con MyMutableList semplicemente restituendo true e MyImmutableList restituendo false.

isMutable() in entrambe le classi è un metodo di istanza che (1) non utilizza variabili di istanza e (2) non influenza lo stato dell'istanza. Tuttavia, a causa di vincoli nel linguaggio (è impossibile sovrascrivere i metodi statici), questo design è l'unico pratico.

Inoltre, vorrei chiarire un equivoco (come ha fatto anche @manouti): i metodi non statici non sono un'istanza perché usano qualsiasi variabile di istanza o influenzano lo stato dell'istanza; sono metodi di istanza perché sono stati definiti in questo modo (senza la parola chiave static) e quindi hanno un parametro implicito this (che in lingue come Python è in realtà esplicito!).

7

Poiché i metodi statici non possono essere sovrascritti, molti sviluppatori che si preoccupano della verificabilità del loro codice tentano di evitare del tutto i metodi statici in Java.

Il codice è più verificabile se le dipendenze possono essere sostituite con oggetti finti. Mockito e EasyMock sono gli strumenti più comuni per aiutare con questo, e si basano sull'ereditarietà per creare sottoclassi che consentono di sovrascrivere facilmente il metodo (spesso complesso) che non si desidera testare ... in modo che il test si concentra su ciò che si desidera testare do.

Non vado all'estremo di provare a zero metodi statici, ma quando concedo di includerli, spesso me ne pento, per motivi di prova.

Tutto ciò è molto frustrante, perché non ha nulla a che fare con quello che dovrebbe essere il criterio di progettazione dei metodi statici o istanza. Il che mi fa desiderare per quelle lingue che permetteranno avere avere funzioni che non sono collegati con una classe ...

7

Se uno fosse Scrivi descrizione leggibile dello scopo del metodo, farebbe menzione di un oggetto? In tal caso, utilizzare un metodo di istanza. In caso contrario, utilizzare un metodo statico. Si noti che alcuni metodi potrebbero essere descritti in entrambi i casi, nel qual caso si dovrebbe usare un giudizio su quale sia il significato migliore.

Si consideri, ad esempio, "Prendi l'indirizzo a cui deve essere inviato un modulo di imposta sul reddito della Liberia" vs "Richiedi l'indirizzo a cui devono essere inviati i moduli di imposta sul reddito della Frederia"? La prima domanda dovrebbe essere risolta con un metodo di istanza; il secondo con un metodo statico. Potrebbe essere che Freedonia richieda attualmente che tutti i moduli fiscali vengano inviati allo stesso indirizzo (nel qual caso il precedente metodo potrebbe ignorare tutti i campi di istanze), ma in futuro potrebbero avere uffici diversi per persone in diverse regioni (nel qual caso il metodo precedente potrebbe guardare l'ID del contribuente e selezionare un indirizzo postale basato su quello, mentre il secondo metodo dovrebbe dirigere i moduli verso un ufficio che potrebbe accettare moduli per chiunque e reindirizzarli secondo necessità).

2

Un bell'esempio è una codifica orientata agli oggetti di booleani. La maggior parte dei linguaggi, anche quelli orientati agli oggetti come Java, optano per una codifica orientata al tipo di dati astratti di booleani, ma ad es. Smalltalk utilizza una codifica OO e quasi nessuno dei metodi utilizza alcun stato di istanza. Sembra un po 'come questo:

import java.util.function.Supplier; 
@FunctionalInterface interface Block { void call(); } 

interface Bool { 
    Bool not(); 
    Bool and(Bool other); 
    Bool or(Bool other); 
    <T> T ifThenElse(Supplier<T> thenBranch, Supplier<T> elseBranch); 
    void ifThenElse(Block thenBranch, Block elseBranch); 

    static final Bool T = new TrueClass(); 
    static final Bool F = new FalseClass(); 

    class TrueClass implements Bool { 
    public Bool not() { return F; } 
    public Bool and(Bool other) { return other; } 
    public Bool or(Bool other) { return this; } 
    public <T> T ifThenElse(Supplier<T> thenBranch, Supplier<T> elseBranch) { 
     return thenBranch.get(); 
    } 
    public void ifThenElse(Block thenBranch, Block elseBranch) { 
     thenBranch.call(); 
    } 
    } 

    class FalseClass implements Bool { 
    public Bool not() { return T; } 
    public Bool and(Bool other) { return this; } 
    public Bool or(Bool other) { return other; } 
    public <T> T ifThenElse(Supplier<T> thenBranch, Supplier<T> elseBranch) { 
     return elseBranch.get(); 
    } 
    public void ifThenElse(Block thenBranch, Block elseBranch) { 
     elseBranch.call(); 
    } 
    } 
} 

public class Main { 
    public static void main(String... args) { 
    Bool.F.ifThenElse(() -> System.out.println("True"),() -> System.out.println("False")); 
    // False 
    } 
} 

In realtà, se si segue un serio impegno per OO, utilizzare un sacco di metodi referenzialmente trasparenti, e favore il polimorfismo sopra condizionali, è spesso finire con metodi in un sacco di sottoclassi, in cui ogni implementazione in una delle classi restituisce un valore costante.

2

penso a volte è sì, perché il metodo non statico può ignorare per fare i compiti diversi per classe diversa, ma il compito non può comportare variabile di istanza, ad esempio:

Fruit.java

public class Fruit{ 
    public void printInfo(){ 
     System.out.println("This is fruit"); 
    } 
} 

Arancia.java

public class Orange extends Fruit{ 
    public void printInfo(){ 
     System.out.println("This is orange"); 
    } 
} 

Grape.java

public class Grape extends Fruit{ 
    public void printInfo(){ 
     System.out.println("This is grape"); 
    } 
} 

stampa informazioni di oggetto:

Fruit f=new Grape(); 
f.printInfo();