有没有直接的方法来计算原始字段的大小?
Is there a direct way to calculate size of primitive fields?
我正在编写一个小型序列化实用程序,我想计算将对象写入字节数组需要保留多少字节。
假设我有一个 class 和一些 fields/getters 像
int age;
String name;
Colour colour;
boolean active;
...
我以为我可以使用反射来遍历字段并查看它们的大小,但我所能做的就是检查它们是否是原始的。这是一个开始,因为我会使用 short 作为对象的偏移量。好的,我可以使用
if(field.getType() == int.class) {
size = Integer.BYTES;
}
或者使用地图。这并不难,因为我只需要知道图元的大小。但是出于好奇:有什么直接的方法吗?
编辑澄清:
我正在使用它来序列化数据,基本上类似于 DataOutput/InputStream,但我想对自己进行一些调整。
API class 看起来像这样:
public final void write(int i) {
checkBounds(Integer.BYTES);
PrimitiveWriteUtil.write(i, data, marker);
advance(Integer.BYTES);
}
实际工作由实用程序完成 class:
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);
}
所以,我想知道我的字节数组所需的大小,这样我就可以避免以后检查和调整大小的工作。
图元的大小为defined in JLS 4.2。
byte
是1字节,short
和char
是2字节,int
和float
是32字节,double
和long
是 64.
如果您需要将其用于纯粹的理论练习以外的任何目的,则依赖精确的数字可能是危险的。
由于要使用它来分配字节数组的大小以进行序列化,请考虑使用 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);
使用 MyObject 助手 class 的完整工作代码
这并没有直接回答你的问题,但我相信这是实现你想要做的事情的正确方法。
您可以通过实现 readObject 和 writeObject 方法来修改序列化的发生方式。例如,看看 http://www.byteslounge.com/tutorials/java-custom-serialization-example.
嗯,您已经知道 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;
}
}
但是在底层操作上,这并不是最简单的方案,如果你不喜欢,我完全理解。
在那种情况下,答案是没有简单/直接的方法来获取这些数字,因此,从类型到数字的映射或线性探测这八种可能性,都是不可避免的,因此,也是最简单(可用)的解决方案。
我正在编写一个小型序列化实用程序,我想计算将对象写入字节数组需要保留多少字节。 假设我有一个 class 和一些 fields/getters 像
int age;
String name;
Colour colour;
boolean active;
...
我以为我可以使用反射来遍历字段并查看它们的大小,但我所能做的就是检查它们是否是原始的。这是一个开始,因为我会使用 short 作为对象的偏移量。好的,我可以使用
if(field.getType() == int.class) {
size = Integer.BYTES;
}
或者使用地图。这并不难,因为我只需要知道图元的大小。但是出于好奇:有什么直接的方法吗?
编辑澄清: 我正在使用它来序列化数据,基本上类似于 DataOutput/InputStream,但我想对自己进行一些调整。
API class 看起来像这样:
public final void write(int i) {
checkBounds(Integer.BYTES);
PrimitiveWriteUtil.write(i, data, marker);
advance(Integer.BYTES);
}
实际工作由实用程序完成 class:
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);
}
所以,我想知道我的字节数组所需的大小,这样我就可以避免以后检查和调整大小的工作。
图元的大小为defined in JLS 4.2。
byte
是1字节,short
和char
是2字节,int
和float
是32字节,double
和long
是 64.
如果您需要将其用于纯粹的理论练习以外的任何目的,则依赖精确的数字可能是危险的。
由于要使用它来分配字节数组的大小以进行序列化,请考虑使用 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);
使用 MyObject 助手 class 的完整工作代码
这并没有直接回答你的问题,但我相信这是实现你想要做的事情的正确方法。
您可以通过实现 readObject 和 writeObject 方法来修改序列化的发生方式。例如,看看 http://www.byteslounge.com/tutorials/java-custom-serialization-example.
嗯,您已经知道 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;
}
}
但是在底层操作上,这并不是最简单的方案,如果你不喜欢,我完全理解。
在那种情况下,答案是没有简单/直接的方法来获取这些数字,因此,从类型到数字的映射或线性探测这八种可能性,都是不可避免的,因此,也是最简单(可用)的解决方案。