当前位置: 首页 > news >正文

JDK源码系列(一)Object

Object

概述

Object类是所有类的基类——java.lang.Object。

  • Object类是所有类的基类,当一个类没有直接继承某个类时,默认继承Object类
  • Object类属于java.lang包下,此包下的所有类在使用时无需手动导入,系统会在程序编译期间自动导入。

Object类有七个native方法:registerNatives()、getClass()、hashCode()、clone()、notify()、notifyAll()。

源码解析

/**
 * native 方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。
 */
public final native Class<?> getClass()
/**
 * native 方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap.
*/
public native int hashCode()
/**
* 用于比较两个对象的内存地址是否相等。
*/
public boolean equals(Object obj)
/**
* naitive 方法,用于创建并返回当前对象的一份拷贝。
*/
protected native Object clone() throws CloneNotSupportedException
/**
* 返回类的名字实例的哈希码的16进制的字符串。
*/
public String toString()
/**
* native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
*/
public final native void notify()
/**
 * native 方法,并且不能重写。跟 notify 一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
 */
public final native void notifyAll()
/**
* native方法,并且不能重写。暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁,timeout是等待时间。
*/
public final native void wait(long timeout) throws InterruptedException
/**
 * 多了 nanos 参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 毫秒。
 */
public final void wait(long timeout, int nanos) throws InterruptedException
/**
 * 跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
 */
public final void wait() throws InterruptedException
/**
 * 实例被垃圾回收器回收的时候触发的操作
 */
protected void finalize() throws Throwable

类构造器 

 一个类必须要有一个构造器的存在,如果没有显示声明,那么系统会默认创建一个无参构造器,在JDK的Object类源码中,是看不到构造器的,系统会自动添加一个无参构造器。

// 构造一个Object类的对象。
Object obj = new Object();

equals方法

 源码

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

结论:

  • 在 Object 类中,== 运算符和 equals 方法是等价的,都是比较两个对象的引用是否相等,从另一方面来讲,如果两个对象的引用相等,那么这两个对象一定是相等的
  • 对于我们自定义的一个对象,如果不重写 equals 方法,那么在比较对象的时候就是调用 Object 类的 equals 方法,也就是用 == 运算符比较两个对象

 重写equals原则

   @Override
    public boolean equals(Object otherObject) {
        //1、判断比较的两个对象引用是否相等,如果引用相等那么表示是同一个对象,那么当然相等
        if(this == otherObject){
            return true;
        }
        //2、如果 otherObject 为 null,直接返回false,表示不相等
        if(otherObject == null ){//对象为空或者不是Person类的实例
            return false;
        }
        //3、比较 this 和 otherObject 是否是同一个类(注意下面两个只能使用一种)
        //3.1:如果 equals 的语义在每个子类中所有改变,就使用 getClass 检测
        if(this.getClass() != otherObject.getClass()){
            return false;
        }
        //3.2:如果所有的子类都有统一的定义,那么使用 instanceof 检测
        if(!(otherObject instanceof Person)){
            return false;
        }
 
        //4、将 otherObject 转换成对应的类类型变量
        Person other = (Person) otherObject;
 
        //5、最后对对象的属性进行比较。使用 == 比较基本类型,使用 equals 比较对象。如果都相等则返回true,否则返回false
        //   使用 Objects 工具类的 equals 方法防止比较的两个对象有一个为 null而报错,因为 null.equals() 是会抛异常的
        return Objects.equals(this.pname,other.pname) && this.page == other.page;
 
        //6、注意如果是在子类中定义equals,则要包含 super.equals(other)
        //return super.equals(other) && Objects.equals(this.pname,other.pname) && this.page == other.page;
 
    }

如果在重写 equals() 方法时没有重写 hashCode() 方法,使用 HashMap 可能会出现以下问题:

  1. 违反 hashCode 契约

    Java 规定,如果两个对象通过 equals() 方法比较相等,那么它们的 hashCode() 也必须相等。如果只重写 equals() 而不重写 hashCode(),可能会导致两个相等的对象返回不同的哈希值,从而违反这一契约。
  2. HashMap 无法正确查找对象

    HashMap 依赖 hashCode() 来确定对象的存储位置。如果两个对象相等但 hashCode() 不同,HashMap 可能会将它们放在不同的桶中,导致无法通过 get() 方法正确找到对象。
  3. 数据丢失或重复

    由于 HashMap 使用 hashCode() 和 equals() 来管理键值对,如果 hashCode() 不一致,可能会导致数据被错误地存储或覆盖,进而引发数据丢失或重复。

getClass方法

public final native Class<?> getClass();

getClass()在 Object 类中如上,作用是返回对象的运行时类。

toString 方法

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
  • getClass().getName()是返回对象的全类名(包含包名),Integer.toHexString(hashCode()) 是以16进制无符号整数形式返回此哈希码的字符串表示形式。
  • 打印某个对象时,默认是调用 toString 方法,比如 System.out.println(person),等价于 System.out.println(person.toString())。

clone方法

/**
* 本地clone方法,用于对象的复制
*/
protected native Object clone() throws CloneNotSupportedException;

保护方法,实现对象的浅拷贝,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。

finalize 方法

protected void finalize() throws Throwable { }

当 GC 确定不再有对该对象的引用时,GC 会调用对象的 finalize() 方法来清除回收。

JVM 会确保一个对象的 finalize() 方法只被调用一次,而且程序中不能直接调用 finalize() 方法。

finalize() 方法通常也不可预测,而且很危险,一般情况下,不必要覆盖 finalize() 方法。

 

 

 

 

相关文章:

  • Kubernetes控制平面组件:APIServer 基于 引导Token 的认证机制
  • C#上位机--选择语句(switch)
  • Typora软件(Markdown编辑器)详细安装教程(附补丁包)2025最详细图文教程安装手册
  • 打开Firefox自动打开hao360.hjttif.com标签解决方案
  • Resource not found: roslaunchROS path [0]=/opt/ros/noetic/share/ros
  • DeepSeek模型量化
  • 第一个CMAKE项目hello cmake
  • C++ 设计模式-解释器模式
  • Vue2 和 Vue3 的区别
  • 高级推理的多样化推理与验证
  • 前端(AJAX)学习笔记(CLASS 3):AJAX原理
  • 2025年度福建省职业院校技能大赛中职组“网络建设与运维”赛项规程模块三
  • 从Revit建模软件的“编辑”操作分析:构件与编辑 = 数据结构与算法
  • 【排版教程】如何在Word/WPS中优雅的插入参考文献
  • 鸿蒙-做一个简版的富文本解析控件
  • Docker+Kubernetes_第一章_Docker入门
  • Spring Boot文件上传
  • 设备树及gpio子系统及ioctl控制及字符设备驱动及内核模块编程事项仨LED灯说点就点说灭就灭
  • 计算机原理第三章——存储器(未完善
  • 计算机网络面试知识点总结
  • 多家国有大行存款利率即将迎来新一轮下调
  • 外汇局:4月下旬外资投资境内股票转为净买入
  • 王毅同丹麦外交大臣拉斯穆森会谈
  • 美国失去最后一个AAA评级,资产价格怎么走?美股或将触及天花板
  • 联合国报告:全球经济前景恶化,面临高度不确定性
  • 习近平复信中国丹麦商会负责人