2016-07-11 1 views
2

私は小さなシリアル化ユーティリティを書いています。バイト配列にオブジェクトを書き込むために必要なバイト数を計算したいと思います。 のは、私は私がフィールドを反復処理し、彼らが持っているもののサイズに見えるためにリフレクションを使用すると考えていたプリミティブフィールドのサイズを直接計算する方法はありますか?

int age; 
String name; 
Colour colour; 
boolean active; 
... 

のようないくつかのフィールド/ゲッターを持つクラスを持っていると言うが、彼らは原始的であるかどうか私にできることすべてをチェックしています。私はオブジェクトのオフセットとしてショートを使用するので、これは始まりです。はい、私は使用できます

if(field.getType() == int.class) { 
    size = Integer.BYTES; 
} 

または地図を使用します。私はプリミティブのサイズを知る必要があるので、それほど難しくありません。しかし好奇心から:直接的な方法はありますか?

明示的に編集する: 私はDataOutput/InputStreamのようなデータをシリアライズするために使用しています。

は、APIクラスは次のようになります。

public final void write(int i) { 
    checkBounds(Integer.BYTES); 
    PrimitiveWriteUtil.write(i, data, marker); 
    advance(Integer.BYTES); 
} 

実際の作業は、ユーティリティクラスによって行われますので、

public static void write(int i, byte[] target, int pos) { 
    target[pos] =  (byte) ((i >>> 24) & 0xFF); 
    target[pos + 1] = (byte) ((i >>> 16) & 0xFF); 
    target[pos + 2] = (byte) ((i >>> 8) & 0xFF); 
    target[pos + 3] = (byte) ((i >>> 0) & 0xFF); 
} 

だから、私は私のバイト配列の必要なサイズを知りたいです私は後でチェックし、サイズを変更する努力を避けることができます。

+0

可能な複製:http://stackoverflow.com/questions/52353/in-java-what-is-the-best-way-to-determine-the-size-of-an-object –

+0

私は見て回ったそれは以前のものであり、私のユースケースにはまったく合致しません。私は実行時に_one_オブジェクトのすべてのプリミティブフィールドのサイズを取得したいだけです。 – Silverclaw

+0

なぜですか? ByteArrayOutputStreamに書き込み、そこからバイト配列を取得するだけです。それは正しいサイズになります。 – EJP

答えて

1

あなたはすでにBYTESフィールドについて知っていますが、問題はこれらのフィールドが対応するラッパータイプで宣言されているため、プリミティブ型のラッパータイプを取得する簡単な方法がないことです。コードサイズの面では、それを取得する最も簡単な方法は、プリミティブ値の折り返しを意味get方法を介してフィールドを読み取ることである。

public class FieldSize { 
    static final int BOOLEAN_SIZE = 1; // adjust to your storage method 
    static final int REF_SIZE = 2;  // dito 
    private static int getSize(Field f, Object o) { 
     try { 
     return f.getType().isPrimitive()? f.getType()==boolean.class? BOOLEAN_SIZE: 
       f.get(o).getClass().getField("BYTES").getInt(null): REF_SIZE; 
     } catch(ReflectiveOperationException ex) { 
      throw new AssertionError(ex); 
     } 
    } 
    boolean z; 
    byte b; 
    short s; 
    char c; 
    int i; 
    long l; 
    float f; 
    double d; 
    String str; 

    public static void main(String[] args) { 
     System.out.println("total: "+calculateSize(new FieldSize())+" size"); 
    } 
    static int calculateSize(Object o) { 
     int total=0; 
     for(Class cl=o.getClass(); cl!=null; cl=cl.getSuperclass()) { 
      for(Field f: cl.getDeclaredFields()) { 
       if(Modifier.isStatic(f.getModifiers())) continue; 
       int size=getSize(f, o); 
       System.out.println(f.getName()+" ("+f.getType()+"): "+size); 
       total+=size; 
      } 
     } 
     return total; 
    } 
} 

しかし、基礎となる動作の点で、それが最も簡単ではありませんあなたがそれを気に入らなければ、私はそれを完全に理解しています。

この場合、これらの数字を取得する単純/直接の方法はないので、タイプから番号へのマッピング、またはこれらの8つの可能性を線形にプロービングすることは避けられないため、 (利用可能な)ソリューションです。

+0

*一口*私はそれが私が得る最高の答えだと思います。努力をいただきありがとうございます。 – Silverclaw

1

プリミティブのサイズはdefined in JLS 4.2です。

byteshortcharは2、intfloatあり、1バイトであるあなたがに頼る、単なる理論的な運動よりも、それ以上の目的のためにそれを使用する必要がある場合は32、doublelongは64

+0

はい...私が述べたように、私はちょうどShortへのマッピングを使うことができます。 Bytes、Integer.Bytes、etc.私の質問は、それが必要なのかどうか、あるいは**フィールドサイズを直接得る**の代替方法があるかどうかです。 – Silverclaw

-1

されています正確な数は危険です。

バイト配列のサイズをシリアル化に割り当てるために使用するので、ByteArrayOutputStreamの使用を検討してください。

ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 
ObjectOutputStream out = new ObjectOutputStream(bytesOut); 

out.writeObject(new MyObject(12, "JackDaniels", true)); 
out.close(); 
System.out.println("Number of bytes for serialized object: " + bytesOut.toByteArray().length); 

Codiva online compiler IDEのMyObjectヘルパークラスを持つ完全な作業コードです。

これはあなたの質問に直接答えませんが、これはあなたがしようとしていることを達成する正しい方法だと思います。


シリアライズの方法を変更するには、readObjectメソッドとwriteObjectメソッドを実装します。たとえば、http://www.byteslounge.com/tutorials/java-custom-serialization-exampleをご覧ください。

+0

サイズに頼っても危険ではありません。これはJavaではなく、Cである。 – chrylis

+0

本当ではない。 Cでは、少なくとも実行時には信頼できるsizeof()を持っています(もちろん、ポインタを見てください)。 Javaでは、オブジェクトのサイズを推定する信頼できる方法はありません。 JLSで指定されていないブール値の大きさはどうですか?ブール値の配列はどうですか?またはint配列の大きささえあります。 – JackDaniels

+0

オブジェクトと配列は、とにかく別の方法で処理されます。必要なのはプリミティブのサイズです。プリミティブのサイズはラッパークラスの定数で定義されています。私はちょうどマップやスイッチを使ってサイズを取得することを避ける方法があることを望んでいました。 – Silverclaw

関連する問題