【JavaEE】详解Object类

Object类

官方定义:Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.

Object 类是类层次结构的根。每个类都有 Object 作为父类。所有对象(包括数组)都实现了此类的方法。

Java是一门面向对象语言,Object类作为所有对象的父类,有必要需要了解其基本功能,接下来我将结合源码对重要功能逐一分析。

public class Object {
    private static native void registerNatives();
    static {
        registerNatives();
    }
    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 native void wait(long timeout, int nanos) throws InterruptedException;
    public final void wait() throws InterruptedException {wait(0);}
    
    // other methods
}

registerNatives() 注册本地方法

打开源码,映入眼帘的是一个native方法以及静态代码块。

    private static native void registerNatives();
    static {
        registerNatives();
    }

这是 JNI(Java Native Interface) 中的常见操作,注册本地方法。下面简要说明一下这么做的必要。

本地方法是指JDK自带的方法,通常是由其他语言(C/C++)编写的方法。由Java程序调用,但是具体实现是在本地操作系统上完成。

JNI(是一种编程框架,它允许Java代码与用其他语言(如C、C++)编写的本地应用程序或库进行交互。通过JNI,Java程序可以调用本地代码中的函数,这对于执行需要高性能或特定于平台的操作非常有用。

通常,JNI需要 1.加载本地方法库; 2.注册本地方法。 两个步骤来实现,确保这些方法在后续调用中可以正确映射到本地实现(JVM层面)。,而一些核心类,比如Object、Thread、String,已经默认加载。所以此处直接声明native方法后,通过静态代码块调用注册本地方法。

而后续的hashCode()、wait()、notify()、notifyAll()等带有native的方法都是本地方法的调用。


getClass()

定义:返回此对象的运行时类。返回的 Class 对象是被所表示类的静态同步方法锁定的对象。

什么是该对象的运行时类呢?
当我们创建一个对象MyObject时,编译器( javac )为我们将 .java 文件编译为 .class 文件,而JVM通过 .class 文件生成了Class对象,使用这个 Class 对象的信息,JVM会分配内存并初始化所创建对象MyObject的实例。

这里,JVM运行时创建和使用的Class对象,就是我们说的运行时类,这个对象包含了该类的所有信息,例如类的名称、方法、字段等。

public class MyObject{
    public static void main(String[] args) {
        MyObject obj = new MyObject();
        Class<?> clazz = obj.getClass();
        System.out.println("Class Name: " + clazz.getName());
    }
}

hashCode()

定义:返回对象的哈希值。

什么是该对象的哈希值?
Object.hashCode()是很多类默认的返回哈希值的方法,该方法返回的是对象内存地址通过哈希函数转换后的整数值,这个默认实现对于不同的对象通常会返回不同的哈希值。
哈希函数有很多种,一般我们只需要知道有这么些函数,它的作用就是为了计算哈希值,哈希值相当于对象 一种映射,每个对象都有其哈希值,但不同对象的哈希值可能会相同,即哈希冲突。


equals()

    public boolean equals(Object obj) {
        return (this == obj);
    }

equals默认方法是直接采用的==作比较,那么两对象引用地址相同的话则返回true,或是两基本数据类型值相等的话,返回true,反之则false

通常,我们都会对其进行改写,比如String中,就是直接比较内部真实值而非引用地址:

    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;
    }

clone()

    protected native Object clone() throws CloneNotSupportedException;

定义:创建并返回当前对象基于Class类的复制。
理解:当前类 Object x = new Object();x.clone() != x && x.clone().getClass() == x.getClass(),结果为true

注意,若当前对象未实现Cloneable接口,则会抛出异常CloneNotSupportedException


toString()

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

定义:返回当前对象的字符串表达。

这里Object默认返回的是类名 + 哈希值的16进制整数
通常,我们会将其重写,返回我们想要展示的对象信息。举例说明,希望Student.toString()返回当前学生类的姓名、班级。

class Student{
	private String name;
	private String classroom;

	@Override
	public String toString() {
		return "姓名:" + this.name + ", 班级:" + this.classroom;
	}
}

线程相关方法

notify()notifyAll()wait()等线程控制方法,本质上都是通过JNI调用本地方法,本地方法调用操作系统的线程管理 API 来执行这些方法的具体操作,即依赖于底层操作系统的线程管理机制

唤醒、等待是线程控制的基本功能,也是后续各类线程同步的基本原理,在理解它们之前,必须先学习一个概念:监视器锁

监视器锁(也称为内部锁或对象锁)

概念:每个 Java 对象都有一个监视器锁,它是用来实现同步的基础设施。这个锁的状态和持有信息存储在对象的对象头(object header)中。对象头包含三种信息:锁标志位和指向持有锁的线程等指针信息、对象数据体对齐信息(8进制/16进制)。

  • synchronized
    • synchronized 关键字用于显式地获取和释放对象的监视器锁,从而实现线程同步。
    • 当一个线程进入一个同步代码块或同步方法时,它会尝试获取该对象的监视器锁。如果锁已经被其他线程持有,则当前线程会被阻塞,直到锁被释放。
  • 锁的加锁和解锁机制:
    • 使用 synchronized 来修饰方法或代码块时,会对指定的对象进行加锁和解锁操作。
    • 对于实例方法,隐式锁是当前实例对象 (this)。
    • 对于静态方法,隐式锁是当前类的 Class 对象。
    • 对于同步代码块,显式锁是 synchronized 关键字后面括号中的对象。

为什么这里先介绍以下锁的基本概念,因为wait()notify()方法必须在同步代码或同步方法中调用,它们的本质就是依赖监视器锁来实现的和synchronzied原理相同。因此,wait()notify()必须被调用的是同一个对象的监视器锁,否则会抛出IllegalMonitorStateException异常。

wait()
1. 线程调用对象的wait()方法。
2. 线程释放对象的监视器锁。
3. 线程进入等待队列中等待唤醒。
4. 其他线程调用对象的notify()方法。
5. 一个等待的线程被唤醒。
6. 唤醒的线程重新获取对象的监视器锁。
7. 线程从等待状态变为可运行状态。
8. 线程继续执行。

notify()
1. 线程调用对象的notify()方法。
2. 唤醒等待队列中的一个线程。
3. 被唤醒的线程重新获取对象的监视器锁。
4. 线程从等待状态变为可运行状态。
5. 线程继续执行。

细节内容会在Thread类的详解中说明,此处不过多赘述,明白Object类为每一个对象都提供了基本的线程唤醒、等待功能即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值