Ich habe diese Frage durchgegangen Gibt es eine Möglichkeit, Klassenvariablen in Java zu überschreiben? Der erste Kommentar mit 36 Upvotes war:
Wenn Sie jemals einen
protected static
sehen, führen Sie ihn aus.
Kann jemand erklären, warum ein protected static
verpönt ist?
Es ist mehr eine stilistische Sache als ein direktes Problem. Es legt nahe, dass Sie sich nicht genau überlegt haben, was mit der Klasse los ist.
Denken Sie darüber nach, was static
bedeutet:
Diese Variable existiert auf Klassenebene, sie ist nicht für jede Instanz separat vorhanden und hat keine unabhängige Existenz in Klassen, die mich erweitern.
Denken Sie darüber nach, was protected
bedeutet:
Diese Variable kann von dieser Klasse gesehen werden, Klassen im selben Paket und Klassen, die mich erweitern.
Die beiden Bedeutungen schließen sich nicht genau aus, sind aber ziemlich nahe.
Ich kann nur sehen, wo Sie die beiden zusammen verwenden könnten, wenn Sie über eine abstrakte Klasse verfügen, die erweitert werden soll, und die Erweiterungsklasse das Verhalten dann mithilfe der im Original definierten Konstanten ändern kann. Selbst dann ist es ein sehr schwacher Grund, da Sie die Konstanten fast immer noch als öffentlich empfinden würden. Das macht einfach alles sauberer und ermöglicht den Mitarbeitern eine höhere Flexibilität.
Um den ersten Punkt zu erweitern und zu erläutern, versuchen Sie diesen Beispielcode:
public class Program {
public static void main (String[] args) throws Java.lang.Exception {
System.out.println(new Test2().getTest());
Test.test = "changed";
System.out.println(new Test2().getTest());
}
}
abstract class Test {
protected static String test = "test";
}
class Test2 extends Test {
public String getTest() {
return test;
}
}
Sie sehen die Ergebnisse:
test
changed
Probieren Sie es selbst aus: https://ideone.com/KM8u8O
Die Klasse Test2
kann von test
aus auf das statische Member Test
zugreifen, ohne den Namen qualifizieren zu müssen. Sie erbt jedoch nicht oder erhält keine eigene Kopie. Es betrachtet genau dieselbe Variable.
Es ist verpönt, weil es widersprüchlich ist.
Das Erstellen einer Variablen protected
impliziert, dass sie innerhalb des Pakets verwendet wird oder innerhalb einer Unterklasse geerbt.
Wenn Sie die Variable static
machen, wird sie zum Mitglied der Klasse. Eliminiert die Absicht, sie zu erben. Dies lässt nur die Absicht, innerhalb eines Pakets verwendet zu werden, und wir haben package-private
dafür (keinen Modifikator).
Die einzige Situation, für die ich dies nützlich finden könnte, ist, wenn Sie eine Klasse deklarieren, die zum Starten der Anwendung verwendet werden soll (wie JavaFXs Application#launch
) und nur von einer Unterklasse aus starten möchten final
, um hiding nicht zuzulassen. Dies ist jedoch nicht "die Norm" und wurde wahrscheinlich implementiert, um das Hinzufügen von Komplexität durch Hinzufügen einer neuen Methode zum Starten von Anwendungen zu verhindern.
Informationen zu den Zugriffsebenen der einzelnen Modifizierer finden Sie hier: Die Java-Tutorials - Steuern des Zugriffs auf Member einer Klasse
Ich sehe keinen besonderen Grund, warum dies missbilligt werden sollte. Es kann immer Alternativen geben, um dasselbe Verhalten zu erreichen, und es hängt von der tatsächlichen Architektur ab, ob diese Alternativen "besser" sind als eine geschützte statische Methode oder nicht. Ein Beispiel, bei dem eine geschützte statische Methode zumindest sinnvoll wäre, könnte folgendes sein:
(Zur Aufteilung in separate Pakete bearbeitet, um die Verwendung von protected
klarer zu machen)
package a;
import Java.util.List;
public abstract class BaseClass
{
public Integer compute(List<Integer> list)
{
return computeDefaultA(list)+computeDefaultB(list);
}
protected static Integer computeDefaultA(List<Integer> list)
{
return 12;
}
protected static Integer computeDefaultB(List<Integer> list)
{
return 34;
}
}
Davon abgeleitet:
package a.b;
import Java.util.List;
import a.BaseClass;
abstract class ExtendingClassA extends BaseClass
{
@Override
public Integer compute(List<Integer> list)
{
return computeDefaultA(list)+computeOwnB(list);
}
private static Integer computeOwnB(List<Integer> list)
{
return 56;
}
}
Eine andere abgeleitete Klasse:
package a.b;
import Java.util.List;
import a.BaseClass;
abstract class ExtendingClassB extends BaseClass
{
@Override
public Integer compute(List<Integer> list)
{
return computeOwnA(list)+computeDefaultB(list);
}
private static Integer computeOwnA(List<Integer> list)
{
return 78;
}
}
Der protected static
-Modifikator kann hier sicherlich begründet werden:
static
sein, da sie nicht von Instanzvariablen abhängen. Sie sollen nicht direkt als polymorphe Methode verwendet werden, sondern sind "Utility" -Methoden, die standardmäßige Implementierungen bieten, die Teil einer komplexeren Berechnung sind und als "Bausteine" der eigentlichen Implementierung dienen.public
sein, da sie ein Implementierungsdetail sind. Sie können nicht private
sein, da sie von den Erweiterungsklassen aufgerufen werden sollten. Sie können auch keine "Standardsicht" haben, da sie für die Erweiterungsklassen in anderen Paketen nicht zugänglich sind.(EDIT: Man könnte davon ausgehen, dass der ursprüngliche Kommentar sich nur aufFelder und nicht auf Methoden bezog - dann war es jedoch zu allgemein)
Statische Member werden nicht vererbt und geschützte Member sind nur für Unterklassen sichtbar (und natürlich für die enthaltende Klasse). Daher hat ein protected static
dieselbe Sichtbarkeit wie static
, was auf ein Missverständnis durch den Codierer schließen lässt.
Eigentlich ist mit protected static
nichts grundlegend falsch. Wenn Sie wirklich eine statische Variable oder Methode wünschen, die für das Paket und alle Unterklassen der deklarierenden Klasse sichtbar ist, machen Sie es mit protected static
.
Einige Leute verwenden generell protected
aus verschiedenen Gründen nicht, und manche Leute meinen, nicht endestatic
-Variablen sollten unter allen Umständen vermieden werden (ich persönlich sympathisiere bis zu einem gewissen Grad), also denke ich, dass die Kombination von protected
und static
aussehen muss schlecht ^ 2 zu denen, die zu beiden Gruppen gehören.
Protected wird verwendet, damit es in Unterklassen verwendet werden kann. Es gibt keine Logik beim Definieren einer geschützten Statik, wenn im Kontext konkreter Klassen verwendet wird, da Sie auf dieselbe Variable zugreifen können. Dies geschieht auf statische Weise. Der Complier gibt jedoch eine Warnung aus, um auf die statische Superklasse-Variable statisch zuzugreifen.
Nun, wie die meisten Leute geantwortet haben:
protected
bedeutet - ' package-private + Sichtbarkeit für Unterklassen - Die Eigenschaft/das Verhalten ist INHERITED 'static
bedeutet - ' das Gegenteil von Instanz - es handelt sich um eine CLASS-Eigenschaft/ein Verhalten, d. h. es ist NICHT INHERITIERT 'Daher sind sie etwas widersprüchlich und inkompatibel.
Vor kurzem kam ich jedoch zu einem Anwendungsfall, bei dem es sinnvoll sein könnte, diese beiden zusammen zu verwenden. Stellen Sie sich vor, Sie möchten eineabstract
-Klasse erstellen, die eine übergeordnete Klasse für immutable types ist, und eine Reihe von Eigenschaften aufweist, die den Untertypen gemeinsam sind. Um Unveränderlichkeit richtig zu implementieren und Lesbarkeit zu erhalten könnte man sich für die Verwendung des Builder - Musters entscheiden.
package X;
public abstract class AbstractType {
protected Object field1;
protected Object field2;
...
protected Object fieldN;
protected static abstract class BaseBuilder<T extends BaseBuilder<T>> {
private Object field1; // = some default value here
private Object field2; // = some default value here
...
private Object fieldN; // = some default value here
public T field1(Object value) { this.field1 = value; return self();}
public T field2(Object value) { this.field2 = value; return self();}
...
public T fieldN(Object value) { this.fieldN = value; return self();}
protected abstract T self(); // should always return this;
public abstract AbstractType build();
}
private AbstractType(BaseBuilder<?> b) {
this.field1 = b.field1;
this.field2 = b.field2;
...
this.fieldN = b.fieldN;
}
}
Und warumprotected static
? Weil ich möchte, dass ein nicht abstrakter Untertyp von AbstactType
, der seinen eigenen nicht abstrakten Builder implementiert und sich außerhalb von package X
befindet, auf die BaseBuilder
zugreifen und diese wiederverwenden kann.
package Y;
public MyType1 extends AbstractType {
private Object filedN1;
public static class Builder extends AbstractType.BaseBuilder<Builder> {
private Object fieldN1; // = some default value here
public Builder fieldN1(Object value) { this.fieldN1 = value; return self();}
@Override protected Builder self() { return this; }
@Override public MyType build() { return new MyType(this); }
}
private MyType(Builder b) {
super(b);
this.fieldN1 = b.fieldN1;
}
}
Natürlich können wir die BaseBuilder
öffentlich machen, aber dann kommen wir zu anderen widersprüchlichen Aussagen:
Also in beiden Fällen mitprotected static
undpublic
BUILDER EINES abstract class
kombinieren wir widersprüchliche Anweisungen. Es geht um persönliche Vorlieben.
Ich bevorzuge jedoch immer noch denpublic
-BUILDER EINES abstract class
, weil derprotected static
mir in einer OOD- und OOP - Welt unnatürlicher vorkommt!
Es ist nichts falsch mit protected static
. Eine Sache, die viele Leute übersehen, ist, dass Sie Testfälle für statische Methoden schreiben möchten, die Sie unter normalen Umständen nicht zeigen möchten. Ich habe festgestellt, dass dies besonders nützlich ist, um Tests für statische Methoden in Dienstprogrammklassen zu schreiben.