Der Java -Debugger JDB
Programmablauf anzeigen
Der Ablauf einer Sequenz läßt sich mit dem zum JDK gehörenden jdb (Java debugger ) anzeigen. Das wird hier am Beispiel der Quelldatei "Main.java" gezeigt. Diese Datei enthält einen Block mit sieben Ausdruckanweisungen.
Main.java
public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.Thread.dumpStack();
java.lang.Thread.dumpStack();
java.lang.Thread.dumpStack(); }}
Die Quelldatei sollte mit der Option "-g" übersetzt werden, damit die für die Ablaufanzeige nötigen Information in die Klassendatei übertragen werden.
Konsole
javac -g Main.java
jdb
Wenn die Klassendatei vorliegt kann der Ablaufanzeiger "jdb" gestartet werden, der anstelle der virtuellen Javamaschine "java" mit dem Klassennamen als Argument aufgerufen wird. Durch die Ausgabe der Aufforderung ">" zeigt er seine Bereitschaft zur Entgegennahme von Kommandos an.
Konsole
jdb Main
Initializing jdb ...
>
"stop" "in" 〈Klasse 〉 '.'
Mit dem stop-in -Kommando kann ein Haltepunkt gesetzt werden. Der Ablauf des Programmes wird dann an dieser Stelle unterbrochen werden, damit weitere Kommandos eingegeben werden können. Durch das Kommando "stop in Main.main" wird ein Haltepunkt am Anfang der Methode "Main.main" (also am Anfang des Blocks von "Main.java") gesetzt. Das bedeutet, daß die Ausführung des Programms an der Stelle des Haltepunktes unterbrochen werden wird und weitere Kommandos eingegeben werden können.
Konsole
> stop in Main.main
Deferring breakpoint Main.main.
It will be set after the class is loaded.
>
"run"
Das Kommando "run" startet die Ausführung der beim Aufruf des Programmes angegebenen Klasse. Dabei wird der noch vor der ersten Ausdruckanweisung liegende Haltepunkt erreicht und das Programm fordert mit der Ausgabe "main[1] " zur Eingabe weiterer Kommandos auf. Die erste Ausdruckanweisung wurde also bisher noch nicht ausgeführt.
Die nächste zur Ausführung anstehende Anweisung erscheint unter der mit dem Text "Breakpoint hit" beginnenden Zeile.
Konsole
> run
run Main
>
VM Started: Set deferred breakpoint Main.main
Breakpoint hit: "thread=main", Main.main(), line=3 bci=0
3 { java.lang.Thread.dumpStack();;
main[1]
"next"
Durch das Kommando "next" kann die zuvor angezeigte Zeile nun ausgeführt werden. Da hier mehrere Anweisungen in einer Zeile gleichzeitig ausgeführt werden würden, kann es zur Benutzung der Ablaufanzeige hilfreich sein, nur höchstens eine Anweisung pro Zeile zu verwenden.
Konsole
main[1] next
> ...
Step completed: "thread=main", Main.main(), line=4 bci=8
4 java.lang.Thread.dumpStack();;
main[1]
"!!"
Das Kommando "!!" wiederholt immer das direkt zuvor gegebene Kommando. Daher kann anstelle einer erneuten Eingabe des Kommandos "next" hier auch das Kommando "!!" eingegeben werden, um eine weitere Zeile ausführen zu lassen.
Konsole
main[1] !!
> ...
Step completed: "thread=main", Main.main(), line=5 bci=16
5 java.lang.Thread.dumpStack();
main[1]
"list"
Das Kommando "list" gibt den Quelltext aus. Dabei wird die nächste zur Ausführung anstehende Zeile durch den Text "=>" markiert.
Konsole
main[1] list
1 public class Main
2 { public static void main( String s[])
3 { java.lang.Thread.dumpStack();
4 java.lang.Thread.dumpStack();
5 => java.lang.Thread.dumpStack(); }}
main[1]
"stop" "at" 〈Klasse 〉 ':'
Das stop-at -Kommando erlaubt es, einen Haltepunkt vor eine bestimmte Zeilennummer einer bestimmten Klasse zu setzen. Das Kommando "stop at Main:8" setzt einen Haltepunkt vor Zeile 8 des obigen Auflistung des Quelltextes der Klasse "Main".
Konsole
main[1] stop at Main:8
Set breakpoint Main:8
main[1]
"stop"
Durch Eingabe des Kommandos "stop" alleine können die bisher gesetzten Haltepunkt angezeigt werden.
Konsole
main[1] stop
Breakpoints set:
breakpoint Test.main
breakpoint Main:8
"cont"
Während die erste Ausführung einer Klasse mit dem Kommando "run" gestartet wird, dient das Kommando "cont" (continue , „setze fort!“) zur Fortsetzung der Ausführung an der aktuellen Stelle. Der vom Block erzeugten Ausgabe wird noch ein Größer-Zeichen ">" hinzugefügt, das an dieser Stelle etwas irritiert. Die Ausführung läuft bis zum nächsten Haltepunkt vor Zeile 8 weiter.
Konsole
main[1] cont
...
Breakpoint hit: "thread=main", Main.main(), line=8 bci=40
8 System.out.println( "Alte Kinder, junge Kinder" );
main[1]
Wie zuvor kann das Kommando "next" verwendet werden, um die zur Ausführung anstehende Zeile auszuführen.
Konsole
main[1] next
> ...
Step completed: "thread=main", Main.main(), line=9 bci=48
9 System.out.println( "Hoerens immer gerne." );
main[1]
"exit" | "quit"
Das Kommando "exit" beendet das Programm zur Ablaufanzeige. Die Ausführung wird dabei aber zunächst noch fortgesetzt. Das Kommando "quit" hat die gleiche Wirkung. (Unter manchen Umgebungen kann eine Eingabe wie Strg-C die Ablaufanzeige sofort unterbrechen.)
Konsole
main[1] exit
...
>
Die Datei ".jdbrc"
Kommandos, die am Anfang des Testens immer wieder eingegeben werden, können einmal in eine Datei namens ".jdbrc" geschrieben werden.
.jdbrc
stop in Main.main
run
Durch die hier als Beispiel gegeben Datei ".jdbrc" geht der Ablaufanzeiger „automatisch“ vor den Anfang der ersten Ausdruckanweisung und wartet auch weitere Kommandos. Hier kann nun beispielsweise sofort das Kommando "next" eingegeben werden.
Konsole
>jdb Main
Initializing jdb ...
*** Reading commands from F:\r\k\java\.jdbrc
Deferring breakpoint Main.main.
It will be set after the class is loaded.
> run Main
> >
VM Started: Set deferred breakpoint Main.main
Breakpoint hit: "thread=main", Main.main(), line=3 bci=0
3 { java.lang.Thread.dumpStack();;
main[1]
"print"
Die Ausgabe eines Ausdrucks mit dem Kommando "print" ist hilfreich, wenn eine Ausdruck ausgewertet werden soll, ohne daß erst ein Programm geschrieben werden muß. Doch es werden zum Zeitpunkt der Niederschrift dieses Textes noch nicht alle Arten von Ausdrücken unterstützt.
Konsole
main[1] print 4 + 5.0 * 3.24333
4 + 5.0 * 3.24333 = 20.21665
main[1] print 4 % 3
com.sun.tools.example.debug.expr.ParseException: Unknown operation: %
4 % 3 = null
main[1] print java.lang.Math.abs( -2 )
operation not yet supported
java.lang.Math.abs( -2 ) = null
main[1]
"classes"
Das Kommando "classes" zeigt alle verfügbaren Klassen an.
Konsole [Anfang]
main[1] classes
boolean[]
byte[]
char[]
char[][]
char[][][]
double[]
float[]
int[]
java.beans.PropertyChangeEvent
java.beans.PropertyChangeSupport
java.io.BufferedInputStream
"methods"
Mit dem methods -Kommando lassen sich alle Methode einer Klasse anzeigen.
Konsole [Anfang]
main[1] methods java.lang.Math
java.lang.Math <init>()
java.lang.Math sin(double)
java.lang.Math cos(double)
java.lang.Math tan(double)
java.lang.Math asin(double)
Programmablauf anzeigen *
Der Ablauf eines Methodenaufrufs läßt sich mit dem zum JDK gehörenden jdb (java debugger ) anzeigen. Das wird hier am Beispiel der Quelldatei »Main.java« gezeigt.
Main.java
public class Main
{ public static void refrainAusgeben()
{ Java.lang.System.out.println( "Sim sa la dim, bam ba," );
Java.lang.System.out.println( "Sa la du, sa la dim -" ); }
public static void main( final java.lang.String[] args )
{ { Java.lang.System.out.println( "Auf einem Baum ein Kuckuck, -" );
refrainAusgeben();
Java.lang.System.out.println( "Auf einem Baum ein Kuckuck sass." ); }
{ Java.lang.System.out.println( "Da kam ein junger Jaeger, -" );
refrainAusgeben();
Java.lang.System.out.println( "Da kam ein junger Jaegersmann." ); }
{ Java.lang.System.out.println( "Der schoss den armen Kuckuck, -" );
refrainAusgeben();
Java.lang.System.out.println( "Der schoss den armen Kuckuck tot." ); }}}System.out
Auf einem Baum ein Kuckuck, -
Sim sa la dim, bam ba,
Sa la du, sa la dim -
Auf einem Baum ein Kuckuck sass.
Da kam ein junger Jaeger, -
Sim sa la dim, bam ba,
Sa la du, sa la dim -
Da kam ein junger Jaegersmann.
Der schoss den armen Kuckuck, -
Sim sa la dim, bam ba,
Sa la du, sa la dim -
Der schoss den armen Kuckuck tot.
Die Grundlagen der Bedienung der Ablaufanzeige wurden bereits in einer anderen Lektion behandelt. Hier werden nun noch einige Aspekte ergänzt, die mit Methodenaufrufen zusammenhängen. Die Ablaufanzeige wird hier mit einer Datei ».jdbrc« im aktuellen Verzeichnis »dir0« so gestartet, daß sie bei der ersten Zeile der Hauptmethode zunächst anhält.
.jdbrc
stop in Main.main
runKonsole
dir0>jdb Main
Initializing jdb ...
*** Reading commands from dir0\.jdbrc
Deferring breakpoint Main.main.
It will be set after the class is loaded.
> run Main
> >
VM Started: Set deferred breakpoint Main.main
Breakpoint hit: "thread=main", Main.main(), line=6 bci=0
6 { { Java.lang.System.out.println( "Auf einem Baum ein Kuckuck, -" );
»methods«
Mit dem methods -Kommando lassen sich die beiden Methoden unserer Klasse anzeigen. Daneben werden noch weitere Methoden angezeigt, die aber in dieser Lektion ignoriert werden können.
Konsole
main[1] methods Main
** methods list **
Main <init>()
Main refrainAusgeben()
Main main(java.lang.String[])
java.lang.Object <init>()
java.lang.Object registerNatives()
java.lang.Object getClass()
java.lang.Object hashCode()
java.lang.Object equals(java.lang.Object)
java.lang.Object clone()
java.lang.Object toString()
java.lang.Object notify()
java.lang.Object notifyAll()
java.lang.Object wait(long)
java.lang.Object wait(long, int)
java.lang.Object wait()
java.lang.Object finalize()
java.lang.Object <clinit>()
»next«
Durch das Kommando »next« kann die nächste Zeile bekanntlich ausgeführt werden.
Konsole
main[1] next
> Auf einem Baum ein Kuckuck, -
Step completed: "thread=main", Main.main(), line=7 bci=8
7 refrainAusgeben();
Ein Methodenaufruf wird dabei als ein Schritt angesehen, die einzelnen Zeilen der aufgerufenen Methode werden also nicht zur Einzelzeilenausführung vorgelegt. Daher wird die Methode »refrainAusgeben« nach der Eingabe des ersten Kommandos »!!« vollständig abgearbeitet und der gesamte Refrain erscheint vor der nächsten Eingabemöglichkeit.
Konsole
main[1] !!
> Sim sa la dim, bam ba,
Sa la du, sa la dim -
Step completed: "thread=main", Main.main(), line=8 bci=11
8 Java.lang.System.out.println( "Auf einem Baum ein Kuckuck sass." ); }
Nach dem Ende der Auswertung des Methodenaufrufs geht der Ablauf natürlich wieder in der aufrufenden Methode weiter.
Konsole
main[1] !!
> Auf einem Baum ein Kuckuck sass.
Step completed: "thread=main", Main.main(), line=9 bci=19
9 { Java.lang.System.out.println( "Da kam ein junger Jaeger, -" );
main[1]
»step«
Falls keine verfolgbare Methode aufgerufen wird, ist die Wirkung des Kommandos »step« der des Kommandos »next« gleich. Es wird die nächste zur Ausführung anstehende Zeile aufgerufen.
Konsole
main[1] step
> Da kam ein junger Jaeger, -
Step completed: "thread=main", Main.main(), line=10 bci=27
10 refrainAusgeben();
Das Kommando »step« setzt die Einzelzeilenausführung gegebenenfalls innerhalb einer aufgerufenen Methode fort (falls die Methode angezeigt werden kann). So kann auch nach jeder Zeile einer aufgerufenen Methode ein Kommando eingegeben werden.
Konsole
main[1] !!
step
>
Step completed: "thread=main", Main.refrainAusgeben(), line=3 bci=0
3 { Java.lang.System.out.println( "Sim sa la dim, bam ba," );
main[1] !!
step
> Sim sa la dim, bam ba,
Step completed: "thread=main", Main.refrainAusgeben(), line=4 bci=8
4 Java.lang.System.out.println( "Sa la du, sa la dim -" ); }
main[1] !!
step
> Sa la du, sa la dim -
Step completed: "thread=main", Main.main(), line=11 bci=30
11 Java.lang.System.out.println( "Da kam ein junger Jaegersmann." ); }
Nach dem Ende der aufgerufenen Methode geht der Ablauf auch hier wieder in der aufrufenden Methode weiter.
Konsole
main[1] !!
step
> Da kam ein junger Jaegersmann.
Step completed: "thread=main", Main.main(), line=12 bci=38
12 { Java.lang.System.out.println( "Der schoss den armen Kuckuck, -" );
main[1] !!
> Der schoss den armen Kuckuck, -
Step completed: "thread=main", Main.main(), line=13 bci=46
13 refrainAusgeben();
»step« »up«
Das step-up -Kommando erlaubt es, alle weiteren Zeilen einer Methode bis zum Ende der Methode auszuführen. Der nächste Schritt ist dann also gegebenenfalls die nächste Zeile in der aufrufenden Methode.
Konsole
main[1] step
>
Step completed: "thread=main", Main.refrainAusgeben(), line=3 bci=0
3 { Java.lang.System.out.println( "Sim sa la dim, bam ba," );
main[1] step up
Sim sa la dim, bam ba,>
Sa la du, sa la dim -
Step completed: "thread=main", Main.main(), line=14 bci=49
14 Java.lang.System.out.println( "Der schoss den armen Kuckuck tot." ); }}}
main[1] step
> Der schoss den armen Kuckuck tot.
The application exited
$