Domanda Qual è il guadagno dal dichiarare un metodo come statico


Recentemente ho esaminato i miei avvisi in Eclipse e ho trovato questo:

static warning

Fornirà un avvertimento al compilatore se il metodo può essere dichiarato come statico.

[modificare] Preventivo esatto all'interno dell'aiuto di Eclipse, con stress su privato e finale:

Se abilitato, il compilatore emetterà un errore o un avvertimento per   metodi che sono privato o finale e che si riferiscono solo a statico   membri.

Sì, lo so che posso spegnerlo, ma voglio conoscere il motivo per accenderlo?

Perché sarebbe una buona cosa dichiarare ogni metodo possibile come statico?

Ciò fornirà vantaggi in termini di prestazioni? (in un dominio mobile)

Indicando un metodo come statico, suppongo stia dimostrando che non si usano variabili di istanza, quindi si potrebbe passare a una classe di stile utils?

Alla fine della giornata dovrei semplicemente disattivarlo ignorando o dovrei correggere gli oltre 100 avvertimenti che mi ha dato?

Pensi che questo sia solo parole chiave extra sporco il codice, in quanto il compilatore adotterà comunque questi metodi? (un po 'come se non dichiarassi ogni variabile che puoi finale ma tu potresti).


93
2018-06-28 07:44


origine


risposte:


Ogni volta che scrivi un metodo, rispetti un contratto in un determinato ambito. Più ristretto è lo scope, più piccola è la possibilità di scrivere un bug.

Quando un metodo è statico, non è possibile accedere ai membri non statici; di conseguenza, il tuo ambito è più ristretto. Quindi, se non ne hai bisogno e non avrà mai bisogno (anche in sottoclassi) membri non statici per soddisfare il tuo contratto, perché dare l'accesso a questi campi al tuo metodo? Dichiarazione del metodo static in questo caso consentirà al compilatore di verificare che non si utilizzino membri che non si intende utilizzare.

Inoltre, aiuterà le persone a leggere il tuo codice a capire la natura del contratto.

Ecco perché è considerato buono dichiarare un metodo static quando in realtà sta implementando un contratto statico.

In alcuni casi, il tuo metodo significa solo qualcosa relativo a un'istanza della tua classe, e succede che la sua implementazione non usi effettivamente campi o istanze non statici. In questi casi, non contrassegni il metodo static.

Esempi di dove non useresti il static parola chiave:

  • Un hook di estensione che non fa nulla (ma potrebbe fare qualcosa con dati di istanza in una sottoclasse)
  • Un comportamento di default molto semplice pensato per essere personalizzabile in una sottoclasse.
  • Implementazione del gestore eventi: l'implementazione varierà con la classe del gestore eventi ma non utilizzerà alcuna proprietà dell'istanza del gestore eventi.

129
2018-06-28 07:49



Non c'è nessun concetto con l'ottimizzazione qui.

UN static il metodo è static perché dichiari esplicitamente che il metodo non si basa su alcuna istanza della classe di inclusione solo perché non è necessario. In modo che l'avviso Eclipse, come indicato nella documentazione:

Se abilitato, il compilatore emetterà un errore o un avvertimento per i metodi che sono privati ​​o finali e che si riferiscono solo ai membri statici.

Se non hai bisogno di alcuna variabile di istanza e il tuo metodo è privato (non può essere chiamato dall'esterno) o finale (non può essere annullato), non c'è motivo di lasciarlo essere un metodo normale invece che uno statico. Un metodo statico è intrinsecamente più sicuro anche solo perché ti è permesso fare meno cose con esso (non ha bisogno di alcuna istanza, non hai impliciti this oggetto).


12
2018-06-28 07:51



Non ho informazioni sulla performance, suppongo che sia alquanto migliore al massimo, dal momento che il codice non ha bisogno di fare l'invio dinamico in base al tipo.

Tuttavia, un argomento molto più forte contro il refactoring nei metodi statici è che attualmente l'uso statico è considerato una cattiva pratica. I metodi / le variabili statiche non si integrano bene in un linguaggio orientato agli oggetti e anche difficili da testare correttamente. Questo è il motivo per cui alcune lingue più recenti rinunciano del tutto al concetto di metodi / variabili statici, o cercano di interiorizzarlo nella lingua in un modo che giochi meglio con OO (es. Oggetti in Scala).

Nella maggior parte dei casi, sono necessari metodi statici per implementare funzioni che utilizzano solo i parametri come input e producono un output usando quello (ad esempio le funzioni di utilità / aiuto) Nei linguaggi moderni, esiste un concetto di funzione di prima classe che consente, in modo statico non è necessario Java 8 avrà espressioni lambda integrate, quindi ci stiamo già muovendo in questa direzione.


6
2018-06-28 07:53



1. Metodo di dichiarazione static offre un leggero vantaggio in termini di prestazioni, ma ciò che è più utile consente di utilizzarlo senza avere a disposizione un'istanza dell'oggetto (si pensi ad esempio al metodo factory o al singleton). Serve anche lo scopo documentativo di raccontare la natura del metodo. Questo scopo documentale non dovrebbe essere ignorato, in quanto fornisce un indizio immediato sulla natura del metodo ai lettori del codice e agli utenti dell'API e serve anche come uno strumento di riflessione per il programmatore originale - essere espliciti sul significato previsto aiuta anche tu pensi bene e produci un codice di qualità migliore (penso in base alla mia esperienza personale, ma le persone sono diverse). Ad esempio, è logico e quindi desiderabile distinguere tra metodi che operano su un tipo e metodi che agiscono su un'istanza del tipo (come sottolineato da Jon Skeet nel suo commento ad una domanda di C #).

Ancora un altro caso d'uso per static i metodi è quello di simulare l'interfaccia di programmazione procedurale. Pensa a java.lang.System.println() classe e i metodi e attributi in esso. La classe java.lang.System è usato come uno spazio dei nomi di raggruppamento piuttosto che un oggetto istantaneo.

2. In che modo Eclipse (o qualsiasi altra entità programmata o di altro tipo - biocomposibile o non biocomposibile) sa per certo quale metodo può essere dichiarato statico? Anche se una classe base non sta accedendo alle variabili di istanza o chiama metodi non statici, dal meccanismo di ereditarietà le cose possono cambiare. Solo se il metodo non può essere sovrascritto ereditando la sottoclasse, possiamo affermare con certezza al 100% che il metodo può essere realmente dichiarato static. Sovrascrivere un metodo è impossibile esattamente nei due casi di essere

  1. private (nessuna sottoclasse può usarlo direttamente e nemmeno in linea di principio lo sa), o
  2. final (anche se accessibile dalla sottoclasse, non c'è modo di cambiare il metodo per fare riferimento a dati o funzioni di istanza).

Da qui la logica dell'opzione Eclipse.

3. Anche il poster originale chiede: "Indicando un metodo come statico, suppongo stia dimostrando che non si usano variabili di istanza, quindi si potrebbe passare a una classe di stile utils?"Questo è un ottimo punto: a volte questo tipo di modifica del design è indicata dall'avviso.

È un'opzione molto utile, che personalmente mi assicurerei di abilitare, se dovessi usare Eclipse e se dovessi programmare in Java.


3
2017-07-04 05:21



Vedi la risposta di Samuel su come cambia lo scopo del metodo. Immagino, questo è l'aspetto principale del rendere statico un metodo.

Hai anche chiesto informazioni sulle prestazioni:

Potrebbe esserci un piccolo guadagno in termini di prestazioni, in quanto una chiamata a un metodo statico non ha bisogno del riferimento "questo" implicito come parametro.

Tuttavia, questo impatto sulle prestazioni è davvero minuscolo. Pertanto, è tutto sulla portata.


1
2018-06-28 07:56



Dalle linee guida sul rendimento di Android:

Preferisci Statico su virtuale Se non hai bisogno di accedere a un oggetto   campi, rendere statico il tuo metodo. Le invocazioni saranno circa il 15% -20%   Più veloce. È anche una buona pratica, perché puoi dire dal metodo   firma che chiamando il metodo non può alterare lo stato dell'oggetto.

http://developer.android.com/training/articles/perf-tips.html#PreferStatic


1
2017-07-17 15:12



Bene, la documentazione di Eclipse dice sull'avviso in questione:

Il metodo può essere statico

Se abilitato, il compilatore emetterà un errore o un avvertimento per   metodi che sono privati ​​o finali e che si riferiscono solo a statici   membri

Penso che lo dica praticamente tutto. Se il metodo è privato e definitivo e si riferisce solo a membri statici, il metodo in questione potrebbe anche essere dichiarato statico e con questo, è evidente che intendiamo solo accedere al contenuto statico da esso.

Onestamente, non penso ci sia alcun altro motivo misterioso dietro di esso.


0
2017-07-03 19:53



Mi mancavano alcuni numeri per le differenze di velocità. Così ho provato a confrontarli, ma non è stato così facile: Il ciclo di Java diventa più lento dopo alcune esecuzioni / errore di JIT?

Finalmente ho usato Caliper ed i risultati sono gli stessi di quelli che eseguono i miei test a mano:

Non esiste una differenza misurabile per le chiamate statiche / dinamiche. Almeno non per Linux / AMD64 / Java7.

I risultati della pinza sono qui: https://microbenchmarks.appspot.com/runs/1426eac9-36ca-48f0-980f-0106af064e8f#r:scenario.benchmarkSpec.methodName,scenario.vmSpec.options.CMSLargeCoalSurplusPercent,scenario.vmSpec.options.CMSLargeSplitSurplusPercent,scenario.vmSpec. options.CMSSmallCoalSurplusPercent, scenario.vmSpec.options.CMSSmallSplitSurplusPercent, scenario.vmSpec.options.FLSLargestBlockCoalesceProximity, scenario.vmSpec.options.G1ConcMarkStepDurationMillis

e i miei risultati sono:

Static: 352 ms
Dynamic: 353 ms
Static: 348 ms
Dynamic: 349 ms
Static: 349 ms
Dynamic: 348 ms
Static: 349 ms
Dynamic: 344 ms

La classe del test di calibro era:

public class TestPerfomanceOfStaticMethodsCaliper extends Benchmark {

    public static void main( String [] args ){

        CaliperMain.main( TestPerfomanceOfStaticMethodsCaliper.class, args );
    }

    public int timeAddDynamic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addDynamic( 1, i );
        }
        return r;
    }

    public int timeAddStatic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addStatic( 1, i );
        }
        return r;
    }

    public int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}

E il mio corso di prova era:

public class TestPerformanceOfStaticVsDynamicCalls {

    private static final int RUNS = 1_000_000_000;

    public static void main( String [] args ) throws Exception{

        new TestPerformanceOfStaticVsDynamicCalls().run();
    }

    private void run(){

        int r=0;
        long start, end;

        for( int loop = 0; loop<10; loop++ ){

            // Benchmark

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addStatic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Static: " + ( end - start ) + " ms" );

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addDynamic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Dynamic: " + ( end - start ) + " ms" );

            // Do something with r to keep compiler happy
            System.out.println( r );

        }

    }

    private int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}

0
2017-07-22 16:07



I metodi che puoi dichiarare come statici sono quelli che non richiedono l'istanziazione, come ad esempio

public class MyClass
{
    public static string InvertText(string text)
    {
        return text.Invert();
    }
}

Che poi puoi in cambio chiamare in qualsiasi altra classe senza instanciare quella classe.

public class MyClassTwo
{
    public void DoSomething()
    {
        var text = "hello world";
        Console.Write(MyClass.InvertText(text));
    }
}

... Ma è qualcosa che probabilmente già conosci. Non offre alcun vantaggio reale di per sé, oltre a rendere più chiaro che il metodo non utilizza alcuna variabile di istanza.

In altre parole, puoi tranquillamente disattivarlo completamente. Se sai che non utilizzerai mai un metodo in altre classi (nel qual caso dovrebbe essere solo privato), non è necessario che sia statico.


-2
2018-06-28 07:52