{"id":4252,"date":"2018-09-25T18:47:44","date_gmt":"2018-09-25T16:47:44","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=4252"},"modified":"2018-09-25T18:47:44","modified_gmt":"2018-09-25T16:47:44","slug":"klassenlader-verbose-class","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2018\/09\/klassenlader-verbose-class\/","title":{"rendered":"Klassenlader"},"content":{"rendered":"<p>Ein Klassenlader ist daf\u00fcr verantwortlich, die Bin\u00e4rrepr\u00e4sentation einer Klasse aus einem Hintergrundspeicher oder Hauptspeicher zu laden. Aus der Datenquelle (im Allgemeinen die .class-Datei) liefert der Klassenlader ein Byte-Array mit den Informationen, die im zweiten Schritt dazu verwendet werden, die Klasse ins Laufzeitsystem einzubringen; das ist Linking. Es gibt vordefinierte Klassenlader und die M\u00f6glichkeit, eigene Klassenlader zu schreiben, um etwa verschl\u00fcsselte vom Netzwerk zu beziehen oder komprimierte .class-Dateien aus Datenbanken zu laden.<\/p>\n<h3>Klassenladen auf Abruf<\/h3>\n<p>Nehmen wir zu Beginn ein einfaches Programm mit drei Klassen:<\/p>\n<p>package com.tutego.insel.tool;<\/p>\n<p>&nbsp;<\/p>\n<p>public class <strong>HambachForest<\/strong> {<\/p>\n<p>public static void main( String[] args ) {<\/p>\n<p>boolean rweWantsToCutTrees = true;<\/p>\n<p>Forrest hambachForest = new Forrest();<\/p>\n<p>if ( rweWantsToCutTrees ) {<\/p>\n<p>Protest&lt;Forrest&gt; p1 = new Protest&lt;&gt;();<\/p>\n<p>p1.believeIn = hambachForest;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>class <strong>Forrest<\/strong> { }<\/p>\n<p>&nbsp;<\/p>\n<p>class <strong>Protest<\/strong>&lt;T&gt; {<\/p>\n<p>T believeIn;<\/p>\n<p>java.time.LocalDate since;<\/p>\n<p>}<\/p>\n<p>Wenn die Laufzeitumgebung das Programm HambachForest startet, muss sie eine Reihe von Klassen laden. Das tut sie dynamisch zur Laufzeit. Sofort wird klar, dass es zumindest HambachForest sein muss. Und da die JVM die statische main(String[])-Methode aufruft und Optionen \u00fcbergibt, muss auch String geladen sein. Unsichtbar stecken noch andere referenzierte Klassen dahinter, die nicht direkt sichtbar sind. So wird zum Beispiel Object geladen, da implizit in der Klassendeklaration von HambachForest steht: class HambachForest extends Object. Intern ziehen die Typen viele weitere Typen nach sich. String implementiert Serializable, CharSequence und Comparable, also m\u00fcssen diese drei Schnittstellen auch geladen werden. Und so geht das weiter, je nachdem, welche Programmpfade abgelaufen werden. Wichtig ist aber, zu verstehen, dass diese Klassendateien so sp\u00e4t wie m\u00f6glich geladen werden.<\/p>\n<h3>Klassenlader bei der Arbeit zusehen<\/h3>\n<p>Im Beispiel l\u00e4dt die Laufzeitumgebung selbstst\u00e4ndig die Klassen (implizites Klassenladen). Klassen lassen sich auch mit Class.forName(String) \u00fcber ihren Namen laden (explizites Klassenladen).<\/p>\n<p>Um zu sehen, welche Klassen \u00fcberhaupt geladen werden, l\u00e4sst sich der virtuellen Maschine beim Start der Laufzeitumgebung ein Schalter mitgeben: -verbose:class. Dann gibt die Maschine beim Lauf alle Typen aus, die sie l\u00e4dt. Nehmen wir das Beispiel von eben, so ist die Ausgabe mit dem aktivierten Schalter unter Java 11 fast 500 Zeilen lang; ein Ausschnitt:<\/p>\n<p>$ <strong>java -verbose:class com.tutego.insel.tool.HambachForest<\/strong><\/p>\n<p>[0.010s][info][class,load] opened: C:\\Program Files\\Java\\jdk-11\\lib\\modules<\/p>\n<p>[0.032s][info][class,load] java.lang.Object source: jrt:\/java.base<\/p>\n<p>[0.032s][info][class,load] java.io.Serializable source: jrt:\/java.base<\/p>\n<p>[0.033s][info][class,load] java.lang.Comparable source: jrt:\/java.base<\/p>\n<p>[0.036s][info][class,load] java.lang.CharSequence source: jrt:\/java.base<\/p>\n<p>[0.037s][info][class,load] java.lang.String source: jrt:\/java.base<\/p>\n<p>\u2026<\/p>\n<p>[0.684s][info][class,load] sun.security.util.Debug source: jrt:\/java.base<\/p>\n<p>[0.685s][info][class,load] com.tutego.insel.tool.<strong>HambachForest<\/strong> source: file:\/C:\/Inselprogramme\/target\/classes\/<\/p>\n<p>[0.687s][info][class,load] java.lang.PublicMethods$MethodList source: jrt:\/java.base<\/p>\n<p>[0.687s][info][class,load] java.lang.PublicMethods$Key source: jrt:\/java.base<\/p>\n<p>[0.689s][info][class,load] java.lang.Void source: jrt:\/java.base<\/p>\n<p>[0.690s][info][class,load] com.tutego.insel.tool.<strong>Forrest<\/strong> source: file:\/C:\/Inselprogramme\/target\/classes\/<\/p>\n<p>[0.691s][info][class,load] jdk.internal.misc.TerminatingThreadLocal$1 source: jrt:\/java.base<\/p>\n<p>[0.692s][info][class,load] java.lang.Shutdown source: jrt:\/java.base<\/p>\n<p>[0.692s][info][class,load] java.lang.Shutdown$Lock source: jrt:\/java.base<\/p>\n<p>\u00c4ndern wir die Variable rweWantsToCutTrees auf true, so wird unsere Klasse Protest geladen, und in der Ausgabe kommt nur eine Zeile hinzu! Das wundert auf den ersten Blick, denn die Klasse referenziert LocalDate. Doch ein LocalDate wird nicht ben\u00f6tigt, also auch nicht geladen. Der Klassenlader bezieht nur Klassen, wenn die f\u00fcr den Programmablauf ben\u00f6tigt werden, nicht aber durch die reine Deklaration als Attribut. Wenn wir LocalDate mit zum Beispiel LocalDate.now() initialisieren kommen stattliche 200 Klassendateien hinzu.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ein Klassenlader ist daf\u00fcr verantwortlich, die Bin\u00e4rrepr\u00e4sentation einer Klasse aus einem Hintergrundspeicher oder Hauptspeicher zu laden. Aus der Datenquelle (im Allgemeinen die .class-Datei) liefert der Klassenlader ein Byte-Array mit den Informationen, die im zweiten Schritt dazu verwendet werden, die Klasse ins Laufzeitsystem einzubringen; das ist Linking. Es gibt vordefinierte Klassenlader und die M\u00f6glichkeit, eigene Klassenlader [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[11],"tags":[],"class_list":["post-4252","post","type-post","status-publish","format-standard","hentry","category-insel"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/4252","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=4252"}],"version-history":[{"count":1,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/4252\/revisions"}],"predecessor-version":[{"id":4253,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/4252\/revisions\/4253"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=4252"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=4252"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=4252"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}