面试:Object 方法与原理
Object 方法与原理
1. clone 方法
clone 方法的用法是对象的浅拷贝和深拷贝,clone是浅拷贝是对基本类型的值传递,对引用类型进行引用类型般的拷贝。深拷贝并拷贝对象的所有属性,并拷贝属性所指向的动态分配内存。实现深拷贝的方法有:1. 重写clone方法,对其内部的引用类型再进行clone. 2.通过序列化实现深拷贝,将拷贝的对象写入内存的字节流中,然后在读出转换为对象。新对象和原对象不存在地址的共享,所以实现深拷贝。3. 可以采用反射来实现深拷贝,迭代的依次拿到字段,并给新对象赋值。
拓展:java序列化的问题?
java 序列化是对对象的压缩便于存储和传输,但是为什么序列化不是默认添加,而是需要实现一个标志接口。
最大的问题是对象的引用问题,例如现在有A,B两个类。
此时空间上分配两个空间来存储 A,B对象。
如果B类中含有一个指向A类对象的引用,因为对象b包含对对象a的引用,所以系统会自动的将a的数据复制一份到b中,内存分配了三个空间,而对象a同时在内存中存在两份。必须对a进行修改等操作,需要维护每一份的拷贝来达到数据的一致性。不是默认序列化很重要的一个原因就是为了安全,java的类安全机制是做的很好的.
序列化的漏洞,如果Java应用对用户输入,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,非预期的对象在产生过程中就有可能带来任意代码执行。
序列化ID的作用?
序列化ID起着关键的作用,java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。反序列化时,JVM会把传来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。
2. getClass 方法
getClass, .class, getName 的区别:
getClass 只能使用在实例类,是运行时获得类型,.class 在编译时获得一个类的对象,getName 是获得对象的名称
class.forName() jvm 查找并加载指定类,如果类中有静态初始化器,执行代码段。
newInstance() 创建对象,必须保证1.类已经加载,2.类已经连接。java1.9中,newInstance已经弃用,使用class.getDeclaredConstructor().newInstance();
3. equals 方法
“==” 比较两个对象是否是同一个对象,比较的两个对象的地址(基本数据是值,引用是地址)
没有覆盖equals和“==”一样,我们常见的对象类型,都是已经重写equals比较的是对象的内容
当然Integer 对象,有个静态的类IntegerCache,当缓存数值为-128 ~ 127 下限是固定的,127上限可以调节,当定义两个数值在其中之间,“== ” 比较是 true, 否则“==” 比较是false
4. hashcode 方法
- 如果 equals 方法判断两个对象相等,hashcode 也一定相等,hashcode 相等,equals 并不一定会相等,先用hashcode判断, 可以加快判断的速度。
- 重写 equals 一定要重写 hashcode
4. wait() notify() notifyAll()
wait() notify() notifyAll() 他们必须用在 同步代码块内, 调用wait()就是释放锁,释放锁的前提是必须要获得锁,先获得锁才能释放锁。
wait() 是线程自动释放他们所占有的对象锁,并等待notify.
notify(),唤醒一个正在wait当前对象锁的线程,并让其拿到对象。
notifyAll() 唤醒所有正在wait当前对象锁的线程,接下来会竞争对象锁。平常使用过程中,还需要注意把wait()放到循环里面。如果采用if判断的话,wait线程唤醒会直接处理接下来的业务,但是可能出现另一种情况,条件语句已经不满足业务处理的条件了,所以需要再次进行判断。