‘壹’ java new object 占多少字节
Object o=new Object():
在java中空对象占八个字节,对象的引用占四个字节。所以上面那条语句所占的空间是4byte+8byte=12byte.java中的内存是以8的倍数来分配的,所以分配的内存是16byte.
举个例子:
Class O{
int i;
byte j;
String s;
}
其所占内存的大小是空对象(8)+int(4)+byte(1)+String引用(4)=17byte,因要是8的整数倍,所以其占大小为24byte.
当然,如果类里有其他对象的话,也要把其他对象的空间算进去。
其实这个在javaeye的电子期刊上有。
‘贰’ java 里的 ByteArrayInputStream 与ObjectInputStream
ByteArrayInputStream 作为参数提供给 ObjectInputStream 是没有问题的,你的程序唯一不对的地方是不应该将 new byte[1024];一个没有内容的byte数组 做为输入参数提供给 ByteArrayInputStream ,ObjectInputStream 是要读取对象的,那么自然输入也应该是一个对象的字节数组,而很明显 String.getBytes 并不能返回作为字符串对象的字节数组,仅是该字符串对象内容的字节数组。
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream(100);
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject( "asdfsad ");
byte [] bytes = bos.toByteArray();
InputStream s = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(s); //something wrong here
} catch (IOException e) {
e.printStackTrace();
}
‘叁’ 什么是Java字节码
它是程序的一种低级表示,可以运行于Java虚拟机上。将程序抽象成字节码可以保证Java程序在各种设备上的运行
Java号称是一门“一次编译到处运行”的语言,从我们写的java文件到通过编译器编译成java字节码文件(.class文件),这个过程是java编译过程;而我们的java虚拟机执行的就是字节码文件。不论该字节码文件来自何方,由哪种编译器编译,甚至是手写字节码文件,只要符合java虚拟机的规范,那么它就能够执行该字节码文件。
JAVA程序的运行
因为Java具有跨平台特性,为了实现这个特性Java执行在一台虚拟机上,这台虚拟机也就是JVM,Java通过JVM屏蔽了不同平台之间的差异,从而做到一次编译到处执行。JVM位于Java编译器和OS平台之间,Java编译器只需面向JVM,生成JVM能理解的代码,这个代码即字节码,JVM再将字节码翻译成真实机器所能理解的二进制机器码。
字节码是怎么产生的?
我们所编写的程序都是.java格式,通常在执行的时候也许点击一下eclipse的运行键就可以在控制台看到运行结果,但是也可以更酷一些,如果你装了JDK,那就可以直接在以命令行的方式编译运行你的.java文件,编译后会形成.class文件,这个.class文件即字节码。
字节码怎么解读?
上图是编译好的字节码文件,即一堆16进制的字节,如果使用IDE去打开,也许看到的是已经被反编译的我们所熟悉的java代码,但这才是纯正的字节码
这里只介绍字节码由哪些部分组成, 具体的意思自行网络或者看文尾的连接, 有较为详细的讲解
上图即字节码文件的组成部分, Class文件的结构不像XML等描述语言那样松散自由。由于它没有任何分隔符号,
所以,以上数据项无论是顺序还是数量都是被严格限定的。哪个字节代表什么含义,长度是多少,先后顺序如何,都不允许改变, 如上图左侧即每一部分规定的长度
魔数(Magic Number)
魔数是用来区分文件类型的一种标志,一般都是用文件的前几个字节来表示。
比如0XCAFE BABE表示的是class文件,那么有人会问,文件类型可以通过文件名后缀来判断啊?是的,但是文件名是可以修改的(包括后缀),那么为了保证文件的安全性,将文件类型写在文件内部来保证不被篡改。
至于为什么是CAFE BABE估计大家也能猜到, 程序员与咖啡的不解之缘
版本号(Version)
版本号含主版本号和次版本号,都是各占2个字节。在此Demo种为0X0000 0033。其中前面的0000是次版本号,后面的0033是主版本号。通过进制转换得到的是次版本号为0,主版本号为51。高版本的JDK能向下兼容以前版本的Class文件,但不能运行以后版本的Class文件,即使文件格式未发生任何变化. 这就是target参数的用处,可以在使用JDK 1.7编译时指定-target 1.5
常量池(Constant Pool)
常量池是Class文件中的资源仓库, 量池中主要存储2大类常量:字面量和符号引用。字面量如文本字符串,java中声明为final的常量值等等,而符号引用如类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符。常量池是一个表结构,在表的内容前有一个类型的计数器,表示常量池的长度
上面的表中描述了11中数据类型的结构,其实在jdk1.7之后又增加了3种(CONSTANT_MethodHandle_info,CONSTANT_MethodType_info以及CONSTANT_InvokeDynamic_info)。这样算起来一共是14种
访问标志(Access_Flag)
访问标志信息包括该Class文件是类还是接口,是否被定义成public,是否是abstract,如果是类,是否被声明成final。通过上面的源代码,我们知道该文件是类并且是public。
0x 00 21:是0×0020和0×0001的并集。其中0×0020这个标志值涉及到字节码指令
类索引(This Class Name)
类索引用于确定类的全限定名
0×00 03 表示引用第3个常量,同时第3个常量引用第19个常量,查找得”com/demo/Demo”。#3.#19
父类索引(Super Class Name)
0×00 04 同理:#4.#20(java/lang/Object)
接口索引(Interfaces)
通过上边字节码图可以看到,这个接口有2+n个字节,前两个字节表示的是接口数量,后面跟着就是接口的表。我们这个类没有任何接口,所以应该是0000。果不其然,查找字节码文件得到的就是0000。
字段表集合(fields)
字段表用于描述类和接口中声明的变量。这里的字段包含了类级别变量以及实例变量,但是不包括方法内部声明的局部变量。接下来就是2+n个字段属性。我们只有一个属性a,所以应该是0001。查找文件果不其然是0001。
该区域含有字段的访问标志, 访问权限, 字段的名称索引, 字段的描述符索引, 属性表
描述符的作用就是用来描述字段的数据类型、方法的参数列表和返回值。而属性表就是为字段表和方法表提供额外信息的表结构。对于字段来说,此处如果将字段声明为一个static final msg = "aaa"的常量,则字段后就会跟着一个属性表,其中存在一项名为ConstantValue,指向常量池中的一个常量,值为的"aaa"。
方法(methods)
包含访问标志表, 方法名索引 , 方法描述符索引, 属性表数量,等
Attribute
0×0001 :同样的,表示有1个Attributes了。
0x000f : #15(“SourceFile”)
0×0000 0002 attribute_length=2
0×0010 : sourcefile_index = #16(“Demo.java”)
SourceFile属性用来记录生成该Class文件的源码文件名称。
‘肆’ java Object和byte数组互相转换中遇到的问题
可能跟hashmap的hashcode相关
‘伍’ java 对象转换成字节数组, 字节数据转成对象,出现错误请高手指教
对象序列化好了。
不要是内部类。
正常的
public Object byteArrayToObject(byte[] buffer)throws Exception{
Object ob = null;
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(buffer));
ob = ois.readObject();
ois.close();
return ob;
}
public byte[] ObjectToByteArray(DemoObject obj)throws Exception{
byte [] bytes=null;
ByteArrayOutputStream baos= new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
bytes=baos.toByteArray();
baos.close();
return bytes;
}
调用示范
test.byteArrayToObject( test.ObjectToByteArray(demo) );
得到结果,正常的。
‘陆’ java虚拟机的数据类型
Java虚拟机支持Java语言的基本数据类型有8种,注意String不是基本数据类型如下:
boolean://1字节有符号整数的补码
byte://1字节有符号整数的补码
short://2字节有符号整数的补码
int://4字节有符号整数的补码
long://8字节有符号整数的补码
float://4字节IEEE754单精度浮点数
double://8字节IEEE754双精度浮点数
char://2字节无符号Unicode字符
几乎所有的Java类型检查都是在编译时完成的。上面列出的原始数据类型的数据在Java执行时不需要用硬件标记。操作这些原始数据类型数据的字节码(指令)本身就已经指出了操作数的数据类型,例如iadd、ladd、fadd和dadd指令都是把两个数相加,其操作数类型别是int、long、float和double。虚拟机没有给boolean(布尔)类型设置单独的指令。boolean型的数据是由integer指令,包括integer返回来处理的。boolean型的数组则是用byte数组来处理的。虚拟机使用IEEE754格式的浮点数。不支持IEEE格式的较旧的计算机,在运行Java数值计算程序时,可能会非常慢。
虚拟机支持的其它数据类型包括:
object//对一个Javaobject(对象)的4字节引用
returnAddress//4字节,用于jsr/ret/jsr-w/ret-w指令
注:Java数组被当作object处理。
虚拟机的规范对于object内部的结构没有任何特殊的要求。在Sun公司的实现中,对object的引用是一个句柄,其中包含一对指针:一个指针指向该object的方法表,另一个指向该object的数据。用Java虚拟机的字节码表示的程序应该遵守类型规定。Java虚拟机的实现应拒绝执行违反了类型规定的字节码程序。Java虚拟机由于字节码定义的限制似乎只能运行于32位地址空间的机器上。但是可以创建一个Java虚拟机,它自动地把字节码转换成64位的形式。从Java虚拟机支持的数据类型可以看出,Java对数据类型的内部格式进行了严格规定,这样使得各种Java虚拟机的实现对数据的解释是相同的,从而保证了Java的与平台无关性和可移植性。
‘柒’ java中怎么把byte转成Object
byte bb=2;
Object oo=bb;
Byte b=new Byte((byte) 1);
Object o=b;
System.out.println(o);
System.out.println(oo);