生のバイトコードをダンプすることは可能ですが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 ch = 0; ch < Character.MAX_VALUE; ch++)
if (Character.isJavaIdentifierPart(ch) && !Character.isJavaIdentifierStart(ch))
System.out.printf("%04x <%s>%n", (int) ch, "" + ch);
は、テキストが逆向きに印刷される原因となる識別子の目に見えない文字のため、有効なコードです。
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();
フィールドの初期値。
コンパイラがこれらを期待するほど使用しないことに同意しますが、使用した場合にどのような違いが生じるかはわかりません。