Warum erlaubt Java nicht die Verwendung von Headern wie in C ++?

18

Ich habe eine Frage, auf die ich keine Antwort gefunden habe, mit Ausnahme der folgenden Antwort, die nicht meinen Anforderungen entspricht:

"Weil James Gosling nicht wollte"

Ich weiß, dass Java Schnittstellen haben kann (nur reine virtuelle Funktionen, keine Attribute), aber es ist nicht genau dasselbe wie Klassendefinitionen.

Etienne Noël
quelle
14
Was ist der Grund, warum du sie willst?
19
Um mehr Zeit für Schwertkämpfe zu haben;)
dan04
6
Ich nehme an, die meisten C ++ - Entwickler würden es lieben, die 40 Jahre alte Textersetzungs-Engine loszuwerden, die Hunderte von kLoC für jede CPP-Datei dupliziert, was zu langen Kompilierzeiten in C ++ führt. Tatsächlich wurde ein geeignetes Modulsystem für C ++ 11 in Betracht gezogen, das jedoch aus Zeitgründen eingestellt wurde. Ich nehme an, es wird jedoch wieder auftauchen.
sbi
Ich nehme an, es wird jedoch wieder auftauchen. Tatsächlich hat die WG21 (ISO C ++ - Arbeitsgruppe) eine Arbeitsgruppe, die sich ausschließlich mit der Bewertung / Weiterentwicklung des Konzepts "Module" befasst: SG2 "Module". Schade , dass es die aktuelle Status ist ruhend .
Max Truxa

Antworten:

46

Die folgende Antwort entspricht nicht meinen Anforderungen: "Weil James Gosling es nicht wollte."

Das ist jedoch die richtige Antwort. Das Sprachdesign-Team (Gosling, Sheridan, Naughton, später Bill Joy, Ken Arnold usw.) entschied, dass Header mehr Probleme verursachten, als sie lösten . Also haben sie sie entworfen und gezeigt, dass sie eine vollkommen nützliche Sprache schaffen können, ohne dass sie benötigt werden.

In Abschnitt 2.2.1 des Java Language Environment-Whitepapers heißt es :

In Java geschriebener Quellcode ist einfach. Es gibt keinen Präprozessor, kein #define und verwandte Funktionen, kein typedef, und ohne diese Funktionen sind keine Header-Dateien mehr erforderlich. Anstelle von Header-Dateien enthalten Java-Quelldateien die Definitionen anderer Klassen und deren Methoden.

Redundante Definitionen, Synchronisierung von Dateien, Konflikte mit Definitionen und versteckte Definitionen - keine davon tritt in Java auf, da Sie keine Header haben. Wenn Sie eine bloße Klassendefinition anzeigen möchten, können Sie diese direkt aus einer .java-Datei generieren - z. B. zeigen die meisten IDEs die Struktur einer Klasse in einer Seitenleiste an, was auf dasselbe hinausläuft.

Alex Feinman
quelle
6
Vielen Dank für Ihre Antwort. Die Header verursachten aus diesem Grund weitere Probleme: Redundante Definitionen, Synchronisierung von Dateien, Konflikte mit Definitionen, versteckte Definitionen. Ist das der Grund, warum es nicht erlaubt war?
Etienne Noël
2
Beachten Sie, dass es viele Gespräche über die nächsten Sitzungen des C ++ - Komitees gibt, da sie ein neues "Modul" -System in Betracht ziehen, das ein einfacheres und effizienteres System darstellt als das Einschließen (mit einigen Ähnlichkeiten mit Java-, C # - usw. -Paketen), das jedoch immer noch retro ist -kompatibel mit enthält. Das heißt, dass ein besseres Kompilierungssystem zumindest theoretisch verwendet werden kann, um die C ++ - Kompilierung besser / effizienter zu machen. Ich denke, Gosling hatte recht, und C ++ muss ohnehin einen Weg finden, das Include-System zu reparieren.
Klaim
5
Es ist nicht perfekt verwendbar. Die Java-Build-Systeme können nicht ermitteln, welche Dateien nach einer Codeänderung neu kompiliert werden müssen. Eine IDE bestimmt, welche Dateien eine Codeänderung erfordern, welche jedoch nicht neu kompiliert werden müssen. Wenn sich eine Methodensignatur ändert, die Änderung jedoch mit der alten Signatur kompatibel ist (z. B. Ändern eines Argumenttyps von float in double), ist ein sauberer Build erforderlich, um MethodNotFoundException zu verhindern.
Kevin Cline
1
@kevin: Normalerweise ist es jedoch möglich, einfach alles ohne zu hohe Kosten neu zu erstellen. Im Gegensatz zu C ++ (aber wie fast jeder anderen kompilierten Sprache auf der Erde) dauert das Kompilieren von Java nicht so lange. Eine teilweise Kompilierung ist eine sehr lohnende Optimierung Ihres Entwicklungsworkflows.
Donal Fellows
1
@Donal: Es ist wahr, dass Java ziemlich schnell kompiliert wird, aber ich hasse es zu raten, ob ich eine vollständige Neukompilierung durchführen soll oder nicht. Baut sollte gerade arbeiten, jedes Mal.
Kevin Cline
16

In C ++ besteht keine wirkliche Notwendigkeit, die Klassendefinitionen und Deklarationen in separaten Dateien zu haben. Es bedeutet nur, dass Sie zumindest in den C-Tagen den Code in einem einzigen Scan von oben nach unten analysieren können. Auf Maschinen ohne Direktzugriffsspeicher war dies eine große Sache!

Wenn Sie über Header verfügen, können Sie die Schnittstelle auch in Ihrer Codebibliothek veröffentlichen, indem Sie den Header bereitstellen, ohne den Quellcode preisgeben zu müssen. Leider müssen Sie in C ++ auch die privaten Datenelemente offenlegen, was zu Lösungen wie dem Horror von Pimpl geführt hat .

Es gab Versuche, eine C ++ - Umgebung zu erstellen, in der alles in einer Datenbanktypstruktur gespeichert war und keine Dateien vorhanden waren, die sich jedoch nicht durchsetzten.

Martin Beckett
quelle
Ich weiß das, aber Sie können es zumindest in C ++ und nicht in Java tun. Das war meine Hauptanfrage. Danke für die Antwort.
Etienne Noël
14

Wegen des DRY- Prinzips. In Java sind die Informationen, die zur Verwendung von Klassen in einem Paket (oder einer Klasse) erforderlich sind, in der .class-Datei enthalten. Wenn Sie separate Header-Dateien erstellen, die dieselben Informationen enthalten, müssen Sie diese an zwei Stellen wiederholen.

Jay Elston
quelle
Leider möchten Sie es oft wiederholen - denken Sie an WSDL-Dateien, IDL-Dateien usw. Eine beschreibt die Schnittstelle, die Sie verwenden können, und eine andere Datei enthält die Implementierung. C ++ - Header sind (schlechte) Schnittstellendefinitionen.
gbjbaanb
6

In jeder Sprache - es gibt zwei Stufen zum Erstellen des endgültigen Binärcodes - Kompilieren und Verknüpfen (natürlich wird geladen, aber das hat hier keine großen Auswirkungen). Zum Zeitpunkt des Kompilierens braucht man nur Hooks (die Spezifikation der Funktionen, die aufgerufen werden) an die entsprechende Stelle zu setzen. Linker tritt tatsächlich bei sie , wenn beide echten Codes verfügbar sind. Bisher gibt es keinen Unterschied zwischen C ++ und Java.

Es ist jedoch ein Bedarf für C ++ haben Deklaration und Definition getrennt. Wenn Sie die Implementierung im Header beibehalten und die Headerdatei ändert, muss der damit verknüpfte Code neu kompiliert werden. Wenn sich die Definition in einer separaten Datei befindet, muss der Code nur erneut verknüpft werden.

Verstehen Sie, dass C ++ die Option hat, statisch zu sein Verknüpfungen verfügt, die impliziert, dass der Objektcode zusammen mit der aufrufenden Anwendung korrigiert wird. Bitte beachten Sie, dass es sowohl in C als auch in C ++ nicht ungültig ist, in der Header-Datei zu programmieren oder sogar #include zu verwenden. Es bedeutet nur, dass Sie sich Gedanken darüber machen müssen, wie die Verknüpfung mit diesen Objektdateien erfolgt.

Die Situation in Java ist sehr unterschiedlich. Jede Klassendatei wird mit einer .class-Datei kompiliert. In der Tat die Notwendigkeit der Kompilierung von Aufruferklassenfunktionen, die als Header-Abschnitt in der .class-Datei dienen. In Java erfolgt die endgültige Verknüpfung jedoch nur innerhalb der Runtime (der virtuellen Maschine), wenn der Bytecode der Klassendatei angegeben ist.

Sieh dies und das

Dipan Mehta
quelle
4

Tatsächlich sind die Schnittstellen und Includes die Header. Die Definitionen sind daher identisch mit den Binärdateien und können nicht synchron sein. Dies ist eine der besten Entwurfsentscheidungen in Java, aber es ist ein kleines Ärgernis, dass es keine Möglichkeit gibt, diese Deklarationen für Kompaktheit und Konsistenz zu bündeln.

ddyer
quelle
1

Ein guter Grund für Includes ist, den Code, den Sie möglicherweise wiederverwenden möchten (z. B. allgemeine Definitionen), von dem Code zu trennen, der für ein bestimmtes Projekt spezifisch ist. Java möchte, dass Sie nur eine Klasse oder Schnittstelle pro Datei angeben, und dies reduziert größtenteils den Bedarf an eingeschlossenen Headern - denn Sie werden die gemeinsam genutzten Teile bereits in ihren eigenen Dateien speichern.

Außerdem möchten Compiler und Buildsysteme möglicherweise vorkompilierte Header zwischenspeichern, um zu vermeiden, dass sie mehrmals analysiert werden.

rbanffy
quelle
1
Ich nehme an, Sie könnten die Schnittstellen in einem freigegebenen Projekt speichern und dann in unabhängigen Projekten implementieren
Alexander Mills,