Java: Statische Klasse?


130

Ich habe eine Klasse voller Dienstprogrammfunktionen. Eine Instanz davon zu instanziieren macht keinen semantischen Sinn, aber ich möchte trotzdem ihre Methoden aufrufen. Was ist der beste Weg, um damit umzugehen? Statische Klasse? Abstrakt?


14
Sie können übrigens keine Top-Level-Klasse statisch machen ...
Jon

Antworten:


163

Privater Konstruktor und statische Methoden für eine als final gekennzeichnete Klasse.


19
@matt b: Wie David Robles in seiner Antwort hervorhebt, müssen Sie die Klasse nicht endgültig machen ... Sie kann nicht in Unterklassen unterteilt werden, da eine Unterklasse einen Superklassenkonstruktor nicht aufrufen kann, da sie privat ist. Es schadet jedoch nicht, explizit zu sein. Aber jfyi :-).
Tom

93

Nach dem großen Buch "Effective Java" :

Punkt 4: Erzwingen Sie die Nichtinstanzierbarkeit mit einem privaten Konstruktor

- Der Versuch, die Nichtinstanzierbarkeit durch eine abstrakte Klasse zu erzwingen, funktioniert nicht.

- Ein Standardkonstruktor wird nur generiert, wenn eine Klasse keine expliziten Konstruktoren enthält. Daher kann eine Klasse durch Einfügen eines privaten Konstruktors nicht instabilisiert werden:

// Noninstantiable utility class
public class UtilityClass
{
    // Suppress default constructor for noninstantiability
    private UtilityClass() {
        throw new AssertionError();
    }
}

Da der explizite Konstruktor privat ist, kann außerhalb der Klasse nicht auf ihn zugegriffen werden. Der AssertionError ist nicht unbedingt erforderlich, bietet jedoch eine Versicherung für den Fall, dass der Konstruktor versehentlich aus der Klasse heraus aufgerufen wird. Es garantiert, dass die Klasse unter keinen Umständen instanziiert wird. Diese Redewendung ist leicht eingängig, da der Konstruktor ausdrücklich angegeben wird, damit er nicht aufgerufen werden kann. Es ist daher ratsam, einen Kommentar aufzunehmen, wie oben gezeigt.

Als Nebeneffekt verhindert diese Redewendung auch, dass die Klasse in Unterklassen unterteilt wird. Alle Konstruktoren müssen explizit oder implizit einen Konstruktor der Oberklasse aufrufen, und eine Unterklasse hätte keinen zugänglichen Konstruktor der Oberklasse zum Aufrufen.


1
Warum haben Sie AssertionErrorandere Alternativen über wie IllegalStateException, UnsupportedOperationExceptionusw.?
Pacerier

@ Pacerier Sehen Sie dies .
bcsb1001

@ bcsb1001, das bringt uns dazu .
Pacerier

21

Klingt so, als hätten Sie eine Dienstprogrammklasse ähnlich java.lang.Math .
Der Ansatz dort ist die letzte Klasse mit privatem Konstruktor und statischen Methoden.

Beachten Sie jedoch, was dies für die Testbarkeit bedeutet. Ich empfehle, diesen Artikel zu lesen.
Statische Methoden sind der Tod für die Testbarkeit


Also ist java.lang.Math "Tod zur Testbarkeit"?
Pacerier

1
Es könnte interessant sein zu sehen, wie es punktet, wenn es durch code.google.com/p/testability-explorer
Crowne

6

Nur um flussaufwärts zu schwimmen, nehmen statische Mitglieder und Klassen nicht an OO teil und sind daher böse. Nein, nicht böse, aber im Ernst, ich würde eine reguläre Klasse mit einem Singleton-Muster für den Zugriff empfehlen. Auf diese Weise ist es keine größere Umrüstung, wenn Sie das Verhalten in einem späteren Fall außer Kraft setzen müssen. OO ist dein Freund :-)

Meine $ .02


17
Singletons gelten auch als böse.
Dan Dyer

3
Sie verwenden den privaten Konstruktor, um zu verhindern, dass jemand die Klasse instanziiert oder in Unterklassen unterteilt. Siehe die Antwort von David Robles: stackoverflow.com/questions/1844355/java-static-class/…
rob

5
Singleton ist nicht böser als Abhängigkeitsinjektion :)
unwiderlegbar

12
OO hat seinen Platz, aber es gibt Zeiten, in denen es einfach nicht praktikabel ist oder eine Verschwendung von Ressourcen wäre - zum Beispiel etwas so Einfaches wie Math.abs (). Es gibt keinen Grund, ein Objekt zu instanziieren, nur um ein Objekt zu instanziieren, wenn ein statischer Methodenaufruf Ihnen ohne den OO-Overhead genauso gut gedient hätte. ;)
Rob

2
@rob re OO, ich stimme zu, Math.Abs ​​braucht wahrscheinlich nie eine Instanz. Wenn ich "Ich habe eine Utility-Klasse" höre, sehe ich Math.Avg (), wo Sie jetzt Unterstützung für einen gewichteten Durchschnitt hinzufügen müssen. Ich sehe einen URL-Generator, param in, url out, der überarbeitet werden muss, um href oder nur url usw. zu unterstützen. Aus diesen Gründen kann sich die OO-basierte Utility-Klasse auszahlen. Außerdem werde ich jetzt die Standard-OO-Defensivtaktik fallen lassen und testen! / me ducks
Bennett Dill

3

Kommentar zu den Argumenten des "privaten Konstruktors": Komm schon, Entwickler sind nicht so dumm; aber sie sind faul. ein Objekt erstellen und dann statische Methoden aufrufen? wird nicht passieren.

Verbringen Sie nicht zu viel Zeit, um sicherzustellen, dass Ihre Klasse nicht missbraucht werden kann. Vertrauen Sie Ihren Kollegen. und es gibt immer eine Möglichkeit, Ihre Klasse zu missbrauchen, egal wie Sie sie schützen. Das einzige, was nicht missbraucht werden kann, ist etwas, das völlig nutzlos ist.


7
Jemand, der object.staticMethod gesehen hat (im Produktionscode, nicht im Studentencode). Ich denke, Sie überschätzen die Fähigkeiten von Joe Random Programmer! :-P
TofuBeer

2
  • Abschlussklasse und privater Konstrukteur (gut, aber nicht unbedingt erforderlich)
  • Öffentliche statische Methoden

1

Es macht keinen Sinn, die Klasse als zu deklarieren static. Deklarieren Sie einfach die Methoden staticund rufen Sie sie wie gewohnt aus dem Klassennamen auf, wie in der Java- Klasse Math .

Auch wenn es nicht unbedingt erforderlich ist, den Konstruktor privat zu machen, ist es eine gute Idee, dies zu tun. Durch Markieren des Konstruktors als privat wird verhindert, dass andere Personen Instanzen Ihrer Klasse erstellen und dann statische Methoden von diesen Instanzen aufrufen. (Diese Aufrufe funktionieren in Java genauso, sie sind nur irreführend und beeinträchtigen die Lesbarkeit Ihres Codes.)


1
Vergessen Sie auch nicht, einen privaten Konstruktor zu erstellen.
Asaph

@Asaph: Einverstanden. Ich habe meiner Antwort etwas hinzugefügt. Vielen Dank.
Bill the Lizard

Wenn Sie statische Methoden innerhalb einer inneren Klasse wünschen, muss die Klasse auch statisch sein.
Rui Marques

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.