jar-Bibliotheken

jar-Bibliotheken

Ausgangslage

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---l        19.01.2025     13:24            216 Greeter.java
-a---l        19.01.2025     13:24            283 Main.java
-a---l        19.01.2025     13:38            370 Pythagoras.java

Kompilieren wir einfach mal Pythagoras.java.

>> javac Pythagoras.java


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---l        19.01.2025     13:24            216 Greeter.java
-a---l        19.01.2025     13:24            283 Main.java
-a---l        19.01.2025     13:38            453 Pythagoras.class
-a---l        19.01.2025     13:38            370 Pythagoras.java

Man sieht, dass ohne Probleme Pythagoras.class entsteht. Da kann man auch mal reinschaun - obwohl es erstmal nicht so super hilfreich ist.

>> cat Pythogoras.class
>> javap -c Pythagoras

Was nicht klappt: Das Ausführen der class-Datei:

>> java Pythagoras

Fehler: Hauptmethode in Klasse Pythagoras nicht gefunden. Definieren Sie die Hauptmethode als:
   public static void main(String[] args):
oder eine JavaFX-Anwendung muss javafx.application.Application erweitern

Kompilieren der main

Es fehlt eine main - also schnell Main.java kompilieren

>> javac Main.java


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---l        19.01.2025     13:48            915 Greeter.class
-a---l        19.01.2025     13:24            216 Greeter.java
-a---l        19.01.2025     13:48            643 Main.class
-a---l        19.01.2025     13:48            285 Main.java
-a---l        19.01.2025     13:38            453 Pythagoras.class
-a---l        19.01.2025     13:38            370 Pythagoras.java

Spannend

  • Auch Greeeter.class ist mitkompiliert worden!
  • Aber Pythagoras.class ist NICHT nochmal kompiliert worden (s. Zeitstempel)

Kompilieren von java und class-Files

Was, wenn einige Dateien nicht als .java vorliegen?

Um das zu simulieren, verschieben wir ein paar java-files in den Ordner temp

 >> mkdir temp
 >> mv Pythagoras.java temp
 >> mv Greeter.java temp
 >> rm Main.class
… und kompilieren dann Main.java.

>> javac Main.java

    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    dar--l        19.01.2025     13:58                temp
    -a---l        19.01.2025     13:48            915 Greeter.class
    -a---l        19.01.2025     13:48            285 Main.java
    -a---l        19.01.2025     13:38            453 Pythagoras.class
Kompilieren ist trotzdem möglich!

Compiler ist sogar happy über bereits fertig kompilierte Klassen.

 >> javac Main.java

    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    dar--l        19.01.2025     13:58                temp
    -a---l        19.01.2025     13:48            915 Greeter.class
    -a---l        19.01.2025     13:59            643 Main.class
    -a---l        19.01.2025     13:48            285 Main.java
    -a---l        19.01.2025     13:38            453 Pythagoras.class
Das ist sogar der Klassiker: Man schreibt eigenen Java-Code, der von bereits fertig kompilierten Klassen abhängig ist

Meist liegen diese fertigen Dateien irgendwo, bsp im Ordner classes

>> rm Main.class
>> mkdir classes
>> mv *.class classes

ClassPath angeben mit -cp

Aber jetzt funktioniert das kompilieren von Main.java nicht mehr, weil die Klassen nicht gefunden werden.

>> javac Main.java

Deshalb muss ich dem Compiler erstmal sagen, wo sich die Klassendateien befinden. Hierfür benutzt man die -cp Option (Class Path).

>> javac -cp classes Main.java

Aber man kann es immer noch nicht ausführen!

>> java Main

Es muss auch hier wieder der classPath angegeben werden…

>> java -cp classes Main
Fehler: Hauptklasse Main konnte nicht gefunden oder geladen werden
Ursache: java.lang.ClassNotFoundException: Main

… und der classPath muss angepasst werden und durch ; (Windows) um das aktülle Verzeichnis erweitert werden.

Vorsicht

Die Erweiterung wird je nach Betriebssystem und Terminal unterschiedlich angegeben. Im Fall von PowerShell verwenden wir das ;. Auch muss der Pfad von Hochkommata " umschlossen werden.

Unter Linux ist es schlicht ein Punkt .

>> java -cp ".;classes" Main
5.0
4.76837158203125
Donald says: Hello World

Classfiles im Archiv .jar (java archive)

Classfiles werden meist nicht einzeln verteilt, sondern gepackt als Archiv.

>> cd classes
...
>> jar cvf library.jar *.class
Manifest wurde hinzugefügt
Greeter.class wird hinzugefügt(ein = 915) (aus = 498)(45 % verkleinert)
Pythagoras.class wird hinzugefügt(ein = 453) (aus = 323)(28 % verkleinert)
...
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---l        19.01.2025     13:48            915 Greeter.class
-a---l        19.01.2025     14:28           1386 library.jar
-a---l        19.01.2025     13:38            453 Pythagoras.class

Mit jar tvf kann man auch in ein .jar hineingucken.

>> jar tvf .\library.jar
     0 Sun Jan 19 14:28:38 CET 2025 META-INF/
    66 Sun Jan 19 14:28:38 CET 2025 META-INF/MANIFEST.MF
   915 Sun Jan 19 13:48:16 CET 2025 Greeter.class
   453 Sun Jan 19 13:38:28 CET 2025 Pythagoras.class

Wir knnen jetzt auch alle .class-files löschen und trotzdem wird der Compiler funktionieren:

>> rm *.class
>> cd ..
>> rm *.class

>> javac -cp classes\library.jar Main.java
>> java -cp ".;classes\library.jar" Main

5.0
4.76837158203125
Donald says: Hello World

jar-Bibliothek für gesamtes Programm

Wie wäre es aber nun, wenn wir das fertige Produkt inklusive der main in solch einer jar-Bibliothek verpacken? So hätten wir doch nur 1 File, das wir problemlos weitergeben könnten?

Antwort lautet: Genau - so machen wir es auch!

Also, hier nochmal die Ausgangslage: Alle java-Files liegen in einem Ordner

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---l        19.01.2025     13:24            216 Greeter.java
-a---l        19.01.2025     13:24            283 Main.java
-a---l        19.01.2025     13:38            370 Pythagoras.java

Mit javac Main.java wird alles kompiliert - als Ergebnis haben wir alle class-Files.

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---l        19.01.2025     19:39            915 Greeter.class
-a---l        19.01.2025     13:24            216 Greeter.java
-a---l        19.01.2025     19:39            643 Main.class
-a---l        19.01.2025     13:48            285 Main.java
-a---l        19.01.2025     19:43             18 manifest.txt
-a---l        19.01.2025     19:39            453 Pythagoras.class
-a---l        19.01.2025     13:38            370 Pythagoras.java

Was hat es mit dieser manifest.txt auf sich?

Werfen wir einen kurzen Blick hinein:

>> cat manifest.txt
Main-Class: Main

In diesem File ist einfach nur definiert, in welcher Klasse sich die main-Methode des gesamten Programms befindet.

Tipp: Am Ende der Zeile muss ein Zeilenumbruch stehen. Ist er nicht da, suchst du dich dumm und dämlich…

Erstellung eines jar-Files

Jetz erstellen wir daraus ein jar-File. Nennen wir es super.jar

>> jar cvfm super.jar manifest.txt *.class

Manifest wurde hinzugefügt
Greeter.class wird hinzugefügt(ein = 915) (aus = 498)(45 % verkleinert)
Main.class wird hinzugefügt(ein = 643) (aus = 442)(31 % verkleinert)
Pythagoras.class wird hinzugefügt(ein = 453) (aus = 323)(28 % verkleinert)

Ausführen der jar

>> java -jar super.jar
5.0
4.76837158203125
Donald says: Hello World

Und am Ende nochmal einen Blick ins jar:

>> jar tvf super.jar

     0 Sun Jan 19 19:53:40 CET 2025 META-INF/
    66 Sun Jan 19 19:53:40 CET 2025 META-INF/MANIFEST.MF
   915 Sun Jan 19 19:39:56 CET 2025 Greeter.class
   643 Sun Jan 19 19:39:56 CET 2025 Main.class
   453 Sun Jan 19 19:39:56 CET 2025 Pythagoras.class