2016-07-11 3 views
2

작은 직렬화 유틸리티를 작성 중이며 바이트 배열에 객체를 쓰려면 예약해야하는 바이트 수를 계산하고 싶습니다. 의 나는 내가 필드를 반복하고 그들이 가지고있는 크기를 찾기 위해 반사를 사용할 수 있다고 생각원시 필드의 크기를 직접 계산할 수 있습니까?

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

같은 몇 가지 필드/게터와 클래스가 있다고 가정 해 봅시다,하지만 그들은 원시인지 내가 할 수있는 확인한다. 어느 쪽이 시작입니까? 객체의 오프셋을 short로 사용하기 때문입니다. 좋아, 사용할 수 있습니다

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입니다.

byte

는 1 바이트, shortchar은 2, intfloat입니다이다 (32)는에 의존, 단순한 이론적 인 운동보다 더 용도로 사용해야하는 경우, doublelong는 64

+0

예 ... 제가 말했듯이, 저는 Short에 대한 매핑을 사용할 수 있습니다. Bytes, Integer.Bytes, 등등. 내 질문은 그것이 필요한지 아니면 ** 직접 ** 필드 크기를 얻는 다른 방법이 있는지 여부입니다. – Silverclaw

-1

있습니다 정확한 숫자는 위험 할 수 있습니다.

ByteArrayOutputStream을 사용하여 직렬화를 위해 바이트 배열의 크기를 할당하려는 경우이를 고려하십시오. Codiva online compiler IDE에서 MyObject를 헬퍼 클래스와

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

전체 작업 코드입니다.

이 질문은 귀하의 질문에 직접적으로 대답하는 것은 아니지만 귀하가하고자하는 바를 이루기위한 올바른 방법이라고 생각됩니다.


readObject 및 writeObject 메소드를 구현하여 직렬화의 방법을 수정할 수 있습니다. 예를 들어 http://www.byteslounge.com/tutorials/java-custom-serialization-example을 살펴보십시오.

+0

크기에 의지하지 않는 것은 위험하지 않습니다. 이것은 Java가 아니고 C가 아닙니다. – chrylis

+0

사실이 아닙니다. C에서 적어도 sizeof()는 런타임에 신뢰할 수 있습니다 (물론 포인터를 봐야합니다). Java에서는 객체의 크기를 예측할 수있는 신뢰할만한 방법이 없습니다. JLS에서 지정되지 않은 부울 크기는 얼마입니까? 부울 배열은 어떻습니까? 또는 int 배열의 크기 일 수도 있습니다. – JackDaniels

+0

개체와 배열은 어쨌든 다르게 처리됩니다. 필요한 것은 래퍼 클래스의 상수 값에 의해 정의되는 프리미티브 크기입니다. 나는 방금지도를 사용하거나 크기를 바꾸는 것을 피하는 방법이 있기를 바랐다. – Silverclaw

관련 문제