1

Java仮想マシン仕様から:

classファイルは、8ビットバイトのストリームで構成されます。すべての16ビット、32ビット、および64ビットの量は、それぞれ2、4、および8つの連続する8ビットバイトを読み取ることによって構成されます。マルチバイトデータ項目は常にビッグエンディアンの順序で格納され、上位バイトが最初になります。java.io.DataOutputJavaプラットフォームでは、このフォーマットは、インターフェースjava.io.DataInputと、java.io.DataInputStreamやjava.io.DataOutputStreamなどのクラスによってサポートされます。

classこの章では、ファイルデータを表す独自のデータ型のセットを定義します。型u1、、、u2およびu4は、それぞれ符号なしの1バイト、2バイト、または4バイトの量を表します。readUnsignedByteJavaプラットフォームでは、これらのタイプは、、、readUnsignedShortおよびreadIntインターフェイスのメソッドによって読み取ることができますjava.io.DataInput

「64ビット量」(no u8long、doubleは2つの項目に分割されています)についての苛立たしい言及を除けば、タイプu4の処理方法がわかりません。u4

u1とそれはu2明らかです:

  • u1:で読んでreadUnsignedByteint
  • u2:で読んでreadUnsignedShortint

仕様はこれをアドバイスしています:

  • u4:で読んで、 (?)readIntに保存するint

より大きい値はどうなりInteger.MAX_VALUEますか?u4このアドバイスは、タイプのすべての値が以下であることを黙って暗示していますInteger.MAX_VALUEか?

私はこのアイデアを思いついた:

  • u4:で読んでreadUnsignedIntlong

残念ながら、そのような方法はありません。しかし、それは問題ではありません。自分で簡単に書くことができるからです。

public long readUnsignedInt() throws IOException {
    return readInt() & 0xFFFFFFFFL;
}

したがって、ここに2つの疑わしいスポットがあります。

  1. コード属性

    Code_attribute {
    ...
    u4 code_length;
    u1コード[コード長];
    ...
    }

    なぜcode_lengthタイプではないのu2ですか?後でそれは言う

    アイテムの値はcode_length65536未満である必要があります。

  2. SourceDebugExtension属性

    SourceDebugExtension_attribute {
    ...
    u4 attribute_length;
    u1 debug_extension [attribute_length];
    }
    ...配列は、クラスのインスタンスで表すことができる文字列よりも長い文字列を示す場合があること
    に注意してください。debug_extensionString

    なんで?u4値は実際に超えることができますか(これはインスタンスInteger.MAX_VALUEの最大長だと思うので)?String

4

2 に答える 2

1
  1. そのような必要が生じた場合、64Kコード長の制限を簡単に解除します。
  2. u4の値がInteger.MAX_VALUEを超えることはできないという言及がないため、u4の値がInteger.MAX_VALUEを超えることができると想定する必要があります。JVM仕様は、暗黙的なものを何も残していません。
于 2012-07-26T02:01:37.930 に答える
0

クラスファイルを効率的に処理したい場合は、架空のケースだけに多くのリソースを浪費しないでください。お気づきのとおり、コード配列のサイズはとして指定されてu4いますが、実際にサポートされる値はに制限されていu2ます。同様に、クラスファイルをJVMに取り込む唯一の公式にサポートされている方法が配列またはu4基づいていると考える場合、他のすべてのサイズ値は暗黙的に制限され、両方とも合計サイズを表す符号付きに制限されます。ByteBufferint

より大きなクラスファイルをJVMに取り込む方法があったとしても、Instrumentation APIのように、クラスを通常の配列に戻す可能性を期待する他の部分があります。将来のJVMがより大きなクラスファイルの実際のサポートを取得したとしても、新しいバッファタイプを使用してすべてのAPIを代替で拡張すると、今日コンパイルされるアプリケーションは、今日のAPIとバッファタイプに制限されます。

したがって、クラスファイルの合計intサイズが本質的に最大符号付きバイト、つまりバイトに制限されている場合、1つの属性など、クラスファイルの一部がそれよりも大きくなる2³¹可能性を考慮する必要はありません。このような巨大な属性を使用して理論的に正しいクラスファイルを作成することはできますが、JVM自体でさえそれをサポートしません。また、そのようなシナリオには実際の関連性はありません。

したがって、問題がそれらをどのように処理するかではない場合、問題はそれらを正しく拒否する方法です。ファイルを処理する場合、実際にはバイトを超える可能性がInteger.MAX_VALUEあります。さらに処理するためにファイルをバッファに読み込む場合は、とにかく考慮する必要があります。次に、他のことをする前にサイズをチェックして、を投げるのUnsupportedOperationExceptionが適切でしょう。32ビットJVMでは、OutOfMemoryErrorファイルの内容をバッファリングしようとする実際の試みはこのようになるため、をスローすることも適切です。

ファイルがより小さい場合、Integer.MAX_VALUEまたはクラスファイルを本質的にそれよりも小さくなるように制限するAPIを介してクラスファイルを受信して​​いる場合、たとえば配列またはを渡すことにより、続行して、すべてのサイズ値が無効であるByteBufferと見なすことができます。クラスファイル自体よりも大きいサイズを示しているためです。両方とも同じサイズであるため、特別なメソッドは必要ありません。有効な正の範囲外の値を分類するには、値を正しく解釈するだけで済みます。u4Integer.MAX_VALUEreadUnsignedIntintu4int

Java 8では、これは特に簡単です。

int codeSize=bytebuffer.getInt();
if(Integer.compareUnsigned(codeSize, 65536)>0)
    throw new IllegalArgumentException(
        "invalid code size "+Integer.toUnsignedString(codeSize));
// carry on using the int value ordinarily

以前のバージョンでは、次のように解釈されると、u4より大きい値は負の値として表示されると考える場合があります。Integer.MAX_VALUEint

int codeSize=bytebuffer.getInt();
if(codeSize<0 || codeSize>65536)
    throw new IllegalArgumentException("invalid code size "+(codeSize&0xFFFFFFFFL));
// carry on using the int value ordinarily

同様に、他のu4サイズ値を処理します。

int size=bytebuffer.getInt();
// ByteBuffer can't be bigger than Integer.MAX_VALUE bytes:
if(size<0) throw new IllegalArgumentException(
    "truncated class file (attribute size "+(size&0xFFFFFFFFL)+')');
// carry on using the int value ordinarily
于 2017-01-09T18:06:35.593 に答える