Der Hauptzweck des Ausblendens von Informationen besteht darin, sie von der Systemkonfiguration zu trennen, damit sie unabhängig voneinander entwickelt, getestet, optimiert, verstanden und geändert werden können.
Der Zugriff auf Klassen ist nur öffentlich oder paketprivat (kein Zugriffsmodifikator).
Wenn eine paketprivate Klasse nur von einer Klasse aufgerufen wird, sollten Sie in Betracht ziehen, sie zu einer privaten statischen verschachtelten Klasse zu machen, um die Wahrscheinlichkeit eines Zugriffs zu verringern.
Ab Java9 wird das Modulsystem als Zugriffskontrollmechanismus übernommen.
Point.java usw. in der Klasse java.awt hat öffentlichen Zugriff auf Feldvariablen, aber es scheint, dass dies aufgrund von Leistungsproblemen erfolgt.
Wenn es sich um eine unveränderliche Feldvariable handelt, gibt es wenig Schaden, selbst wenn sie öffentlich ist, aber es ist besser, sie zu stoppen.
Unveränderliche Klassen sind einfacher zu entwerfen, zu verwenden und zu implementieren als variable Klassen.
Befolgen Sie beim Erstellen einer unveränderlichen Klasse die folgenden 5 Regeln.
Geben Sie keine Methoden an, die den Status von Objekten ändern
Machen Sie es unmöglich zu erben
Machen Sie alle Felder endgültig
Machen Sie alle Felder privat
Verhindern Sie den Zugriff auf variable Klassen
Unveränderliche Klassen sind threadsicher und erfordern keine Synchronisation.
Der Nachteil unveränderlicher Klassen besteht darin, dass sie separate Objekte für unterschiedliche Werte erstellen, was kostspielig ist. Die Lösung hierfür ist die Companion-Klasse. Ein spezielles Beispiel ist die variable Klasse StringBuilder, die der unveränderlichen Klasse String entspricht.
Um die unveränderliche Klasse nicht zu erben, gibt es eine Methode zum öffentlichen Erstellen einer Factory-Methode mit dem Konstruktor, der so privat ist wie eine andere Methode als das Hinzufügen des endgültigen Modifikators zur Klasse.
Als BigInteger und BigDecimal implementiert wurden, war nicht bekannt, dass unveränderliche Klassen nicht vererbt werden sollten, sodass eine Vererbung möglich ist.
In der Regel sollte das Feld ein privates Finale sein, um der unveränderlichen Klasse so nahe wie möglich zu kommen. (CountDownLatch ist ein gutes Beispiel)
Es ist gefährlich, eine konkrete Klasse paketübergreifend zu erben. Es gibt zwei mögliche Probleme:
Superclass-Implementierungen können sich von Release zu Release ändern. Unterklassen müssen möglicherweise entsprechende Änderungen vornehmen.
Es scheint, dass es zu einer Sicherheitslücke werden kann, wenn der Superklasse eine neue Methode hinzugefügt wird. (** Es kommt überhaupt nicht **)
Um eine Vererbung zu vermeiden, kann dies realisiert werden, indem eine Klasse, die ursprünglich als Oberklasse gedacht war, als privates Endfeld (Komposition) importiert und in jeder Methode auf die Methode des importierten Felds verwiesen wird (Weiterleitung).
Der Nachteil von ↑ ist, dass es nicht für das Callback-Framework geeignet ist. Umschlossene Objekte wissen nicht, welche umschlossen sind, daher können sie keine Unterklassenaufrufe mit Verweisen auf sich selbst tätigen.
B erweitert A sollte vermieden werden, es sei denn, die Beziehung B ist ein A, das wirklich gilt. Dies ist nicht durch die Java-Plattformbibliothek geschützt, und Stack ist kein Vektor. Daher sollte Stack nicht von Vector erben, ebenso wie die Beziehung zwischen Eigenschaften und HashList.
Für überschreibbare Methoden müssen Sie Ihre eigene Verwendung schreiben. Die Javadoc-Annotation dafür lautet @implSpec.
Im Allgemeinen beschreibt eine gute API, was zu tun ist und nicht, wie es zu tun ist. Sie wird jedoch beschrieben, da detaillierte Spezifikationen für eine sichere Vererbung erforderlich sind.
Die einzige Möglichkeit, das Design der geerbten Klasse zu testen, besteht darin, eine Unterklasse zu erstellen und zu testen. Wenn Sie eine weit verbreitete Bibliothek anstreben, ist diese nach der Freigabe einer geschützten Methode nahezu unveränderlich. Erstellen Sie daher vor der Freigabe eine Unterklasse und überprüfen Sie sie.
Rufen Sie keine Methoden auf, die im Konstruktor unterstützt werden können. Dies liegt daran, dass die Verarbeitung des Oberklassenkonstruktors immer ausgeführt wird, bevor die Verarbeitung des Unterklassenkonstruktors ausgeführt wird. "Es gibt jedoch eine Verarbeitung wie die Initialisierung von Unterklassenfeldern im Unterklassenkonstruktor, und die überschriebene Methode hat dieses Feld verwendet. Im Fall von "Durchführen der Verarbeitung", um nicht intuitives Verhalten zu zeigen.
Grundsätzlich sollten Serializable und Clonable nicht in der Klasse implementiert werden, die als Vererbungsquelle konzipiert ist. In unvermeidbaren Fällen sollten jedoch die Methoden verwendet werden, die in der readObject-Methode und der clone-Methode überschrieben werden können. Ruf nicht an. Wenn Sie es aufrufen, kann es vorkommen, dass Sie kein Klonobjekt erstellt haben, aber versuchen, Änderungen daran vorzunehmen.
Es ist einfach, eine vorhandene Klasse zu ändern, um eine neugeborene Schnittstelle zu implementieren.
Die Oberfläche eignet sich hervorragend zum Definieren von Mixins.
Was ist Mixin? Code, der nicht unabhängig arbeiten soll (Code, den Sie wiederverwenden möchten), wird im Voraus definiert und bei Bedarf in die Klasse gemischt (implementiert in Java), um den Prozess wiederzuverwenden. Es ist ein Mechanismus zur Förderung.
https://ja.wikipedia.org/wiki/Mixin
http://equj65.net/tech/java8mixin/
Was ist eine nicht primitive Schnittstellenmethode?
Es gibt eine Skelettimplementierungsklasse, die die Vorteile der Schnittstelle und die Vorteile abstrakter Klassen verbirgt. Die Skeleton-Implementierungsklasse heißt AbstractInterface und entspricht AbstractCollection und AbstractSet of CollectionsFW. (Ursprünglich sollten diese SkeletalCollection, SkeletalSet genannt werden, aber dies wird üblicherweise so genannt.)
Die Skeleton-Implementierungsklasse wurde entwickelt, um einige der von der implementierten Schnittstelle bereitgestellten Methoden zu überschreiben und den Rest der Methoden in Klassen zu überschreiben, die von der Skeleton-Implementierungsklasse erben. Ohne diese Skeleton-Implementierungsklasse müsste der Implementierer die Schnittstelle direkt implementieren und alle bereitgestellten Methoden überschreiben, aber durch das Einfügen der Skeleton-Implementierungsklasse werden die Methoden reduziert, die der Implementierer überschreiben sollte (falsch). Das Risiko eines Überschreibens wird ebenfalls verringert. ** Ist es in Ordnung zu verstehen, dass dies ein Vorteil ist? ** ** **
Es besteht das Risiko, einer vorhandenen Schnittstelle eine Methode hinzuzufügen.
Als Beispiel wurde removeIf als Standardmethode zur Sammlung hinzugefügt. Wenn diese removeIf jedoch in der SynchronizedCollection der Apache Commons-Bibliothek aufgerufen wird, die die Sammlung implementiert, wird sie als nicht synchronisierte Methode aufgerufen, wodurch die Konvention für die Verwendung von SynchronizedCollection verletzt wird. Getan werden. Die Java-Bibliothek überschreibt die removeIf-Methode in Collections.synchronizedCollection, um dies zu verhindern.
Sie sollten keine konstante Schnittstelle erstellen, die nur Konstanten definiert. java.io.ObjectStreamConstants macht es, aber es sollte nicht nachgeahmt werden. Der Grund unten.
Sie müssen weiterhin implementieren, um die Binärkompatibilität aufrechtzuerhalten, auch wenn Sie keine Konstanten mehr benötigen. (** Binärkompatibilität ?? **)
Implementiert eine konstante Schnittstelle, die den Namespace verschmutzt.
Eine andere rationale Art, Konstanten zu definieren, ist:
Wenn der von Ihnen definierte Wert eng mit einer vorhandenen Klasse verknüpft ist, fügen Sie ihn dort hinzu.
Konstante Verwenden Sie Enum, wenn es am besten ist, die definierten Werte aufzulisten.
Verwenden Sie andernfalls die Utility-Klasse.
// Constant utility class
public interface PhysicalConstants {
static final double AVOGADROS_NUMBER = 6.02214199e23;
static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
static final double ELECTRON_MASS = 9.10938188e-31;
}
// Use of static import to avoid qualifying constants
import static com.effectivejava.science.PhysicalConstants.*;
public class Test {
double atoms(double mols) {
return AVOGADROS_NUMBER * mols;
}
...
// Many more uses of PhysicalConstants justify static import
Recommended Posts