Java|Java中的天使和魔鬼:Unsafe类( 三 )


更简单的sizeof方法实现逻辑是:我们只读取该对象对应的class对象中关于大小的字段值 。 在JVM 1.7 32 位版本上该表示大小的字段偏移量是12 。
normalize是一个将有符号的int类型转为无符号的long类型的方法 。
太棒了这个方法返回的结果和我们之前的sizeof函数是相同的 。
事实上 , 对于合适的 , 安全的 , 准确的sizeof函数最好使用java.lang.instrument包 , 但它需要特殊的JVM参数 。
6、浅拷贝在实现了计算对象浅层大小的基础上 , 我们可以非常容易的添加对象的拷贝方法 。 标准的办法需要修改我们的代码和Cloneable 。 或者你可以实现自定义的对象拷贝函数 , 但它不会变为通用的函数 。
浅拷贝:
toAddress 和 fromAddress 将对象转为它在内存中的地址或者从指定的地址内容转为对象 。
该拷贝函数可以用来拷贝任何类型的对象 , 因为对象的大小是动态计算的 。
【Java|Java中的天使和魔鬼:Unsafe类】注意 在完成拷贝动作后你需要将拷贝对象的类型强转为目标类型 。
7、隐藏密码在Unsafe的直接内存访问方法使用case中有一个非常有趣的用法就是删除内存中不想要的对象 。
大多数获取用户密码的API方法的返回值不是byte[
就是char[
, 这是为什么呢?
这完全是出于安全原因 因为我们可以在不需要它们的时候将数组元素置为失效 。 如果我们获取的密码是字符串类型 , 则密码字符串是作为一个对象保存在内存中的 。 要将该密码字符串置为无效 , 我们只能讲字符串引用职位null , 但是该字符串的内容任然存在内存直到GC回收该对象后 。
这个技巧在内存创建一个假的大小相同字符串对象来替换原来的:
感觉安全了吗?
其实该方法不是真的安全 。 想要真的安全我们可以通过反射API将字符串对象中的字符数组value字段的值修改为null 。
8、多重继承在Java中本来是没有多重集成的 。 除非我们可以将任意的类型转为我们想要的任意类型 。
这段代码将String类添加到Integer的超类集合中所以我们的强转代码是没有运行时异常的 。
有个问题是我们需要先将要转的对象转为Object , 然后再转为我们想要的类型 。 这是为了欺骗编译器 。
9、动态类我们可以在运行时创建类 例如通过一个编译好的class文件 。 将class文件的内容读入到字节数组中然后将该数组传递到合适的defineClass方法中 。
读取class文件内如的代码:
该方式是非常有用的 , 如果你确实需要在运行时动态的创建类 。 比如生产代理类或切面类 。
10、抛出一个异常不喜欢受检异常?这不是问题 。
该方法抛出一个受检异常 , 但是你的代码不需要强制捕获该异常就像运行时异常一样 。
11、快速序列化每个人都知道java标准的序列化的功能速度很慢而且它还需要类拥有公有的构造函数 。
外部序列化是更好的方式 , 但是需要定义针对待序列化类的schema 。
非常流行的高性能序列化库 , 像kryo是有使用限制的 , 比如在内存缺乏的环境就不合适 。
但通过使用Unsafe类我们可以非常简单的实现完整的序列化功能 。
序列化:
通过反射定义类的序列化 。 这个可以只做一次 。
通过Unsafe的getLong getInt getObject等方法获取字段真实的值 。
添加可以恢复该对象的标识符 。
将这些数据写入到输出
当然也可以使用压缩来节省空间 。
反序列化:
创建一个序列化类的实例 , 可以通过方法allocateInstance 。 因为该方法不需要任何构造方法 。
创建schema 和序列化类似
从文件或输入读取或有的字段
使用 Unsafe 的 putLong putInt putObject等方法来填充对象 。
事实上要正确实现序列化和反序列化需要注意很多细节 , 但是思路是清晰的 。


推荐阅读