javaファイルをコンパイルするとclassファイルができます
このclassファイルからデコンパイル、つまりソースコードの復活ができるって知ってましたか?
デコンパイルできる2つのツールについて紹介します
>> [Java]文字列連結で、+演算子 or StringBuilder どちらを使うべき?
◆対象読者
- Javaの知識が少しはある人
- バイトコードって聞いたことある人
- 前回の記事を読んだ人
- classファイルからのデコンパイルを知りたい人
- 基本的なDOSコマンドやshellコマンドを使える人
◆解決できるかも知れないお悩み
- Jadの使い方
- JD-GUIの使い方
- JadとJD-GUIの違い
Contents
Javaのデコンパイルツール
僕が知ってるのはこの2つ
- Jad
- JD-GUI
どちらもclassファイルからソースコードを起こしてくれます
JadとJD-GUIの違い
どっちもデコンパイルしてくれますが、出力されるソースコードは少し違います
classファイルの内容をそれぞれに解釈した上でソースコードにしてくれていますので、もちろん処理は同じです
Jadはバイトコードに、JD-GUIはソースコードに寄っている感じですね
使いやすいのはJD-GUIの方だと思いますが、バイトコードが想像し易いJadの方が僕は好きです
その辺はお好みに合わせて使い分ければ良いでしょう
Jadについて
ダウンロード
公式サイトはこちらなので、各自のプラットフォームに合わせてダウンロードしてください。
Windowsの場合はこれですね
Windows7でもこれで動きました
Jad 1.5.8g for Windows 9x/NT/2000 on Intel platform
Macならこれですね
Jad 1.5.8g for Mac OS X 10.4.6 on Intel platform
使い方
Windowsの場合はダウンロードファイルはzipなので解凍すれば即使えます
jad.exeが入っているフォルダにPATHを通すか、既にPATHの通っているフォルダにjad.exeを入れるかですね
PATHを通すのが面倒なら、classファイルと同じ場所にjad.exeを置けばいいでしょう
- コマンドプロンプト(Macならターミナル)起動
- jad.exeの置いてあるディレクトリへ移動
豆知識
Windowsの場合、エクスプローラーのアドレスバーでcmd+Enterと打てば、そのフォルダがカレントとなっている状態でDOSプロンプトが起動します
jad classname.class
とかjad *.class
と打てば、拡張子がjadのテキストファイルができます- このjadファイルにデコンパイルしたソースコードが書かれています
コマンドプション
> jad -help
と打てば、jadが持つオプションが沢山でてきますが…..、面倒なので、1個だけピックアップします
> jad -a classname.class
バイトコードをコメントとして表示してくれるので、ソースコードと併せて見たい時に使います
元のソースコード
public class SamplePlus { //=========================================================== // ノーマル系 //=========================================================== //*********************************************************** // 大分類:1行で連結 // 中分類:String変数使用 // 小分類:--- //*********************************************************** public static String Test11() { String hoge = "aiueo"; String fuga = "kakikukeko"; String piyo = "sasisuseso"; String gabo; gabo = hoge + fuga + piyo; return gabo; } //*********************************************************** // 大分類:1行で連結 // 中分類:文字列使用 // 小分類:--- //*********************************************************** public static String Test12() { String gabo; gabo = "aiueo" + "kakikukeko" + "sasisuseso"; return gabo; } //*********************************************************** // 大分類:複数行で連結 // 中分類:String変数使用 // 小分類:--- //*********************************************************** public static String Test13() { String hoge = "aiueo"; String fuga = "kakikukeko"; String piyo = "sasisuseso"; String gabo; gabo = ""; gabo += hoge; gabo += fuga; gabo += piyo; return gabo; } //*********************************************************** // 大分類:複数行で連結 // 中分類:文字列使用 // 小分類:--- //*********************************************************** public static String Test14() { String hoge = "aiueo"; String fuga = "kakikukeko"; String piyo = "sasisuseso"; String gabo; gabo = ""; gabo += "aiueo"; gabo += "kakikukeko"; gabo += "sasisuseso"; return gabo; } //*********************************************************** // 大分類:1行で連結 // 中分類:String変数と文字列の混合使用 // 小分類:--- //*********************************************************** public static String Test15() { String hoge = "aiueo"; String piyo = "sasisuseso"; String gabo; gabo = hoge + "kakikukeko" + piyo + "tatituteto"; return gabo; } //=========================================================== // ループ系 //=========================================================== //*********************************************************** // 大分類:ループ使用 // 中分類:String変数使用 // 小分類:ループの【外】でString変数定義 // :代入系 //*********************************************************** public static String Test21() { String hoge = "aiueo"; String gabo = ""; for(int i=0; i < 100; i++) { gabo = hoge; } return gabo; } //*********************************************************** // 大分類:ループ使用 // 中分類:String変数使用 // 小分類:ループの【外】でString変数定義 // :足していく系 //*********************************************************** public static String Test22() { String hoge = "aiueo"; String gabo = ""; for(int i=0; i < 100; i++) { gabo += hoge; } return gabo; } //*********************************************************** // 大分類:ループ使用 // 中分類:String変数使用 // 小分類:ループの【中】でString変数定義 // :代入系 //*********************************************************** public static String Test23() { String gabo = ""; for(int i=0; i < 100; i++) { String hoge = "aiueo"; gabo = hoge; } return gabo; } //*********************************************************** // 大分類:ループ使用 // 中分類:String変数使用 // 小分類:ループの【中】でString変数定義 // :足していく系 //*********************************************************** public static String Test24() { String gabo = ""; for(int i=0; i < 100; i++) { String hoge = "aiueo"; gabo += hoge; } return gabo; } //*********************************************************** // 大分類:ループ使用 // 中分類:文字列使用 // 小分類:--- // :代入系 //*********************************************************** public static String Test25() { String gabo = ""; for(int i=0; i < 100; i++) { gabo = "aiueo"; } return gabo; } //*********************************************************** // 大分類:ループ使用 // 中分類:文字列使用 // 小分類:--- // :足していく系 //*********************************************************** public static String Test26() { String gabo = ""; for(int i=0; i < 100; i++) { gabo += "aiueo"; } return gabo; } }
出力内容(ノーマル)
newのタイミングが分かるので、ループ文の中で毎回newしていないかとかが分かりやすいですね
> jad SamplePlus.class
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://www.kpdus.com/jad.html // Decompiler options: packimports(3) // Source File Name: SamplePlus.java public class SamplePlus { public SamplePlus() { } public static String Test11() { String hoge = "aiueo"; String fuga = "kakikukeko"; String piyo = "sasisuseso"; String gabo = (new StringBuilder()).append(hoge).append(fuga).append(piyo).toString(); return gabo; } public static String Test12() { String gabo = "aiueokakikukekosasisuseso"; return gabo; } public static String Test13() { String hoge = "aiueo"; String fuga = "kakikukeko"; String piyo = "sasisuseso"; String gabo = ""; gabo = (new StringBuilder()).append(gabo).append(hoge).toString(); gabo = (new StringBuilder()).append(gabo).append(fuga).toString(); gabo = (new StringBuilder()).append(gabo).append(piyo).toString(); return gabo; } public static String Test14() { String hoge = "aiueo"; String fuga = "kakikukeko"; String piyo = "sasisuseso"; String gabo = ""; gabo = (new StringBuilder()).append(gabo).append("aiueo").toString(); gabo = (new StringBuilder()).append(gabo).append("kakikukeko").toString(); gabo = (new StringBuilder()).append(gabo).append("sasisuseso").toString(); return gabo; } public static String Test15() { String hoge = "aiueo"; String piyo = "sasisuseso"; String gabo = (new StringBuilder()).append(hoge).append("kakikukeko").append(piyo).append("tatituteto").toString(); return gabo; } public static String Test21() { String hoge = "aiueo"; String gabo = ""; for(int i = 0; i < 100; i++) gabo = hoge; return gabo; } public static String Test22() { String hoge = "aiueo"; String gabo = ""; for(int i = 0; i < 100; i++) gabo = (new StringBuilder()).append(gabo).append(hoge).toString(); return gabo; } public static String Test23() { String gabo = ""; for(int i = 0; i < 100; i++) { String hoge = "aiueo"; gabo = hoge; } return gabo; } public static String Test24() { String gabo = ""; for(int i = 0; i < 100; i++) { String hoge = "aiueo"; gabo = (new StringBuilder()).append(gabo).append(hoge).toString(); } return gabo; } public static String Test25() { String gabo = ""; for(int i = 0; i < 100; i++) gabo = "aiueo"; return gabo; } public static String Test26() { String gabo = ""; for(int i = 0; i < 100; i++) gabo = (new StringBuilder()).append(gabo).append("aiueo").toString(); return gabo; } }
出力内容(-a
オプション)
-a
オプションを付けることにより、バイトコードとソースコードを併せて見ることができるので、細かい部分も分かりやすいですね
> jad -a SamplePlus.class
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://www.kpdus.com/jad.html // Decompiler options: packimports(3) annotate // Source File Name: SamplePlus.java public class SamplePlus { public SamplePlus() { // 0 0:aload_0 // 1 1:invokespecial #1// 2 4:return } public static String Test11() { String hoge = "aiueo"; // 0 0:ldc1 #2 // 1 2:astore_0 String fuga = "kakikukeko"; // 2 3:ldc1 #3 // 3 5:astore_1 String piyo = "sasisuseso"; // 4 6:ldc1 #4 // 5 8:astore_2 String gabo = (new StringBuilder()).append(hoge).append(fuga).append(piyo).toString(); // 6 9:new #5 // 7 12:dup // 8 13:invokespecial #6 // 9 16:aload_0 // 10 17:invokevirtual #7 // 11 20:aload_1 // 12 21:invokevirtual #7 // 13 24:aload_2 // 14 25:invokevirtual #7 // 15 28:invokevirtual #8 // 16 31:astore_3 return gabo; // 17 32:aload_3 // 18 33:areturn } public static String Test12() { String gabo = "aiueokakikukekosasisuseso"; // 0 0:ldc1 #9 // 1 2:astore_0 return gabo; // 2 3:aload_0 // 3 4:areturn } public static String Test13() { String hoge = "aiueo"; // 0 0:ldc1 #2 // 1 2:astore_0 String fuga = "kakikukeko"; // 2 3:ldc1 #3 // 3 5:astore_1 String piyo = "sasisuseso"; // 4 6:ldc1 #4 // 5 8:astore_2 String gabo = ""; // 6 9:ldc1 #10 // 7 11:astore_3 gabo = (new StringBuilder()).append(gabo).append(hoge).toString(); // 8 12:new #5 // 9 15:dup // 10 16:invokespecial #6 // 11 19:aload_3 // 12 20:invokevirtual #7 // 13 23:aload_0 // 14 24:invokevirtual #7 // 15 27:invokevirtual #8 // 16 30:astore_3 gabo = (new StringBuilder()).append(gabo).append(fuga).toString(); // 17 31:new #5 // 18 34:dup // 19 35:invokespecial #6 // 20 38:aload_3 // 21 39:invokevirtual #7 // 22 42:aload_1 // 23 43:invokevirtual #7 // 24 46:invokevirtual #8 // 25 49:astore_3 gabo = (new StringBuilder()).append(gabo).append(piyo).toString(); // 26 50:new #5 // 27 53:dup // 28 54:invokespecial #6 // 29 57:aload_3 // 30 58:invokevirtual #7 // 31 61:aload_2 // 32 62:invokevirtual #7 // 33 65:invokevirtual #8 // 34 68:astore_3 return gabo; // 35 69:aload_3 // 36 70:areturn } public static String Test14() { String hoge = "aiueo"; // 0 0:ldc1 #2 // 1 2:astore_0 String fuga = "kakikukeko"; // 2 3:ldc1 #3 // 3 5:astore_1 String piyo = "sasisuseso"; // 4 6:ldc1 #4 // 5 8:astore_2 String gabo = ""; // 6 9:ldc1 #10 // 7 11:astore_3 gabo = (new StringBuilder()).append(gabo).append("aiueo").toString(); // 8 12:new #5 // 9 15:dup // 10 16:invokespecial #6 // 11 19:aload_3 // 12 20:invokevirtual #7 // 13 23:ldc1 #2 // 14 25:invokevirtual #7 // 15 28:invokevirtual #8 // 16 31:astore_3 gabo = (new StringBuilder()).append(gabo).append("kakikukeko").toString(); // 17 32:new #5 // 18 35:dup // 19 36:invokespecial #6 // 20 39:aload_3 // 21 40:invokevirtual #7 // 22 43:ldc1 #3 // 23 45:invokevirtual #7 // 24 48:invokevirtual #8 // 25 51:astore_3 gabo = (new StringBuilder()).append(gabo).append("sasisuseso").toString(); // 26 52:new #5 // 27 55:dup // 28 56:invokespecial #6 // 29 59:aload_3 // 30 60:invokevirtual #7 // 31 63:ldc1 #4 // 32 65:invokevirtual #7 // 33 68:invokevirtual #8 // 34 71:astore_3 return gabo; // 35 72:aload_3 // 36 73:areturn } public static String Test15() { String hoge = "aiueo"; // 0 0:ldc1 #2 // 1 2:astore_0 String piyo = "sasisuseso"; // 2 3:ldc1 #4 // 3 5:astore_1 String gabo = (new StringBuilder()).append(hoge).append("kakikukeko").append(piyo).append("tatituteto").toString(); // 4 6:new #5 // 5 9:dup // 6 10:invokespecial #6 // 7 13:aload_0 // 8 14:invokevirtual #7 // 9 17:ldc1 #3 // 10 19:invokevirtual #7 // 11 22:aload_1 // 12 23:invokevirtual #7 // 13 26:ldc1 #11 // 14 28:invokevirtual #7 // 15 31:invokevirtual #8 // 16 34:astore_2 return gabo; // 17 35:aload_2 // 18 36:areturn } public static String Test21() { String hoge = "aiueo"; // 0 0:ldc1 #2 // 1 2:astore_0 String gabo = ""; // 2 3:ldc1 #10 // 3 5:astore_1 for(int i = 0; i < 100; i++) //* 4 6:iconst_0 //* 5 7:istore_2 //* 6 8:iload_2 //* 7 9:bipush 100 //* 8 11:icmpge 22 gabo = hoge; // 9 14:aload_0 // 10 15:astore_1 // 11 16:iinc 2 1 //* 12 19:goto 8 return gabo; // 13 22:aload_1 // 14 23:areturn } public static String Test22() { String hoge = "aiueo"; // 0 0:ldc1 #2 // 1 2:astore_0 String gabo = ""; // 2 3:ldc1 #10 // 3 5:astore_1 for(int i = 0; i < 100; i++) //* 4 6:iconst_0 //* 5 7:istore_2 //* 6 8:iload_2 //* 7 9:bipush 100 //* 8 11:icmpge 39 gabo = (new StringBuilder()).append(gabo).append(hoge).toString(); // 9 14:new #5 // 10 17:dup // 11 18:invokespecial #6 // 12 21:aload_1 // 13 22:invokevirtual #7 // 14 25:aload_0 // 15 26:invokevirtual #7 // 16 29:invokevirtual #8 // 17 32:astore_1 // 18 33:iinc 2 1 //* 19 36:goto 8 return gabo; // 20 39:aload_1 // 21 40:areturn } public static String Test23() { String gabo = ""; // 0 0:ldc1 #10 // 1 2:astore_0 for(int i = 0; i < 100; i++) //* 2 3:iconst_0 //* 3 4:istore_1 //* 4 5:iload_1 //* 5 6:bipush 100 //* 6 8:icmpge 22 { String hoge = "aiueo"; // 7 11:ldc1 #2 // 8 13:astore_2 gabo = hoge; // 9 14:aload_2 // 10 15:astore_0 } // 11 16:iinc 1 1 //* 12 19:goto 5 return gabo; // 13 22:aload_0 // 14 23:areturn } public static String Test24() { String gabo = ""; // 0 0:ldc1 #10 // 1 2:astore_0 for(int i = 0; i < 100; i++) //* 2 3:iconst_0 //* 3 4:istore_1 //* 4 5:iload_1 //* 5 6:bipush 100 //* 6 8:icmpge 39 { String hoge = "aiueo"; // 7 11:ldc1 #2 // 8 13:astore_2 gabo = (new StringBuilder()).append(gabo).append(hoge).toString(); // 9 14:new #5 // 10 17:dup // 11 18:invokespecial #6 // 12 21:aload_0 // 13 22:invokevirtual #7 // 14 25:aload_2 // 15 26:invokevirtual #7 // 16 29:invokevirtual #8 // 17 32:astore_0 } // 18 33:iinc 1 1 //* 19 36:goto 5 return gabo; // 20 39:aload_0 // 21 40:areturn } public static String Test25() { String gabo = ""; // 0 0:ldc1 #10 // 1 2:astore_0 for(int i = 0; i < 100; i++) //* 2 3:iconst_0 //* 3 4:istore_1 //* 4 5:iload_1 //* 5 6:bipush 100 //* 6 8:icmpge 20 gabo = "aiueo"; // 7 11:ldc1 #2 // 8 13:astore_0 // 9 14:iinc 1 1 //* 10 17:goto 5 return gabo; // 11 20:aload_0 // 12 21:areturn } public static String Test26() { String gabo = ""; // 0 0:ldc1 #10 // 1 2:astore_0 for(int i = 0; i < 100; i++) //* 2 3:iconst_0 //* 3 4:istore_1 //* 4 5:iload_1 //* 5 6:bipush 100 //* 6 8:icmpge 37 gabo = (new StringBuilder()).append(gabo).append("aiueo").toString(); // 7 11:new #5 // 8 14:dup // 9 15:invokespecial #6 // 10 18:aload_0 // 11 19:invokevirtual #7 // 12 22:ldc1 #2 // 13 24:invokevirtual #7 // 14 27:invokevirtual #8 // 15 30:astore_0 // 16 31:iinc 1 1 //* 17 34:goto 5 return gabo; // 18 37:aload_0 // 19 38:areturn } }
JD-GUI
ダウンロード
公式サイトはこちらなので、各自のプラットフォームに合わせてダウンロードしてください。
Windowsの場合はこれですね
Windows7でもこれで動きました
jd-gui-windows-1.4.0.zip
Macならこれですね
jd-gui-osx-1.4.0.tar
使い方
Jadと違ってGUIですので使い方は簡単です
- jd-gui.exeをダブルクリックして起動
- 起動したらウィンドウが開きます
- classファイルをウィンドウへドラッグ&ドロップ
- これで終わりです
保存やコピーができますので、必要に応じて操作してください
元のソースコード
※Jadの場合と同じ
出力内容
Jadに比べると、普通のソースコードっぽいですね
public class SamplePlus { public static String Test11() { String hoge = "aiueo"; String fuga = "kakikukeko"; String piyo = "sasisuseso"; String gabo = hoge + fuga + piyo; return gabo; } public static String Test12() { String gabo = "aiueokakikukekosasisuseso"; return gabo; } public static String Test13() { String hoge = "aiueo"; String fuga = "kakikukeko"; String piyo = "sasisuseso"; String gabo = ""; gabo = gabo + hoge; gabo = gabo + fuga; gabo = gabo + piyo; return gabo; } public static String Test14() { String hoge = "aiueo"; String fuga = "kakikukeko"; String piyo = "sasisuseso"; String gabo = ""; gabo = gabo + "aiueo"; gabo = gabo + "kakikukeko"; gabo = gabo + "sasisuseso"; return gabo; } public static String Test15() { String hoge = "aiueo"; String piyo = "sasisuseso"; String gabo = hoge + "kakikukeko" + piyo + "tatituteto"; return gabo; } public static String Test21() { String hoge = "aiueo"; String gabo = ""; for (int i = 0; i < 100; i++) { gabo = hoge; } return gabo; } public static String Test22() { String hoge = "aiueo"; String gabo = ""; for (int i = 0; i < 100; i++) { gabo = gabo + hoge; } return gabo; } public static String Test23() { String gabo = ""; for (int i = 0; i < 100; i++) { String hoge = "aiueo"; gabo = hoge; } return gabo; } public static String Test24() { String gabo = ""; for (int i = 0; i < 100; i++) { String hoge = "aiueo"; gabo = gabo + hoge; } return gabo; } public static String Test25() { String gabo = ""; for (int i = 0; i < 100; i++) { gabo = "aiueo"; } return gabo; } public static String Test26() { String gabo = ""; for (int i = 0; i < 100; i++) { gabo = gabo + "aiueo"; } return gabo; } }
さいごに、
書いたソースコードが効率の悪いものになっていないか?
バイトコードになった時に思ったような形になっているか?
とかを確認することができます
プログラミングに慣れてきて余裕が出てきたら、ソースコードを書きっぱなしにするだけじゃなく細かい部分も気にするようになると、プログラミングは更に更に更に上達しますよ!
なぜそう書くべきなのか
という事が分かるようになるっていうのは、とっても大切ですよ!
プログラミング のレッスンに興味がある方、レッスン内容を聞いてみたい方、なんなりとお問い合わせください。
無料体験レッスンもありますのでお気軽にどうぞ!!!