2015-08-04 19 views
29

Der Compiler lässt eine statische Methode keine nicht statische Methode aufrufen. Ich verstehe, dass dies der Fall ist, weil eine nicht statische Methode normalerweise eine Instanzvariable verwendet.Ist es sinnvoll, eine nicht statische Methode zu verwenden, die keine Instanzvariable verwendet?

Aber macht es Sinn, eine nicht statische Methode zu haben, die keine Instanzvariable verwendet. Wenn wir ein Verhalten haben, das den Zustand der Instanz nicht beeinflusst oder nicht beeinflusst, sollte eine solche Methode nicht als statisch markiert werden.

Antwort

24

Oft mal, nein. Wenn die Methode keinen Instanzstatus berührt, gibt es keinen Grund, sie an eine Instanz zu binden.

Natürlich können statische Methoden nicht vererbt oder überschrieben werden. Es ist also eine naheliegende Zeit, dass Sie eine Instanzmethode haben möchten, die keinen Instanzstatus verwendet. Die strategy pattern ist ein klassisches Beispiel dafür.

Ein weiterer Fall, in dem Sie es an eine Instanz binden können, ist, ob es sich um eine öffentliche API handelt und Sie sich vorstellen, dass Sie die Methode in Zukunft an den Instanzstatus binden möchten. In diesem Fall kann es aufgrund von Bedenken hinsichtlich der Rückwärtskompatibilität für Benutzer, die Ihre API verwenden, schwierig (oder unmöglich) sein, diese statische Methode in eine Instanzmethode umzuwandeln.

+3

Das Argument API ist hier der wichtigste Punkt. Eine 'statische' Methode kann keine Methoden von geerbten Schnittstellen implementieren. Eine "statische" Methode unterliegt keiner Polymorphie. "Statische" Methoden sind in der Tat sehr begrenzt hinsichtlich ihrer Fähigkeiten. –

+0

@BoristheSpider Natürlich ist das sowohl ein Segen als auch ein Fluch. Viele funktionale Sprachen bauen stark auf "statischen" Funktionen auf - grundsätzlich ist alles, was nicht explizit an eine Instanz gebunden sein muss (z. B. polymorphe Schnittstellenimplementierungen), eher statisch. In gewisser Weise ist es eine Rückkehr zu den C-Tagen der alten Schule, aber es ist ziemlich erfrischend. Da funktionale Programmierung dazu tendiert, die Zusammensetzung eher über die Vererbung zu bevorzugen, ist dies durchaus sinnvoll. – Luaan

3

Ich verstehe, dass es dies tut, weil eine nicht statische Methode normalerweise mit einer Instanzvariable endet.

Auch wenn die Instanzmethode keine Instanzvariable verwendet, ist sie immer noch an die Instanz der Klasse gebunden. In der Tat hat es einen Verweis auf this implizit in der Methode Argumente.

Mit anderen Worten, in dem folgende Verfahren:

public void foo() { 

} 

this wird implizit als die erste lokale Variable in der Methode übergeben.

EDIT:

Re-Lektüre der Frage, es ist eher eine breite Frage, die von der Situation abhängt. Im Allgemeinen, wenn die Methode die Instanz nicht benötigt (und Sie sind sich ziemlich sicher, dass dies nicht der Fall ist), dann machen Sie einfach static.

+0

ich verstehe. Aber schreiben wir in realen Anwendungen solche Instanzmethoden (die von Instanzvariablen unabhängig sind) – Chiseled

+1

@Twister Dies ist ein anderes Problem. Hier überlegen Sie, welche logischen Entscheidungen der Programmierer getroffen hat, ob die Methode statisch sein soll oder nicht. Dem Compiler ist das egal: Er muss die Regeln durchsetzen. – manouti

+0

Und diese Antwort Frage wie? – John

30

Na klar! Nehmen wir an, Sie haben interface IMyCollection. Es hat eine Methode boolean isMutable().

Jetzt haben Sie zwei Klassen, class MyMutableList und class MyImmutableList, die beide IMyCollection implementieren. Jeder von ihnen würde die Instanzmethode isMutable() überschreiben, wobei MyMutableList einfach true und MyImmutableList zurückgibt false.

isMutable() in beiden Klassen ist eine Instanzmethode, die (1) keine Instanzvariablen verwendet und (2) den Status der Instanz nicht beeinflusst. Aufgrund von Einschränkungen in der Sprache (statische Methoden können nicht überschrieben werden), ist dieses Design jedoch das einzig praktische.

Außerdem möchte ich ein Missverständnis aufklären (wie auch @manouti): nicht statische Methoden sind keine Instanzen, weil sie Instanzvariablen verwenden oder den Zustand der Instanz beeinflussen; Sie sind Instanzmethoden, weil sie auf diese Weise definiert wurden (ohne das Schlüsselwort static), und haben daher einen impliziten Parameter this (der in Sprachen wie Python tatsächlich explizit ist!).

7

Da statische Methoden nicht überschrieben werden können, versuchen viele Entwickler, die sich mit der Testbarkeit ihres Codes befassen, statische Methoden in Java zu vermeiden.

Code ist testbarer, wenn Abhängigkeiten durch Mock-Objekte ersetzt werden können. Mockito und EasyMock sind die gebräuchlichsten Werkzeuge, um dabei zu helfen, und sie verlassen sich auf die Vererbung, um Unterklassen zu erstellen, mit denen Sie leicht die (oft komplexe) Methode überschreiben können, die Sie nicht testen möchten konzentriert sich auf das, was Sie tun testen möchten.

Ich gehe nicht bis zum äußersten, um für Null statische Methoden zu versuchen, aber wenn ich einräume, sie einzuschließen, bereue ich es oft später, aus Gründen der Prüfung.

All dies ist sehr frustrierend, weil es nichts damit zu tun hat, was die Entwurfsüberlegung von statischen vs Instanzmethoden sein sollte. Was mich für diese Sprachen macht wünschen, mit denen Sie haben Funktionen, die nicht mit einer Klasse verbunden sind ...

7

Wenn man eine Menschen lesbare Beschreibung des Zwecks der Methode zu schreiben, wäre es erwähnt machen ein Objekt? Wenn ja, verwenden Sie eine Instanzmethode. Wenn nicht, verwenden Sie eine statische Methode. Beachten Sie, dass einige Methoden in beide Richtungen beschrieben werden können. In diesem Fall sollte man sich überlegen, welche Bedeutung besser ist.

Betrachten Sie zum Beispiel "Holen Sie sich die Adresse, an die ein Freedonian Einkommenssteuerformular verschickt werden soll" vs "Holen Sie sich die Adresse, an die Freedonian Einkommensteuerformulare verschickt werden sollen"? Die erste Frage sollte mit einer Instanzmethode beantwortet werden; der zweite durch eine statische Methode. Es kann sein, dass Freedonia derzeit verlangt, dass alle Steuerformulare an die gleiche Adresse gesendet werden (in diesem Fall könnte die frühere Methode alle Instanzfelder ignorieren), aber in Zukunft möglicherweise unterschiedliche Büros für Personen in verschiedenen Regionen haben (in diesem Fall die frühere Methode) könnte sich die Steuerzahler-ID ansehen und eine darauf basierende Postanschrift auswählen, während die letztere Methode Formulare an ein Büro senden müsste, das Formulare für jeden annehmen und sie bei Bedarf umleiten könnte).

2

Ein schönes Beispiel ist eine objektorientierte Codierung von Booleans. Die meisten Sprachen, sogar objektorientierte wie Java, entscheiden sich für eine Abstract-Data-Type-orientierte Codierung von Booleans, aber z.B. Smalltalk verwendet eine OO-Codierung, und fast keine der Methoden verwendet einen Instanzstatus. Es sieht ein bisschen wie folgt:

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 der Tat, wenn Sie ein ernsthaftes Engagement für OO folgen, viel referentiell transparenten Methoden verwenden, und für Polymorphismus über conditionals, werden Sie oft mit Methoden in vielen am Ende von Unterklassen, wobei jede Implementierung in einer der Klassen einen konstanten Wert zurückgibt.

2

Ich denke, manchmal ist es ja, weil nicht statische Methode unterschiedliche Aufgaben für andere Klasse zu tun, außer Kraft setzen kann, aber die Aufgabe kann nicht Instanz-Variable, zB beinhaltet:

Fruit.java

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

Orange.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"); 
    } 
} 

Druckinfo des Objekts:

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