Ваша задача немного сложнее, чем кажется.Простой случай:
System.out.println("abc");
Также переводится в простой байт-код:
getstatic #2; //java/lang/System.out
ldc #3; //String abc
invokevirtual #4; //Calling java/io/PrintStream.println(String)
Однако, если вы пытаетесь напечатать что-либо, кроме простой константы / известного значения, оно получаетсложнее:
int x = 42;
System.out.println(x + 17);
Будет переведено на:
bipush 42
istore_1 //x = 42
getstatic #2; //java/lang/System.out
iload_1 //x
bipush 17
iadd //x + 17 on the stack
invokevirtual #5; //Calling java/io/PrintStream.println(int)
Но подождите, может быть еще хуже:
System.out.println("x times 27 is " + x * 27);
Что?StringBuilder
:?
new #6; //new java/lang/StringBuilder()
dup
invokespecial #7; //Calling java/lang/StringBuilder()
ldc #8; //String x times 2 is
invokevirtual #9; //Calling java/lang/StringBuilder.append(String)
iload_1 //x
bipush 27
imul //x * 27 on the stack
invokevirtual #10; //Calling java/lang/StringBuilder.append:(int) with 'x * 27' argument
invokevirtual #11; //Calling java/lang/StringBuilder.toString:()
invokevirtual #4; //Calling java/io/PrintStream.println(String)
Интересно, что оригинальный код был переведен (что является известной оптимизацией Java 5 (?)):
System.out.println(
new StringBuilder().
append("x times 27 is ").
append(x * 27).
toString()
);
Решение
Так что действительно - вам понадобится стек , и вам придется отслеживать каждую операцию push / pop, как определено в инструкции байт-кода .Много работы для такой простой задачи ...
Но если вы пойдете по этому пути, решение проблемы будет довольно простым: когда вы сталкиваетесь с INVOKEVIRTUAL, вершина стека должна содержать некоторое значение, а значение нижеtop должен быть "java/lang/System.out
".
При этом я на 100% уверен, что Findbugs уже реализовали это, и, вероятно, вы можете использовать API FindBugs, чтобы сделать вашу жизнь проще.