Warum wurde die Thread
Klasse als reguläre Klasse und nicht als abstrakte Klasse implementiert, wobei die run()
Methode abstrakt war?
Wird es möglicherweise Probleme geben? Oder hat es irgendeinen Sinn, so zu sein?
Außerdem soll die Thread.start()
Methode eine sehr spezifische Methode sein, deren Funktionalität von keiner anderen Klasse implementiert werden kann (wenn ich mich nicht irre). Und daher denke ich, dass das final
Schlüsselwort mehr als jede andere Methode dafür geeignet wäre.
Aber ich kann diese Methode überschreiben und verwenden, wie ich möchte.
public class Test extends Thread {
public static void main (String... args) {
Thread test = new Test();
test.start();
}
@Override
public void run() {
System.out.println("New thread started...");
}
@Override
public void start() {
System.out.println("Did anyone tell you I will spawn a new thread??");
}
}
Es wurde offensichtlich nur gedruckt,
Hat dir jemand gesagt, dass ich einen neuen Thread erzeugen werde?
Gibt es eine andere Möglichkeit zum Überschreiben, als den Techniker, der Sie ersetzt, zu verwirren?
Wenn nicht, warum wurde die Methode in der Thread-Klasse nicht als endgültig deklariert?
quelle
Thread
Klasse wäre endgültig. Der Konstruktor verwendet bereits eine ausführbare Datei, sodass zum Erstellen eines Threads keine Vererbung erforderlich ist.Antworten:
Diese Frage läuft darauf hinaus, dass Sie Komposition immer der Vererbung vorziehen sollten.
Wenn die
Thread
Klasse als deklariertabstract
wäre, müsste die Sprache eine andere Klasse bereitstellen, die daraus erweitert wurde und mit der Programmierer eine erstellen könntenThread
. Ihre Frage wäre dann , warum diese Klasse, dieextends
ausThread
nichtabstract
. Wenn die Sprache keine andere Klasse bereitstellen würde , dieextends
von stammtThread
, müssten Programmierer ihre eigene Klasse erstellen, dieextend
vonThread
derrun()
Methode stammt, und diese überschreiben .Die einzig mögliche Erklärung, die ich geben kann, ist, dass die Entwickler der Sprache einige Anwendungsfälle zum Überschreiben gesehen haben,
start
als die Klasse in das JDK eingeführt wurde. Die erste Version von Java, die ich verwendet habe, war 1.5, und ich persönlich bin nicht auf einen Anwendungsfall gestoßen, bei dem ich festgestellt habe, dass eine Überschreibung erforderlich iststart
. Wie JB Nizet in seiner Antwort feststelltequelle
Sie können sich natürlich selbst in den Fuß schießen, aber das bedeutet nicht, dass Sie es müssen.
Da die empfohlene Methode zum Erstellen eines Starts eines Threads nicht darin besteht, Thread zu unterordnen. Die empfohlene Methode besteht darin, a zu definieren
Runnable
und als Argument an den Thread-Konstruktor zu übergeben:Runnable r = new Runnable() { @Override public void run() { ... } }; Thread t = new Thread(r); t.start();
Ja und nein. Sie können die Implementierung von start () nicht durch Ihre eigene Implementierung ersetzen, aber Sie können in start () zusätzliche Dinge tun, wenn Sie möchten:
@Override public void start() { System.out.println("Did anyone tell you I will spawn a new thread??"); super.start(); }
Wenn Java heute von Grund auf neu gestaltet wurde, besteht jedoch eine gute Chance, dass das Design anders ausfällt. Denken Sie daran, dass diese Klasse aus Java 1.0 stammt und weiterhin abwärtskompatibel ist.
quelle
Sind Sie sicher, dass Sie es niemals überschreiben möchten?
Class MyThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { return new Thread(r) { @Override public void start() { LOGGER.info("Starting thread " + this); super.start(); } }; } }
quelle
Ich bin der Meinung, dass ein paar Kalibrierungen für die Antworten veröffentlicht werden sollten:
Nein ! Ich würde nicht. Das ist wie zu sagen: "Sind Sie sicher, dass Sie diese Variable als privat deklarieren möchten?" Denn wenn ich eine Variable, die ich verwende, als öffentlich deklarieren könnte, ohne befürchten zu müssen, dass andere Entwickler meine Entwurfslogik durcheinander bringen könnten, wäre das Codieren ein Kinderspiel. Einer der wichtigsten Zwecke der OOPS-Konzepte für Umfang, Abstraktion, Polymorphismus, Fehlerbehandlung usw. besteht darin, anderen Entwicklern das Design und die Absichten Ihres Codes mitzuteilen. Wie in der Frage ausgeführt, zwingt Sie niemand, wenn Sie die Startmethode überschreiben super.start () verwenden. @Codebender hat eine Startmethode für einen Thread geschrieben, ohne super.start () zu verwenden, und der Compiler hat sich nie beschwert. Es steht ihm also frei, den gesamten Mechanismus des Threading zu brechen, und der Compiler soll ihn einfach passieren lassen? Die Startmethode des Threads stellt sicher, dass die Ausführungsmethode aufgerufen und zum richtigen Zeitpunkt ausgeführt wird! Es ist entscheidend für das Konzept des Einfädelns. Ich würde mich sehr über eine Korrektur freuen, wenn ich hier etwas verpassen würde. 2.
OK, wenn Codebender vom Design her erlaubt ist, Thread zu sublassieren und die Startmethode durcheinander zu bringen. Nach dieser Logik ist es das Design, das sich selbst in den Fuß schießt. Nach einer anderen Aussage (der ich voll und ganz zustimme) ist Runnable der empfohlene Weg. Warum erlauben wir dann der Thread-Klasse überhaupt, den Thread ohne Einschränkungen zu instanziieren? Darauf folgt:
Das unterstützt tatsächlich die Behauptung von Codebender, dass die Startmethode endgültig sein sollte, wenn Sie das sagen .. ^
Der eine Punkt, der gültig ist, wird bereits als Randnotiz erwähnt, ist aber die eigentliche Antwort auf diese Frage
"Rückwärtskompatibilität".
Tatsächlich wurden Verbesserungen sogar erst in JDK 5.0 vorgenommen, als sie viele wichtige Ergänzungen und Erläuterungen zum Java-Parallelitätsmodell enthielten. Wir möchten, dass die Abwärtskompatibilität vollständig unterstützt wird, und deshalb ist die Thread-Klasse immer noch genau so, wie sie zuvor war, obwohl die Runnable-Schnittstelle heutzutage die empfohlene Methode ist.
Auch hier würde ich mich sehr über eine Korrektur freuen, wenn ich etwas verpassen würde.
quelle