JDK源码之-java.lang.Object
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize()throwsThrowable { }
equals 方法
// equals 方法
// 在面试中面试官经常会问 equals() 方法和 == 运算符的区别,== 运算符用于比较基本类型的值是否相同而 equals 用于比较两个对象是否相等,那么有个问题来了,两个对象怎么才算是相等的呢。 看object中的equals实现
public boolean equals(Object obj)
{
return (this == obj);
}
// 在Object中equals和==是等价的。所以在Object中两个对象的引用相同,那么一定就是相同的。在我们自定义对象的时候一定要重写equals方法。我参考了以下网上的资料来分析一下String中重写的 equals方法:
public boolean equals(Object anObject)
{
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length)
{
char v1[] = value; char v2[] = anotherString.value;
int i = 0;
while (n-- != 0)
{
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
// String 是引用类型,比较时不能比较引用是否相等,重点是字符串的内容是否相等。所以 String 类定义两个对象相等的标准是字符串内容都相同。
// 在Java规范中,对 equals 方法的使用必须遵循以下几个原则:
// 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
// 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
// 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改
// 对于任何非空引用值 x,x.equals(null) 都应返回 false
// 我们在判断的时候使用了instanceof关键字来判断运行的时候是否是指定的类型
// java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。
// 注意:使用getClass是要根据情况而定,使用getClass 不符合多态的定义
// 那什么时候使用instanceof,什么时候使用getClass呢?
// 如果子类能够拥有自己的相等概念,则对称性需求将强制采用 getClass 进行检测。
// 如果有超类决定相等的概念,那么就可以使用 instanceof 进行检测,这样可以在不同的子类的对象之间进行相等的比较。
// 还有就是一定要注意无论何时重写此方法,通常都必须重写hashCode方法,以维护hashCode方法的一般约定,该方法声明相等对象必须具有相同的哈希代码。
getClass 方法
// getClass 方法
// 我们看到getClass被native标识,这代表这是调用本地方法实现
// native是由操作系统帮我们实现
// 文档说明的是调用getClass返回一个运行时的类。
// 可以看出getClass是返回一个运行时的对象。class是返回编译的类对象
// 可以看到getClass方法被final修饰,说明此方法不能被重写。
hashCode 方法
hashCode也是一个被native修饰的本地方法
注释说明的是返回该对象的哈希值。那么它有什么作用呢?
主要是保证基于散列的集合,如HashSet、HashMap以及HashTable等,在插入元素时保证元素不可重复,同时为了提高元素的插入删除便利效率而设计;主要是为了查找的便捷性而存在。
就比如使用Set进行举例子。
Set集合是不可重复的,如果每次添加数据都使用equals去做对比的话,插入十万条数据就要对比十万次效率是非常慢的。
所以在添加数据的时候使用了哈希表,哈希算法也称之为散列算法,当添加一个值的时候先算出它的哈希值根据算出的哈希值将数据插入指定位置。这样的话就避免了一直调用equals造成的效率隐患。同时有以下条件:
如果位置为空则直接添加
如果位置不为空,判断两个元素是否相同如果相同则不存储。
还有一种情况是两个元素不相同,但是hashCode相同,这就是哈希碰撞。
如果发生了hash key相同的情况就在相同的元素创建一个链表。把所有相同的元素存放在链表中。
可以看出T1的哈希和T2相同,但是元素不同,所以现在会形成一个链来存储。
toString 方法
可以看出toString是返回的类名加16进制无符号整数形式返回此哈希码的字符串表示形式。
运行输出结果:
直接输出对象和使用toString是一样的
如果想要toString输出属性内容则需要重写toString方法
finalize 方法
// finalize用户垃圾回收是由JVM调用。
registerNatives
// 上面说到native是调用本地实现方法,而registerNatives则是对本地方法注册,装载本地库。在Object初始化时执行。