Object:我是所有类的祖先
java.lang.Object 这个类看似其貌不扬,但在Java中的地位就像南方古猿"lucy"在人类中的地位一样——我们所有人的身体里都有她的基因。
当一个类SonClass没有显式的父类时,编译器就会默认Object是它的父类;反之SonClass有显示的父类FatherClass,沿着FatherClass向上追溯,会发现它也是Object类的血脉,所以Object是所有类的祖先。
解析前调
方法属性
方法名 | 关键字 | 返回值 |
---|---|---|
registerNatives | private static native | void |
getClass | public final native | Class |
hashCode | public native | int |
equals | public | boolean |
clone | protected native | Object |
toString | public | String |
notify | public final native | void |
notifyAll | public final native | void |
wait | public final native | void |
关键字
Object类中的方法中使用的关键字除了native关键字,剩下的都很常见。那我们就着重理解一下native关键字。
Java之所以做到了平台无关性和可移植性,是因为Java不直接和硬件层面进行直接交互。那么Java如何将操作同步到硬件层面呢,那就要用到Java native interface(JNI)了,native关键字标识的java方法为本地方法,jdk底层是有c/c++编写的程序编译后dll文件,java加载dll文件后,可用通过本地方法调用dll中函数。JNI只可调用c++或C吗,答案当然是否定的,具体请参考这篇文章native详解。
方法源码解析
registerNatives方法
作用:创建对象时,先加载加载本地Object对应的.dll文件
getClass
作用:返回Object的运行类
hashcode
这个方法返回对象的哈希码值,这个方法与哈希表的性能有关,它的实现方法是通过将对象在内存中所处于的位置转换成数字,这个数字就是hashCode。但是这个内存地址实际上java程序并不关心也是不可知的。这个地址是由JVM维护并保存的,所以实现是native的。通用的约定是:
(1)在同个java环境下,相同的对象必须有同样的哈希码值;但是对于这个具体的整数值(哈希码)在两个相同应用下不需要一定要保持一致(后期会学到如何构建哈希表,一个对象在不同的哈希表下会有不同的哈希值)。
(2)如果两个对象通过equals方法是相等的,则他们的哈希值相同。
(3)反过来,如果两个对象通过equals方法是不相等的,他们的哈希值不一定不同。但是开发者应该明白,对于不相等的两个对象返回不同的哈希值会提高哈希表的性能。
equals
要注意,这里比较的是对象的内存地址
public boolean equals(Object obj) {
return (this == obj);
}
clone
注意:这里的clone是浅克隆
何为浅克隆,就是克隆就是复制一个对象的复本.若只需要复制对象的字段值(对于基本数据类型,如:int,long,float等,则复制值;对于复合数据类型仅复制该字段值,如数组变量则复制地址,对于对象变量则复制对象的reference。
举个例子:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ShadowClone implements Cloneable{
private int cint;
private long clong;
private int[] intArray;
@Override
public ShadowClone clone(){
ShadowClone shadowClone = null;
try {
shadowClone = (ShadowClone)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return shadowClone;
}
public static void main(String[] args) {
ShadowClone shadowClone1 = new ShadowClone();
shadowClone1.setCint(2);
shadowClone1.setClong(3L);
shadowClone1.setIntArray(new int[]{1,2,3,4});
ShadowClone shadowClone2 = shadowClone1.clone();
System.out.println("不改变克隆对象shadowClone1-----------");
System.out.println("shadowClone1数值 "+shadowClone1.toString());
System.out.println("shadowClone2数值 "+shadowClone2.toString());
System.out.println("---------------------结束");
int[] afterArray = shadowClone2.getIntArray();
afterArray[0] = 100;
shadowClone2.setCint(200);
shadowClone2.setClong(300L);
shadowClone2.setIntArray(afterArray);
System.out.println("改变克隆对象shadowClone1-----------");
System.out.println("shadowClone1数值 "+shadowClone1.toString());
System.out.println("shadowClone2数值 "+shadowClone2.toString());
System.out.println("---------------------结束");
}
}
结果如下
不改变克隆对象shadowClone1-----------
shadowClone1数值 ShadowClone(cint=2, clong=3, intArray=[1, 2, 3, 4])
shadowClone2数值 ShadowClone(cint=2, clong=3, intArray=[1, 2, 3, 4])
---------------------结束
改变克隆对象shadowClone1-----------
shadowClone1数值 ShadowClone(cint=2, clong=3, intArray=[100, 2, 3, 4])
shadowClone2数值 ShadowClone(cint=200, clong=300, intArray=[100, 2, 3, 4])
---------------------结束
与克隆相关的知识请参考https://blog.csdn.net/bigconvience/article/details/25025561
notify
不能被重写,用于唤醒一个在因等待该对象(调用了wait方法)被处于等待状态(waiting 或 time_wait)的线程,该方法只能同步方法或同步块中调用,即经过 synchronized修饰过。
notifyAll
不能被重写,用于唤醒所有在因等待该对象(调用wait方法)被处于等待状态(waiting或time_waiting)的线程,该方法只能同步方法或同步块中调用,即经过 synchronized修饰过。
wait(long timeOut)
用于在线程调用中,导致当前线程进入等待状态(time_waiting),timeout单位为毫秒,该方法只能同步方法或同步块中调用,超过设置时间后线程重新进入可运行状态
finalize
这个方法用于当对象被回收时调用,这个由JVM支持,Object的finalize方法默认是什么都没有做,如果子类需要在对象被回收时执行一些逻辑处理,则可以重写finalize方法。