Jede Klasse wird automatische in eine .class gepackt. Du solltest (einfach weil es sauber ist) für jede öffentliche Klasse auch immer eine eigene Datei verwenden (was anderes erlaubt Java auch gar nicht!). Mehrere Klassen in einer Datei macht keine Sinn. Zusammengehörigkeit sollte man ja durch das
package erzeugen.
Was dein Problem angeht, so weiß ich nicht genau was du mit
Options[0] := './HelloWorld.class';
genau erreichen willst.
Ich glaube da kommen wir nicht um ein wenig mehr Theorie zur Vorgehensweise rum. Ich hoffe ich kann es halbwegs verständlich (und korrekt) erklären. Java läuft wie gesagt immer plattform-unabhängig in der virtuellen Maschine. Diese Virtuelle Maschine muss einmal für jede Plattform entwickelt werden, die Java unterstützen soll. Der Vorteil ist halt, dass du nur ein Programm (die virtuelle Maschine) für die Plattform schreiben musst. Genau genommen musst nicht mal du das tun, für die großen Plattformen macht das SUN.
Du schreibst deine Programme nur einmal und sie laufen überall.
Sprachen wie Delphi, C und C++ sind hingegen Plattformspezifisch. Das stimmt so auch nicht 100%ig. Eine C Datei kann so geschrieben werden, dass man Code für verschiedene Plattformen aus ihr ohne Änderung erzeugen kann, aber wenn sie werden halt für eine Plattform (gegen entsprechende Bibliotheken) gelinkt. Du bekommst halt unter Windows eine .exe. Bei den Unix Derivaten gibt es dann ausführbare Dateien (die Erweiterung ist egal). Bibliotheken unter Windows werden dann in .dlls gelinkt, unter Linux in .so usw. Code der so gelinkt wurde, kann nativ von der entsprechenden Plattform ausgeführt werden.
Die JVM muss wie gesagt mind. einmal für jede Plattform geschrieben werden, die Java unterstützt. Die JVM besteht somit aus nativem Code. JNI ist jetzt eine Java Schnittstelle zur nativen Welt (also der Plattform auf dem die JVM läuft). Code der nativ aufgerufen wird, ist dann auch wirklich an die jeweilige Plattform gebunden!
Die JVM ist jetzt sozusagen ein Vermittler. Java Code für die Virtuelle Maschine wird hier in native Befehle umgesetzt. In welche hängt von der Plattform ab, aber du musst dich eben nicht drum kümmern. Das Java Native Interface funktioniert jetzt aber in Beide Richtungen. Das heißt wenn du nativen Code in Java verwenden möchtest, wird der halt in der anderen Richtung umgewandelt.
Du hast also etwas wie NATIV <--> JVM <--> Java Code
Alles was gemacht wird, läuft also immer über die JVM.
In deinem Fall ist die Native Aussenwelt dein Delphi. Delphi kann nichts mit Java Klassen anfangen und diese nichts mit Delphi. Bei der JVM sieht dass anders aus. Delphi kann hier auf native Schnittstellen zur JVM zugreifen und umgekehrt. Anders gesagt, Delphi kommuniziert jetzt mit der JVM, die arbeitet den Java Code ab und gibt das Ergebnis an Delphi weiter.
Das sind nur grob die Grundlagen, warum du dir eine Instanz der JVM in Delphi holst.
Unter Windows kennst du sicherlich Pfade. Der Suchpfad PATH z.B. enthält alle Ordner, die nach Anwendungen durchsucht werden. Tippst du einen Befehl auf der Konsole ein, so gibt es drei Möglichkeiten:
1) Er liegt im aktuellen Verzeichnis und wird ausgeführt
2) Windows findet ihn im Suchpfad und er wird ausgefürht
3) er wird nicht gefunden
Das Windows einen solchen Suchpfad kennt ist zwar schön, hat aber wenig zu bedeuten. Einerseits soll ja Java auf allen Plattformen lauffähig sein (nicht jede muss einen Suchpfad haben) und ausserdem muss Java nur die Lage von .class und .jar Dateien kennen. Die kann Windows (oder eine andere Plattform) aber nicht ausführen. Also würde ein Suchpfad unnötig groß werden. Die Lösung ist einfach, die JVM schafft sich ihren eigenen Suchpfad. Dieser wird halt treffender Weise mit ClassPath bezeichnet. Du kannst den entweder global für deine jeweilige Plattform setzen oder als Argument beim Start mitgeben. Alle Klassen auf die Java zugreifen können soll, müssen im Classpath bekannt gemacht werden. Du kannst entweder alle Klassen einzeln angeben oder sie in ein .jar packen und dieses in den ClassPath einfügen.
Steht eine Klasse nicht im Pfad, kann sie nicht gefunden werden. Ohne Angabe eines ClassPath wird (denke ich) die JVM nur im aktuellen Ordner (in ihrem Fall das bin Verzeichnis des JRE) nachschauen. Liegt hier keine .class, pech.
So, damit wären wir auch schon bei deinem Aufruf. Hoffe hab dich nicht schon jetzt gelangweilt, ein klein wenig kommt noch. Dein Delphi Programm möchte auf Java-Code zugreifen, muss also den Weg über die Schnittstelle JNI gehen. Dies tust du, indem du dir eine Instanz der JVM holst. Wo diese Instanz genau herkommt weißt du eigentlich nicht so recht (rein aus Delphi Sicht). Die Frage ist, ob du es wissen musst. Eigentlich nein!
Hast du die Java-Datei, die du ausführen möchtest, so kennst du auch ihren Pfad. Damit kannst du den einfach bekannt machen. Den Klassenpfad machst du der JVM bei ihrem Start bekannt. Hierzu musst einfach -Djava.class.path=<ClassPathEintrag> als Option mit an die JVM geben. Du solltest dich da echt an das Bsp. von der Seite 2 halten! Gibst du nur einen Klassennamen an, weiß die JVM nichts damit anzufangen.
Klar, sie könnte die Klasse einfach einmal ausführen und fertig. Aber das möchtest du ja nicht, du möchtest ja, dass Delphi mit dieser Klasse kommunizieren kann.
Diese Option solltest du also übergeben. Dann weiß die JVM, dass es eine solche Klasse im Suchpfad gibt.
Hast du die JVM in Delphi gestartet, holst du dir von der jetzt einen Zugriff auf das JNI. Dies ist die Brücke über die nativ (Delphi) mit Java kommuniziert. Du holst dir eine Instanz von TJNIEnv. Über diese Instanz finden dann die Aufrufe statt (und werden entsprechend übersetzt).
Alles was du nun machst entspricht so ziemlich dem, was du in den JNI Texten von Sun findest. Du hast natürlich statt C eine Delphi Kapselung, aber im Prinzip tust du das gleiche.
Mittels FindClass kannst du dir die Klasse die du aufrufen möchtest zurückgeben lassen. Hierbei sucht das JNIEnv einfach im Classpath der JVM nach der entsprechenden Klasse und liefert dir eine Adresse über die du sie erreichst. Hast du eine Klasse, kannst du in dieser wiederum nach Methoden und Variablen suchen. Du bekommst (unter C zumindest) immer eine ID, die du für den entsprechenden Aufruf mit angeben musst. Wichtig ist hier immer zu schauen, dass du eine gültige Adresse bekommst.
Wie das konkret für Delphi aussieht müsste auch ich erst nachlesen, denke aber das findest du schon!
Grob gibt es halt die JNI Seiten von Sun an denen du dich orientieren kannst. Da werden Beispiele zwar in C (ausser man hat es geändert) angegeben, was die Syntax nicht sehr Delphi ähnlich macht, aber verstehen wirst du die schon!
env* entspricht dann halt deiner Klasse TJNIEnv, ähnlich leicht sind andere Entsprechungen zu erkennen. Die Signatur der Methoden kann natürlich in der Delphi Kapselung exakt der von JNI entsprechen oder (da es eine Kapselung ist) auch abweichen. Deswegen möchte ich hier erstmal nichts falsches sagen.
Hoffe du hast grob verstanden warum du wirklich den Klassenpfad setzten musst und nicht den Namen einer Datei angeben reicht.