2

Java Compiler によって生成されたバイト コード (Java バイナリ) を、ある種のエディターを使用して開きたいと考えています.class

javapユーティリティを試しました。しかしjavap、私は.classファイルを変更できません。また、生のバイトコードを表示していないようです

また、ファイルからコードを提供するJD Decompilerのような逆コンパイラも見ました。.classでも、ソースコードには興味がなく、バイトコードを見たい。

また、dirtyJOEJBEという GUI エディターも試しました。このエディターは非常に優れたもので、私の目的の半分を満たしています。ファイル内のさまざまなフィールドを表示し、.classファイルを編集することもでき.classます。しかしこれは、バイトコードをデコードしてUI上に表示して分かりやすくする翻訳機のようなものでもあるようです。生のバイトコードは表示されません。

生のバイトコードに行くことさえ可能ですか?

ばかげているように聞こえるかもしれませんが、Java コンパイラと JVM を正しく理解するために、これを確認したかったのです。

4

2 に答える 2

9

生のバイトコードをダンプすることは可能ですがjavap -v、クラスファイル内のすべての情報を編集可能な形式で取得するには、ASM を使用します。これを編集に使用しない理由は次のとおりです。

  • Java でできないことはほとんどできません。
  • はるかに使いにくいです。
  • それを壊した場合、何が悪いのかについてのフィードバックはあまり得られません。

バイトコードがJavaコード用にコンパイルされただけであることは何の価値もないため、ほとんど同じことを行います。JVM はさまざまな方法で自由に最適化できるため、JVM の動作やコードの実行方法を理解したい場合、バイト コードの理解はあまり役に立ちません。


手動で書かれたバイトコードの推奨される使用法について @Antimony に感謝します。それらのいくつかは有効ですが、かなり高度であるかあいまいであるか、同じことを達成する別の方法があります。

いくつかのアイデア

宣言せずにチェック例外をスローします。

Thread.currentThread().stop(checkedException);

宣言せずにチェック済み例外をキャッチし、

   if (false) throw new CheckedException();
} catch(CheckedException ce) {

Java では無効な識別子を使用する

非常に多くの有効な文字がありますが、使用するのにそれほど有用ではありません。そのうちの1つを使用します

if( ⁀ ‿ ⁀ == ⁀ ⁔ ⁀ || ¢ + ¢== ₡)

for (char c‮h = 0; c‮h < Character.MAX_VALUE; c‮h++)
    if (Character.isJavaIdentifierPart(c‮h) && !Character.isJavaIdentifierStart(c‮h))
        System.out.printf("%04x <%s>%n", (int) c‮h, "" + c‮h);

は、テキストが逆向きに印刷される原因となる識別子の目に見えない文字のため、有効なコードです。

http://vanillajava.blogspot.co.uk/2012/09/hidden-code.html

http://vanillajava.blogspot.co.uk/2012/08/uses-for-special-characters-in-Java-code.html

コンストラクター呼び出しの前にフィールドにアクセスする

これにより VerifyError が発生すると確信しています(または、試したときに発生しました)。代わりに使用できます

Object o = Unsafe.allocateInstance(clazz); // create without calling a constructor.

条件付きで異なるコンストラクターを呼び出す

ここでも、オブジェクトの作成とインスタンスの呼び出しの間にコードを配置できましたが、それを機能させる方法があるかもしれません。Javaでは、次のように記述します

MyClass mc = condition ? new MyClass(a) : new MyClass(a, b);

コンストラクターで例外処理を行います。

コンストラクターで例外をキャッチまたはスローできるため、ここで何を意味するのかわかりません。

final フィールドを複数回割り当てるか、まったく割り当てない

代わりにリフレクションを使用して、最終フィールドにデフォルト値を与えることができます。つまり、フィールドに値がないことはありません。

非strictfpメソッドを持つstrictfpコンストラクターを持つ

それは興味深いものですが、私が今まで必要としていたものではありません。

緩い型チェックを使用する

バイト コードでは、型チェックのさまざまなルールが許可されていますが、あまり役に立たない VerifyErrors で簡単に違反します。これを行うことはできますが、私見を正しくするのは非常に困難です。

静的初期化子から例外をスローします

チェックされていない例外をすでにスローすることができ、チェックされた例外をスローするには上記のトリックを使用できますが、通常は AssertionError などでラップします。

インボークダイナミックを使用する

MethodHandles を使用することもできますが、Java 7 ではかなり扱いにくいです。Java 8 では、より自然に使用できるようになることを願っています。

サブルーチンを使用する

興味深いことに、私はこれを試したことはありませんが、メソッド呼び出しに対してどのような利点があるかはわかりません。

異常な制御フローを使用する

確かに、これは JIT オプティマイザを混乱させる可能性が高く、結果としてコードが遅くなる可能性があり、期待する利点が得られない可能性があります。

古いスーパー コール セマンティクスを使用する

できますが、それがどれほど役立つかはわかりません。

スレッドモニターを使用する

使用できます

Unsafe.enterMonitor();
Unsafe.exitMonitor();
Unsafe.tryMonitorEnter();

フィールドの初期値。

コンパイラがこれらを期待するほど使用しないことに同意しますが、使用した場合にどのような違いが生じるかはわかりません。

于 2012-10-29T09:33:58.173 に答える
2

ASM など、バイトコード操作用に設計されたライブラリがいくつかありますが、私はそれらを使用したことがないので、それらの能力や使いやすさについてはあまり言えません。

人間が読める形式をバイナリ クラス ファイルに変換するように設計されたアセンブラもあります (私自身も作成しました)。私の知る限り、クラス ファイルをアセンブリ形式に変換するツールはありませんが、興味があれば作成できます。

簡単な変更の場合、何をしているのかわかっていれば、16 進エディタを使用することもできます。以前に 16 進エディタでクラスを数回編集したことがあります。

于 2012-10-30T05:01:01.190 に答える