面试题(3)-Object类中有哪些方法及作用
Object类中有哪些方法及作用
1.Object类的定义
Object类是所有类的父类,也就是说任何一个类在定义时候如果没有明确的继承一个父类的话,那么它就是Object类的子类。
由于Java里面的类的继承关系一直都存在(除了Object类)
Object类是所有类的父类的好处:利用Object类可以接收全部类的对象,因为可以向上自动转型,所以如果不确定参数的实际类型,那么Object类就是最好的选择,最后强制向下转型为所需类型即可。
Object类提供了一个无参构造方法:public Object(),因为:类对象实例化时,子类构造方法一定会默认调用父类的无参构造。
2.Object类中的方法及作用
1.hashCode方法
在Object代码中,hashCode是native的,非java代码实现。主要原因是它的实现方法是通过将对象在内存中所处于的位置转换成数字,这个数字就是hashCode。但是这个内存地址实际上java程序并不关心也是不可知的。这个地址是由JVM维护并保存的,所以实现是native的。
在程序运行过程中,同一个对象的hashCode无论执行多少次都要保持一致。但是,在程序重启后同一个对象的hashCode不用和之前那次运行的hashCode保持一致。但是考虑如果在分布式的情况下,如果对象作为key,最好还是保证无论在哪台机器上运行多少次,重启多少次,不同机器上,同一个对象(指的是两个equals对象),的hashCode值都一样。 例如这里的Object对于hashCode的实现,在当前次运行,这个对象的存储地址是不变的。所以hashCode不变,但是程序重启后就不一定了。
String的hashCode实现:
String就是一种典型的适合在分布式的情况下作为key的存储对象。无论程序何时在哪里运行,同一个String的hashCode结果都是一样的。
2.equals方法
该方法用于比较两个对象,如果这两个对象引用指向的是同一个对象,那么返回 true,否则返回 false。一般 equals 和 == 是不一样的,但是在 Object 中两者是一样的。子类一般都要重写这个方法。
String的equals实现:
注意:
如果两个对象是euqal的,那么hashCode要相同
不强制对于不相等的对象的hashCode一定要不同。
3.getClass方法
final 方法,获取对象的运行时 class 对象,class 对象就是描述对象所属类的对象。这个方法通常是和 Java 反射机制搭配使用的。
getClass()和.class的作用与区别
getClass()是Object类的方法,该方法的返回值类型是Class类,通过getClass()方法可以得到一个Class类的对象。
.class返回的也是Class类型的对象。所以,如果getClass()和.class返回的内容相等,说明是同一个对象。
既然都可以得到Class的对象,关于getClass()和.class的区别:
getClass()方法,有多态能力,运行时可以返回子类的类型信息。
.class是没有多态的,是静态解析,编译时可以确定类型信息。
4.toString方法
该方法用得比较多,一般子类都有覆盖。默认的实现就是class名字@hashcode的值(如果hashCode()方法也是默认的话,那么就是如之前所述地址)
5.clone方法
该方法也是一个native方法, 此方法是保护方法, 实现对象的浅复制, 只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
默认的 clone 方法是浅拷贝。所谓浅拷贝,指的是对象内属性引用的对象只会拷贝引用地址,而不会将引用的对象重新分配内存。深拷贝则是会连引用的对象也重新创建。
主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里将参数改变,这时就需要在类中复写clone方法。
6.registerNatives方法
Java有两种方法:Java方法和本地方法。Java方法是由Java语言编写,编译成字节码,存储在class文件中。本地方法是由其他语言(比如C,C++,或者汇编)编写的,编译成和处理器相关的机器代码。本地方法保存在动态连接库中,格式是各个平台专有的。Java方法是平台无关的,单本地方法却不是。运行中的Java程序调用本地方法时,虚拟机装载包含这个本地方法的动态库,并调用这个方法。本地方法是联系Java程序和底层主机操作系统的连接方法。
由此可知,本地方法的实现是由其他语言编写并保存在动态连接库中,因而在java类中不需要方法实现。registerNatives本质上就是一个本地方法,但这又是一个有别于一般本地方法的本地方法,从方法名我们可以猜测该方法应该是用来注册本地方法的。对,你猜的没错。上述代码的功能就是先定义了registerNatives()方法,然后当该类被加载的时候,调用该方法完成对该类中本地方法的注册。这里你可能会有一些疑惑,比如,到底注册了哪些方法?为什么要注册?具体又是怎么注册的?
我们首先看第一个问题:到底注册了哪些方法?细心的你可能还会发现,在Object类中,除了有registerNatives这个本地方法之外,还有hashCode()、clone()等本地方法,而在Class类中有forName0()这样的本地方法等等。也就是说,凡是包含registerNatives()本地方法的类,同时也包含了其他本地方法。所以,显然,当包含registerNatives()方法的类被加载的时候,注册的方法就是该类所包含的除了registerNatives()方法以外的所有本地方法。
7.notify方法和notifyAll方法
final 方法,主要用于唤醒在该对象上等待的某个线程或者是所有线程。
8.wait方法
wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
(1)其他线程调用了该对象的notify方法。
(2)其他线程调用了该对象的notifyAll方法。
(3)其他线程调用了interrupt中断该线程。
(4)时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
参数说明:
该方法导致当前线程等待,直到其他线程调用此对象的 notify() 方法或notifyAll()方法,或在指定已经过去的时间。此方法类似于 wait 方法的一个参数,但它允许更好地控制的时间等待一个通知放弃之前的量。实时量,以毫微秒计算,计算公式如下:
在所有其他方面,这种方法与 wait(long timeout) 做同样的事情。特别是 wait(0, 0) 表示和 wait(0) 相同。
9.finalize方法
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
首先finalize方法是在垃圾回收时,用于确认该对象是否确认被回收的一个标记过程。
确认一个对象真正被回收需要经历两次标记过程:
可达性分析没有引用,这是第一次标记,是否有必要执行finalize方法,如果对象没有重写finalize方法或者finalize方法已经被调用过了,那么finalize方法就是没有必要执行的,没有必要执行finalize方法的对象就会被直接回收。如果对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机创建、低优先级的finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象的finalize()执行缓慢,极端情况下死循环,那么就会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。
finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()成功拯救自己——只需要重新与引用链上的任何一个对象建立关联即可,譬如把this关键字赋值给某个类的变量或者对象的成员变量,那么第二次标记时它将会被移出“即将回收”的集合;如果对象这时还没有逃脱,那么它就真正被回收了。
finalize方法不是一定会执行,只有在该方法被重写的时候才会执行
inalize方法只会被执行一次
对象可以在finalize方法中获得自救,避免自己被垃圾回收,同样自救也只能一次
不推荐Java程序员调用该方法,因为finalize方法代价很大