Java Object
一、什么是Java Object
Java Object 类是所有类的父类,也就是说 Java 的所有类都继承了 Object,子类可以使用 Object 的所有方法。(得了,就是Object就是所有类的爸爸)
Object 类位于 java.lang 包中,编译时会自动导入,我们创建一个类时,如果没有明确继承一个父类,那么它就会自动继承 Object,成为 Object 的子类。
Object 类可以显示继承,也可以隐式继承,以下两种方式时一样的:
显示继承:
public class Test extends Object{
}
隐式继承:
public class Test{
}
下面我们来分析一下Object的源码:
package java.lang;
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
//获取对象的运行时对象的类
public final native Class<?> getClass();
//获取对象的 hash 值
public native int hashCode();
//比较两个对象是否相等
public boolean equals(Object obj) {
return (this == obj);
}
//创建并返回一个对象的拷贝
//clone 方法是浅拷贝,对象内属性引用的对象只会拷贝引用地址,而不会将引用的对象重新分配内存,相对应的深拷贝则会连引用的对象也重新创建。
//浅克隆复制出来的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。也就是说,克隆之后的对象和之前的对象仍存在一些关联,克隆程度不高,因此也被称为浅克隆。
//而深克隆复制出来的所有变量都含有与原来的对象相同的值,那些引用其他对象的变量将指向复制出来的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
protected native Object clone() throws CloneNotSupportedException;
//返回对象的字符串表示形式
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
//唤醒在该对象上等待的某个线程
public final native void notify();
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);
}
//当 GC (垃圾回收器)确定不存在对该对象的有更多引用时,由对象的垃圾回收器调用此方法。
protected void finalize() throws Throwable { }
}
二、Object类的方法
1、创建并返回一个对象的拷贝protected Object clone()
**
* @Description: $ clone()案例
* @Author: dyq
* @Date: $2021年2月4日
*/
public class CloneTest implements Cloneable {
// 声明变量
String name;
int age;
public static void main(String[] args) {
// 创建对象
CloneTest obj1 = new CloneTest();
// 初始化变量
obj1.name = "科隆";
obj1.age = 20;
// 打印输出
System.out.println(obj1.name); // 科隆
System.out.println(obj1.age); //20
try {
// 创建 obj1 的拷贝
CloneTest obj2 = (CloneTest) obj1.clone();
// 使用 obj2 输出变量
System.out.println("clone后:");
System.out.println(obj2.name); // 科隆
System.out.println(obj2.age); //20
} catch (Exception e) {
System.out.println(e);
}
}
}
结果输出:
科隆
20
clone后:
科隆
20
clone 方法是浅拷贝,对象内属性引用的对象只会拷贝引用地址,而不会将引用的对象重新分配内存,相对应的深拷贝则会连引用的对象也重新创建。
那么浅克隆跟深克隆有什么区别?
浅克隆复制出来的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。也就是说,克隆之后的对象和之前的对象仍存在一些关联,克隆程度不高,因此也被称为浅克隆。
而深克隆复制出来的所有变量都含有与原来的对象相同的值,那些引用其他对象的变量将指向复制出来的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
2、比较两个对象是否相等 boolean equals(Object obj)
Object equals() 方法用于比较两个对象是否相等。
equals() 方法比较两个对象,是判断两个对象引用指向的是同一个对象,即比较 2 个对象的内存地址是否相等。
注意:如果子类重写了 equals() 方法,就需要重写 hashCode() 方法,比如 String 类就重写了 equals() 方法,同时也重写了 hashCode() 方法。
该方法返回值为布尔型,则如果两个对象相等返回 true,否则返回 false。
案例:
/**
* @Description: equals()案例$
* @Author: dyq
* @Date: 2021年2月4日$
*/
public class equalsTest {
public static void main(String[] args) {
// Object 类使用 equals() 方法
// 创建两个对象
Object obj1 = new Object();
Object obj2 = new Object();
// 判断 obj1 与 obj2 是否相等
// 不同对象,内存地址不同,不相等,返回 false
System.out.println(obj1.equals(obj2)); // false
// obj1 赋值给 obj3
// String 重写了 equals() 方法
// 对象引用,内存地址相同,相等,返回 true
Object obj3 = obj1;
System.out.println(obj1.equals(obj3)); // true
// String 类使用 equals() 方法
// 创建两个对象
String obj4 = new String();
String obj5 = new String();
// 判断 obj4 与 obj5 是否相等
// 初始化的两个对象都为 null,所以是相等,返回 true
System.out.println(obj4.equals(obj5)); // true
// 给对象赋值
obj4 = "哥哥";
obj5 = "哥";
// 判断 obj4 与 obj5 是否相等
// 两个值不同,内存地址也不同,所以不相等,返回 false
System.out.println(obj4.equals(obj5)); // false
}
}
结果:
false
true
true
false
3、当 GC (垃圾回收器)确定不存在对该对象的有更多引用时,由对象的垃圾回收器调用此finalize() 方法。
Object finalize() 方法用于实例被垃圾回收器回收的时触发的操作。
在GC准备释放对象所占用的内存空间之前,它将首先调用finalize()方法
finalize()方法中一般用于释放非Java 资源(如打开的文件资源、数据库连接等),或是调用非Java方法(native方法)时分配的内存。
4、获取对象的运行时对象的类 Class<?> getClass()
Object getClass() 方法用于获取对象的运行时对象的类。
示例:
/**
* @Description: $getClass
* @Author: dyq
* @Date: $
*/
public class getClassTest {
public static void main(String[] args) {
// getClass() with Object
Object obj1 = new Object();
System.out.println("obj1 的类为: " + obj1.getClass());
// getClass() with String
String obj2 = new String();
System.out.println("obj2 的类为: " + obj2.getClass());
// getClass() with ArrayList
ArrayList<Integer> obj3 = new ArrayList<>();
System.out.println("obj3 的类为: " + obj3.getClass());
// 创建 getClassTest 类的对象
getClassTest classTest = new getClassTest();
// getClassTest 继承 Object 类,Object 是所有类的超类
// 调用 getClass() 方法
System.out.println("classTest的类为:"+classTest.getClass());
}
}
结果:
obj1 的类为: class java.lang.Object
obj2 的类为: class java.lang.String
obj3 的类为: class java.util.ArrayList
classTest的类为:class com.Colltion.Test.getClassTest
5、获取对象的 hash 值 int hashCode()
返回对象是哈希值,是一个整数,表示在哈希表中的位置。
示例:
import java.util.ArrayList;
/**
* @Description: $hashCode()
* @Author: dyq
* @Date: $
*/
public class hashCodeTest {
public static void main(String[] args) {
// Object 使用 hashCode()
Object obj = new Object();
System.out.println(obj.hashCode());
//String 和 ArrayList 类都继承了 Object,所以可以直接使用 hashCode() 方法:
// String 使用 hashCode()
String str = new String();
System.out.println(str.hashCode()); // 0
// ArrayList 使用 hashCode()
ArrayList<Integer> list = new ArrayList<>();
System.out.println(list.hashCode()); // 1
//如果两个对象相等,则它们的哈希值也是相等的
// Object 使用 hashCode()
Object obj1 = new Object();
// obj1 赋值给 obj2
Object obj2 = obj1;
// 判断两个对象是否相等
System.out.println(obj1.equals(obj2)); // true
// 获取 obj1 与 obj2 的哈希值
System.out.println(obj1.hashCode()); // 1163157884
System.out.println(obj2.hashCode()); // 1163157884
}
}
结果:
460141958
0
1
true
1163157884
1163157884
6、唤醒在该对象上等待的某个线程void notify()
notify() 方法只能被作为此对象监视器的所有者的线程来调用。
一个线程要想成为对象监视器的所有者,可以使用以下 3 种方法:
- 执行对象的同步实例方法
- 使用 synchronized 内置锁
- 对于 Class 类型的对象,执行同步静态方法
一次只能有一个线程拥有对象的监视器。
如果当前线程不是此对象监视器的所有者的话会抛出 IllegalMonitorStateException 异常。