2010-08-15 3 views
12

Gibt es eine Garantie, dass (der Standard, System) Java Klassenlader nicht versucht, Klassen zu laden, die nicht in dem Code ausgeführt werden, der ausgeführt wird? Ein paar Beispiele dafür, was ich meine:Wird sichergestellt, dass der Java-Klassenlader keine nicht verwendeten Klassen lädt?

  • Ich bin ein mit framework.jar, die ich kenne Verweise auf andere library.jar enthalten ‚s Klassen drin, aber ich verwende nur solche Teil des Rahmens, der doesn‘ t enthalten diese Referenzen. Ist es sicher, library.jar zu verlassen?
  • Statische Blöcke werden ausgeführt, wenn eine Klasse zuerst geladen wird. Wenn kein laufender Code Verweise auf eine bestimmte Klasse enthält, ist es sicher, dass der statische Block nicht ausgeführt wird?

Schnell Prüfung scheint es, wie oben angenommen zu arbeiten, und es würde nicht viel Sinn machen ohnehin nicht genutzte Klassen zu laden, aber gibt es keine Garantie dazu?

Addition: Es scheint, dass meine "statische Blöcke ausgeführt werden, wenn eine Klasse zuerst geladen wird" Anweisung oben ist etwas falsch. Es ist definitiv möglich, laden Klassen (eine Sache) ohne läuft sie (eine andere Sache). Also bin ich an beiden Fällen interessiert; Garantien über Klassen nicht erhalten geladen, und nicht bekommen Lauf.

Antwort

7

Es gibt keine solche Garantie beim Laden der Klassen.

Sie können jedoch sicher sein, dass statische Blöcke nicht vorzeitig ausgeführt werden. Die Ereignisse, die die Klasseninitialisierung auslösen, werden in JLS 12.4.1 angegeben. wird

  • T erstellt eine Klasse und eine Instanz von T:

    A-Klasse oder Schnittstelle Typ T unmittelbar vor dem von einem der folgenden ersten Vorkommen initialisiert werden.

  • T ist eine Klasse und eine durch T deklarierte statische Methode wird aufgerufen.
  • Ein von T deklariertes statisches Feld wird zugewiesen.
  • Ein durch T deklariertes statisches Feld wird verwendet und das Feld ist keine konstante Variable (§4.12.4).
  • T ist eine Top-Level-Klasse, und eine in T lexikalisch geschachtelte assert-Anweisung (§14.10) wird ausgeführt.

1 - Es wird beobachtet, dass die aktuelle Generation Java-Implementierungen werden nicht geladen Klassen unnötig, aber das ist keine Garantie. Die einzigen Garantien sind, was es in den offiziellen Spezifikationen geschrieben hat.

1

Ich glaube nicht, dass es eine solche Garantie gibt. Zum einen habe ich Code-Scanner gesehen, die beispielsweise Annotationen aus ganzen Pakethierarchien/JARs während des Anwendungsstarts verarbeiten. Sie würden diese Annahme sofort verletzen.

Warum ist das wichtig?Sie sind in der Regel nach sehr kontrollierbaren System laden, so etwas, wo wäre es wichtig wäre irgendwo, wo Sie es sowieso zwingen wollen ...

1

Die Sache, die Klassen zieht ist die Verweise auf sie von Java-Byte-Code (was wiederum kann ziehen Sie in anderen Klassen). Wenn die von Ihnen ausgeführten Klassen keinen Verweis auf die Klasse X haben, wird sie nicht geladen.

Beachten Sie jedoch, dass es neuere Möglichkeiten gibt, z. Dienstleistungen durch META-INF. Diese Klassen müssen ebenfalls geladen werden.

Sie können immer mit "-verbose" laufen, um die Klassen beim Laden zu sehen - die Reihenfolge zeigt deutlich, dass sie bei Bedarf geladen werden.

+0

AFAIK, hier zählt nicht nur die "Referenz", sondern auch die Verwendung. Solange eine Klasse nicht verwendet wird (d. H. In einem ausführenden Bytecode-Befehl referenziert wird), wird sie nicht geladen. Natürlich ist dies nicht durch die Spezifikation garantiert, aber jede JVM, die sich selbst respektiert, verhält sich so. – sasuke

4

Die Java specification Staaten

Der Ladevorgang wird durch die Klasse Klassenladeprogramm und seine Subklassen implementiert. Verschiedene Unterklassen von ClassLoader kann verschiedene Lade-Richtlinien implementieren. Insbesondere kann ein Klassenlader binäre Darstellungen von Klassen und Schnittstellen zwischenspeichern, sie basierend auf der erwarteten Verwendung vorausholen oder eine Gruppe zusammengehöriger Klassen zusammen laden.

Der Classloader ist also frei, Classfiles vorab zu lesen.

A-Klasse oder Schnittstelle Typ T wird unmittelbar vor dem ersten Auftreten von einem der folgenden initialisiert:

  • T eine Klasse ist, und eine Instanz von T erzeugt wird.
  • T ist eine Klasse und eine durch T deklarierte statische Methode wird aufgerufen.
  • Ein von T deklariertes statisches Feld wird zugewiesen.
  • Ein durch T deklariertes statisches Feld wird verwendet und die Referenz auf das Feld ist keine Kompilierzeitkonstante (§15.28). Verweise auf Kompilierzeitkonstanten müssen zum Zeitpunkt der Kompilierung in eine Kopie des Kompilierzeitkonstantenwerts aufgelöst werden, sodass die Verwendung eines solchen Felds niemals zu einer Initialisierung führt.

Die statischen Blöcke werden nur ausgeführt, wenn die Klasse zum ersten Mal verwendet wird.

+1

+1 für "Prefetch sie auf die erwartete Verwendung, oder laden Sie eine Gruppe von verwandten Klassen zusammen". Es gibt also keine Garantie, nichts zu laden. –

1

Wenn Sie keine Reflektion verwenden, können Sie statisch überprüfen, welche Klassen mit einem Dead-Code-Entfernungstool wie ProGuard verwendet werden. Es analysiert Ihren Code und ermittelt alle verwendeten Klassen. Auf dieser Grundlage entfernt es unbenutzten Code, einschließlich nicht verwendeten Code in Bibliotheken.

Wenn Ihr Code oder Ihre Bibliotheken reflection verwenden, um Klassen zu laden, müssen Sie einen vollständigen Abdeckungstest Ihrer Anwendung durchführen und alle geladenen Klassen protokollieren, die Sie von ProGuard anweisen.

+0

Ich denke, Joonas-Projekt hat eine Abhängigkeit von framework.jar, die eine Abhängigkeit von library.jar hat. Joonas glaubt dennoch, dass sein Projekt nicht von library.jar abhängig ist. Kann ProGuard diese Behauptung wirklich bestätigen? – emory

0

Es gibt keine Garantien, wie andere Poster erwähnt haben. Aber Ihre Frage und Ihr Anliegen folgen nicht voneinander. Damit Sie library.jar nicht verlassen können, brauchen Sie solche Garantien nicht.

Es gibt eine Reihe von Frameworks, die während der Laufzeit das Vorhandensein oder Fehlen anderer Frameworks erkennen.Beispiel: Das Commons-Logging entdeckt eine Menge anderer Frameworks. Der Spring-Web-Flow erkennt während der Laufzeit, was das Scripting-Framework ist (zB OGNL). Diese Frameworks werden offensichtlich mit allen abhängigen Frameworks kompiliert, müssen aber nicht zur Laufzeit existieren.

Daher ist es durchaus akzeptabel, library.jar während der Laufzeit zu verlassen.

0

Ja.

Denken Sie über Folgendes nach. Wenn Sie den folgenden Code zu diesem library.jar Klasse hinzufügen:

public ShutDown {static { System.exit(-1); }} 

Dieser Code wird nicht automatisch vom Standard-System geladen werden, da keines der vorhandenen Code einen Verweis hat oder weiß um die ShutDown Klasse, noch hatte ein Möglichkeit, es zu laden, und der Java-Klasse-Lader nicht einfach herumfahren versuchen, zufällige Klassen aus dem Glas zu laden.

Die Art und Weise Klassen geladen werden, sind in den vorherigen Antworten beschrieben, wenn man sie sorgfältig keiner von ihnen gehören ein überprüfen von einer Art „Wenn es eine Klasse in dem Gefäß ist, wäre es geladen werden“.

+0

Ich denke, dass Sie das Klassenladen und die Klasseninitialisierung zusammenfassen. –

Verwandte Themen