Javaクラス解析機を作る 6日目
例外とインナークラス属性に対応。
現在の読み込み対応データ
★付きが今日対応したモノ。
クラスデータ
名称 | サイズ | 説明 |
---|---|---|
magic | 4byte | クラスファイルを識別するためのマジックナンバー。0xCAFEBABEが入る。 |
minor_version | 2byte | クラスのマイナーバージョン |
major_version | 2byte | クラスのメジャーバージョン |
constant_pool_count | 2byte | constant_pool (クラス名メソッド名などの定数が格納されるテーブル)の数 |
constant_pool | 可変 | クラス名メソッド名などの定数が格納されるテーブル。constant_pool_count-(1+Double or Longのconstantの数)個のconstant_poolが並ぶ。「文字列」や「Class情報」など種類がいくつかあって、それぞれデータ形式/サイズが異なる。 |
access_flags | 2byte | クラス/インターフェイスのアクセス権限情報 |
this_class | 2byte | このクラスファイルで定義されているクラスを示すconstant_poolのid。 |
super_class | 2byte | このクラスファイルで定義されているクラスの親クラスを示すconstant_poolのid。 |
interfaces_count | 2byte | 実装しているインターフェイスの数。 |
interfaces | 可変(2byte*interfaces_count) | 実装しているインターフェイスを示すconstant_poolのid。interfaces_count数だけ続く。 |
fields_count | 2byte | クラス/インターフェイスで定義されているフィールドの数。 |
field_info | 可変 | クラス/インターフェイスで定義されているフィールド。データ形式は「フィールドデータ」を参照。fields_count数だけ続く。 |
methods_count | 2byte | クラス/インターフェイスで定義されているメソッドの数。 |
method_info | 可変 | クラス/インターフェイスで定義されているメソッド。データ形式は「メソッドデータ」を参照。methods_count数だけ続く。 |
attributes_count | 2byte | クラス/インターフェイスの属性の数。 |
attribute_info | 可変 | クラス/インターフェイスの属性。コンパイル元のソースファイルの情報などが含まれる。データ形式は各種「属性」を参照。methods_count数だけ続く。 |
フィールドデータ
名称 | サイズ | 説明 |
---|---|---|
access_flags | 2byte | フィールドのアクセス権限情報 |
name_index | 2byte | フィールド名を示すconstant_poolのid |
descriptor_index | 2byte | フィールドの型の文字列表現を示すconstant_poolのid |
attributes_count | 2byte | フィールドに付加された属性の数 |
attribute_info | 可変 | フィールドの属性。定数の値やdeplicatedの情報なんかが属性として指定される。attributes_count数だけ続く |
メソッドデータ
名称 | サイズ | 説明 |
---|---|---|
access_flags | 2byte | メソッドのアクセス権限情報 |
name_index | 2byte | メソッド名を示すconstant_poolのid |
descriptor_index | 2byte | メソッドの引数と戻り値の型の文字列表現を示すconstant_poolのid。「(<引き数の型><引き数の型>..)<戻り値の型>」形式。 |
attributes_count | 2byte | メソッドに付加された属性の数 |
attribute_info | 可変 | メソッドの属性。メソッドの処理コード、発生する例外などが属性として指定される。attributes_count数だけ続く |
ConstantValue属性
文字列とプリミティブ型の定数の値を示すフィールドの属性。
名称 | サイズ | 説明 |
---|---|---|
attribute_name_index | 2byte | 属性名"ConstantValue"を示すconstant_poolのid。 |
attribute_length | 4byte | 属性値の長さ。2で固定 |
constantvalue_index | 2byte | 定数値を示すconstant_poolのid。 |
SourceFile属性
クラスのコンパイル前のソースファイル名(パスではない。)の情報を保持するクラス属性。
名称 | サイズ | 説明 |
---|---|---|
attribute_name_index | 2byte | 属性名"SourceFile"を示すconstant_poolのid。 |
attribute_length | 4byte | 属性値の長さ。2で固定 |
sourcefile_index | 2byte | ソースファイル名を示すconstant_poolのid。 |
Exceptions属性
発生しうる例外を示すメソッドの属性。
名称 | サイズ | 説明 |
---|---|---|
★attribute_name_index | 2byte | 属性名"Exceptions"を示すconstant_poolのid。 |
★attribute_length | 4byte | 属性値の長さ。 |
★number_of_exceptions | 2byte | 例外の数。 |
★exception_index_table | 可変(2byte*number_of_exceptions) | 例外を示すconstant_poolのid。number_of_exceptions数だけ続く。 |
InnerClasses属性
クラス/インターフェイスで定義されたインナークラスの情報が記録されるクラス属性。メソッド内クラスもクラスのインナークラスとしてこの属性で保持される。
名称 | サイズ | 説明 |
---|---|---|
★attribute_name_index | 2byte | 属性名"InnerClasses"を示すconstant_poolのid。 |
★attribute_length | 4byte | 属性値の長さ。 |
★number_of_classes | 2byte | インナークラスの数。 |
★classes | 可変(8byte*number_of_classes) | インナークラスの情報。データ形式は各種↓を参照。number_of_classes数だけ続く。 |
classes内のデータ
名称 | サイズ | 説明 |
---|---|---|
★inner_class_info_index | 2byte | インナークラスを示すconstant_poolのid。 |
★outer_class_info_index | 2byte | インナークラスを持つクラス?を示すconstant_poolのid。無名クラスの場合、0になる。 |
★inner_name_index | 2byte | インナークラスの名前を示すconstant_poolのid。無名クラスの場合、0になる。 |
★inner_class_access_flags | 2byte | インナークラスのアクセス権情報 |
ここまでの解析コード
動作サンプル
解析対象のJavaクラス(のソース)。インナークラスを持つ、インターフェイスとクラスを用意。
package com.example; import java.util.Map; /** * インナークラスを持つインターフェイス */ public interface InnerClass { // staticなインナークラス static class StaticInnerClass { // インナークラス内インナークラス static class StaticInnerInnerClass{} class InnerInnerClass{} } // インナークラス class BasicInnerClass {} // 匿名クラス Object x = new Object() { public String toString() { return "x"; } }; }
package com.example; import java.util.Map; /** * インナークラスを持つクラス */ public class InnerClassImpl implements InnerClass { // staticなインナークラス static class StaticInnerClass2 {} // インナークラス class BasicInnerClass2 {} // 匿名クラス Object xx = new Object() { public String toString() { return "xx"; } }; public static void main() { // 関数内クラス class MethodInnerClass {} // 関数内の匿名クラス Object yy = new Object() { public String toString() { return "yy"; } }; } }
あと、例外をスローする関数を持つやつも。
package com.example; import java.io.IOException; /** * 例外を投げる */ public class ThrowsException { public static void main ( String[] args ) throws IOException, IllegalArgumentException, OutOfMemoryError {} }
↑をまとめて解析!
require "javaclass" [ "./java_class/com/example/InnerClass.class", "./java_class/com/example/InnerClassImpl.class", "./java_class/com/example/InnerClass$StaticInnerClass.class", "./java_class/com/example/ThrowsException.class" ].each { |c| open( c, "r+b" ) {|io| jc = JavaClass.from io puts jc.to_s puts "" } }
実行結果です。インナークラスは「// use inner ....」で始まるコメントとして、クラスの先頭に出力してみました。
// version 49.0 // source InnerClass.java public abstract interface com.example.InnerClass extends java.lang.Object { // use inner public static class com.example.InnerClass$StaticInnerClass // use inner public static class com.example.InnerClass$BasicInnerClass // use inner class com.example.InnerClass$1 public static final java.lang.Object x; static void <clinit> ( ) {}; } // version 49.0 // source InnerClassImpl.java public class com.example.InnerClassImpl extends java.lang.Object implements com.example.InnerClass { // use inner static class com.example.InnerClassImpl$StaticInnerClass2 // use inner class com.example.InnerClassImpl$BasicInnerClass2 // use inner class com.example.InnerClassImpl$1 // use inner class com.example.InnerClassImpl$1MethodInnerClass // use inner class com.example.InnerClassImpl$2 java.lang.Object xx; public void <init> ( ) {}; public static void main ( ) {}; } // version 49.0 // source InnerClass.java public class com.example.InnerClass$StaticInnerClass extends java.lang.Object { // use inner public static class com.example.InnerClass$StaticInnerClass // use inner static class com.example.InnerClass$StaticInnerClass$StaticInnerInnerClass // use inner class com.example.InnerClass$StaticInnerClass$InnerInnerClass public void <init> ( ) {}; } // version 49.0 // source ThrowsException.java public class com.example.ThrowsException extends java.lang.Object { public void <init> ( ) {}; public static void main ( java.lang.String[] arg1 ) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.OutOfMemoryError {}; }