2016-07-11 23 views
2

Ich schreibe ein kleines Serialisierungs-Dienstprogramm, und ich möchte berechnen, wie viele Bytes ich reservieren muss, um ein Objekt in ein Byte-Array zu schreiben. Sagen wir, ich habe eine Klasse mit ein paar Felder/Getter wieGibt es einen direkten Weg, die Größe primitiver Felder zu berechnen?

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

Ich dachte, ich Reflexion über Felder zu durchlaufen benutzen konnten und sehen, welche Größe sie haben, aber alles, was ich tun kann, ist zu überprüfen, ob sie primitiv sind. Was ist ein Anfang, da ich einen Short als Offset für Objekte verwenden würde. Okay, könnte ich

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

oder eine Karte verwenden. Es wäre nicht so schwer, da ich nur die Größe von Primitiven kennen müsste. Aber aus Neugier: Gibt es einen direkten Weg?

bearbeiten um zu klären: Ich benutze es um Daten zu serialisieren, im Grunde wie DataOutput/InputStream, aber mit einigen Verbesserungen, die ich für mich selbst wollte.

Die API-Klasse sieht wie folgt aus:

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

Die eigentliche Arbeit durch eine Utility-Klasse getan wird:

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); 
} 

Also, ich die erforderliche Größe meines Byte-Array wissen wollen, so Ich kann den Aufwand der Überprüfung und Größenanpassung später vermeiden.

+0

möglich duplizieren von: http://StackOverflow.com/Questions/52353/in-java-what-is-the-best-way-to-Determine-the-Size-of-an-Object –

+0

Ich schaute durch das vorher und es passt absolut nicht zu meinem Anwendungsfall. Ich möchte nur die Größe aller primitiven Felder von _one_ Objekt zur Laufzeit erhalten. – Silverclaw

+0

Warum? Schreiben Sie einfach in einen ByteArrayOutputStream und holen Sie sich daraus das Byte-Array. Es wird die richtige Größe sein. – EJP

Antwort

1

Nun, Sie wissen bereits über das BYTES Feld, das Problem ist, diese Felder sind in den entsprechenden Wrapper-Typen deklariert und es gibt keine einfache Möglichkeit, den Wrappertyp für einen primitiven Typ zu erhalten.In Bezug auf die Codegröße, der einfachste Weg, es zu bekommen, ist das Feld über das get Verfahren zu lesen, die Verhüllung des Grundwert bedeutet:

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; 
    } 
} 

jedoch in Bezug auf die zugrunde liegenden Vorgänge, ist es nicht die einfachste Lösung und wenn Sie es nicht mögen, verstehe ich das völlig. In diesem Fall ist die Antwort, dass es keinen einfachen/direkten Weg gibt, diese Zahlen zu erhalten, so dass entweder eine Zuordnung von Typ zu Zahl oder lineares Sondieren für diese acht Möglichkeiten unvermeidbar ist und daher auch die einfachste (verfügbare) Lösung.

+0

* seufz * Ich denke, das ist die beste Antwort, die ich bekommen werde. Danke für die Bemühung. – Silverclaw

1

Die Größe der Grundelemente ist defined in JLS 4.2.

byte ist 1 Byte, short und char sind 2, int und float sind 32, double und long sind 64.

+0

Ja ... und wie gesagt, ich könnte einfach eine Zuordnung zu Short verwenden. Bytes, Integer.Bytes, etc. Meine Frage ist, ob das notwendig ist oder ob es einen alternativen Weg gibt, ** direkt ** die Feldgröße zu bekommen. – Silverclaw

-1

Wenn Sie es für jeden Zweck mehr als nur eine theoretische Übung verwenden müssen, auf die Berufung genaue Nummer kann gefährlich sein.

Da Sie die Größe des Bytearrays für die Serialisierung zuweisen möchten, sollten Sie ByteArrayOutputStream verwenden.

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); 

Voll funktions Code mit der MyObject Hilfsklasse bei Codiva online compiler IDE.

Dies beantwortet Ihre Frage nicht direkt, aber ich glaube, dies ist der richtige Weg, um das zu erreichen, was Sie versuchen zu tun.


Sie können die Implementierung der Serialisierung ändern, indem Sie die Methoden readObject und writeObject implementieren. Schauen Sie sich zum Beispiel http://www.byteslounge.com/tutorials/java-custom-serialization-example an.

+0

Es ist nicht gefährlich, sich auf die Größe zu verlassen. Dies ist Java, nicht C. – chrylis

+0

Nicht wahr. Zumindest in C hast du sizeof(), das zur Laufzeit zuverlässig ist (natürlich solltest du nach Zeigern suchen). In Java gibt es keine vertrauenswürdige Möglichkeit, die Größe eines Objekts zu schätzen. Rate was ist die Größe von Boolean, die nicht in JLS angegeben ist? Wie wäre es mit einem Booleschen Array? oder sogar die Größe des int-Arrays. – JackDaniels

+0

Objekte und Arrays werden trotzdem anders behandelt. Alles, was ich brauche, ist die Größe von Primitiven, die durch konstante Werte in ihren Wrapper-Klassen definiert sind. Ich hoffte nur, dass es eine Möglichkeit geben würde, eine Karte oder einen Schalter zu vermeiden, um die Größe zu erhalten. – Silverclaw