作为一名java开发,肯定会知道object类,object类是所有类的基类,当一个类没有直接继承任何类时,默认继承object类,所以也被称之为“上帝类”。

目录

一、继承Object的时机

二、类中方法解析

1.类构造器

2.equals方法

3.hashcode方法

4.clone方法

5.getClass方法

6.toString方法

7.finalize方法

8.registerNatives方法


一、继承Object的时机

由此,我们抛出一个问题,object类时什么时候成为一个类的父类的?是编译时还是虚拟机处理的时候。

这里我们通过JDK自带的反编译工具javap来看一下就明白了

可以看到在编译时期就已经继承了object类

二、类中方法解析

这是object类中方法,其中共有7个native方法,也就是说这七个方法并不是java本身去完成的,而是通过c/c++来完成,放在.dll动态文件中

关于如何通过java语言调用c/c++的代码,则是有标准的JNI协议来定义的,感兴趣可以自行去了解一下

1.类构造器

每个类都会有类构造器,如果没有声明,则会默认创建一个无参构造

2.equals方法

这个方法相信大家再熟悉不过了,面试中也是一个高频问点,比如经典的:

  • “equals()和==有什么区别”
  • “有没有重写过equals”
  • “什么情况下需要重写equals()以及hashcode()”

在Object中的equals()其实跟==是一样的,都是比较两个对象的引用是否相等,也就是说,如果两个对象的引用相等,那么它俩的对象一定是相等的

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

那肯定就有人有疑惑了,那为啥String当中的equals()也会去比较值是否相等呢,那正是因为String对equals()进行了重写。先是比较了引用,然后再遍历比较值是否相等(下图为jdk11的代码,如果是jdk8则不会将这个方法拆开分情况处理)

 public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String aString = (String)anObject;if (coder() == aString.coder()) {return isLatin1() ? StringLatin1.equals(value, aString.value): StringUTF16.equals(value, aString.value);}}return false;}@HotSpotIntrinsicCandidatepublic static boolean equals(byte[] value, byte[] other) {if (value.length == other.length) {for (int i = 0; i < value.length; i++) {if (value[i] != other[i]) {return false;}}return true;}return false;}

所以,当我们自定义一个类时,如果这个类不重写equals方法,那么只会比较引用,并不会去比较值,值得注意的是,重写equals方法通常都必须重写hashcode方法,以维护hashcode方法的一般约定,该方法声明相等对象必须具有相同的哈希代码

3.hashcode方法

该方法在object中为native方法,作用就是返回对象的散列码,是int类型的数值

HashCode的存在主要是为了查找的快捷性,用来在散列存储结构中确定对象的存储地址,比如说,我们判断一个元素是否相等可以通过equals方法,但是如果集合中有10000个元素,当我们添加一个新元素时,就要调用10000次equals来比较,显然效率很低。

于是java的集合设计者就采用了哈希表来实现,就是将数据依照特定的算法产生的结果指定到一个地址上,这样当集合需要添加新元素的时候,调用其hashcode,就能计算出应该将其存放到什么位置上。

那么由此产生了几种情况:

  1. 该位置没有元素,则直接存放
  2. 该位置有元素,调用equals进行比较,如果相同则无需再存储
  3. 如果不相同,也就是意味着发生了哈希冲突,那这个时候则会在该位置产生一个链表,将产生相同的hashcode存放到这个链表中(如果看过HashMap源码的话就知道了)

那么hashcode到底是啥,是否为对象的内存地址?

要清楚这一点我们需要知道,内存地址是不可能重复的,所以只要产生hashcode重复的情况就能证明hashcode不为内存地址

public class HashCode_Test {public static void main(String[] args) {int num =0;List<Integer> list = new ArrayList<>();for (int i = 0; i < 200000; i++) {Object o = new Object();if(list.contains(o.hashCode())){num++;}else{list.add(o.hashCode());}}System.out.println("重复hashcode个数为:"+num);System.out.println("不重复hashcode个数为:"+list.size());}
}
重复hashcode个数为:8
不重复hashcode个数为:199992

可以看到在循环20万次时,会出现重复的情况,所以先是佐证了hashcode并不是内存地址

那么hashcode的存储位置又在哪里呢?

这个时候我们需要先了解一下啊对象的内存布局

hashcode存放在java的对象头当中,对象头分为两个部分,一个是MarkWord(标记字段),另一个是Class Pointer(类型指针)。其中Class Pointer是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例,Mark Word用于存储对象自身的运行时数据,它是实现轻量级锁和偏向锁的关键。、

下图为MarkWord的机构

当一个对象处于无锁状态时,会用31个bit来存储hashcode;当该对象有锁无论是轻量级锁、重量级锁都没有存放hashcode的空间,因为被指针占据了

如果在偏向锁的过程中,调用了hashcode方法,则会先撤销偏向锁,因为存储hashcode的bit被线程id占据了,所以得先撤销再去生成hashcode

如果有线程硬性调用对象的锁,则对象再也回不到偏向锁状态,而是升级为重量级锁,hashcode跟随mark word被移动到c的object monitor中

4.clone方法

该方法时实现对象的浅拷贝,也就是说只是将指针指向了该对象,而深拷贝则是重新创建了一个一样的对象

值得注意的是,被拷贝的对象需要实现Cloneable接口才行

5.getClass方法

作用是返回对象的运行时类

6.toString方法

作用是返回对象的全类名+十六进制的hashcode,我们打印某个类时,就是默认打印的该类的toString方法

7.finalize方法

当GC确定不再有对该对象的引用时,GC会调用对象的finalize方法来进行回收,jvm会确保一个对象的finalize方法只会被调用一次,并且程序中不能直接调用它

8.registerNatives方法

一个类如果要调用操作系统的实现,则必须要装载本地库,由于Object中用了static代码块调用该方法,所以在类加载时必定会执行该方法


以上就是Object的源码解析,重点还是在hashcode以及equals那部分

JDK源码解析--Object类相关推荐

  1. JDK源码解析 InputStream类就使用了模板方法模式

    JDK源码解析 InputStream类就使用了模板方法模式. 在InputStream类中定义了多个 read() 方法,如下: public abstract class InputStream ...

  2. JDK源码解析 Integer类使用了享元模式

    JDK源码解析 Integer类使用了享元模式. 我们先看下面的例子: public class Demo {public static void main(String[] args) {Integ ...

  3. JDK源码解析——Object的hashCode方法

    目录 前言 说明 一.源码目录结构 (1).JDK目录 (2).hotspot目录 二.基础知识 (1).Object Header(对象头) (2).Lock(锁) 1. 无锁 => 偏向锁 ...

  4. JDK源码解析-Runtime类

    Runtime类就是使用的单例设计模式 通过源代码查看使用的是哪儿种单例模式 public class Runtime {private static Runtime currentRuntime = ...

  5. JDK源码解析 迭代器模式在JAVA的很多集合类中被广泛应用,接下来看看JAVA源码中是如何使用迭代器模式的。

    JDK源码解析 迭代器模式在JAVA的很多集合类中被广泛应用,接下来看看JAVA源码中是如何使用迭代器模式的. 看完这段代码是不是很熟悉,与我们上面代码基本类似.单列集合都使用到了迭代器,我们以Arr ...

  6. JDK源码解析 Comparator 中的策略模式

    JDK源码解析 Comparator 中的策略模式.在Arrays类中有一个 sort() 方法,如下: public class Arrays{public static <T> voi ...

  7. JDK源码解析 Runable是一个典型命令模式,Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法

    JDK源码解析 Runnable是一个典型命令模式, Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法 /命令接口(抽象命令角色) public interfa ...

  8. JDK源码解析 —— IO流中的包装类使用到了装饰者模式

    JDK源码解析 IO流中的包装类使用到了装饰者模式. BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter ...

  9. JDK源码解析之Java.util.Collections

    java.util.Collections 是一个包装类.它包含有各种有关集合操作的静态多态方法.此类不能实例化,就像一个工具类,服务于Java的Collection框架. 一.源码解析 1.不可实例 ...

最新文章

  1. MySQL 配置文档
  2. DRBD+HeartBeat+NFS 架构
  3. 三星电子推出X-net架构用于语音通话
  4. 【笔试面试】C#中的程序集
  5. group by 查询分组后 各组的内部条数与组的条数
  6. 煤矿行业设备管理系统
  7. 联想,华为,惠普的服务器和存储的管理口默认地址与默认用户名密码!
  8. 信息系统集成监理费收取标准_信息系统工程监理资费标准.doc
  9. 什么思维是计算机科学的基础概念,计算思维的定义和特征是什么
  10. linux命令之文件和目录操作
  11. 多元相关分析与回归分析(转)
  12. 教程详解|3D环物的360物体如何在后台上传?
  13. IOS Websocket (一) Starscream实现Websocket通讯
  14. 三维重建 - Clion打包C++代码(包含qt库,opencv以及dcmtk)
  15. android开发之UI
  16. 钢笔工具使用目前的最高水平
  17. 设置Jenkins语言为中文或英文
  18. 屏幕尺寸、分辨率、视口笔记
  19. PB 水凝胶基普鲁士蓝纳米复合物|碳纳米管-离子液体/聚苯胺-普鲁士蓝-普鲁士蓝氧化酶复合物|碳纳米管/普鲁士蓝(MWCNTs/PB)纳米复合物
  20. ubuntu更改更新源

热门文章

  1. python代码大全-python贪吃蛇游戏代码
  2. python语言-python语言基本语句用法总结
  3. 专科python应届生工资多少-应届生自学Python两个月,为什么找不到工作?
  4. 科大讯飞免切换语音输入,留住更美乡音!
  5. 两位一体数码管引脚图_LED数码管你知道多少?
  6. Node-Promise
  7. java点击上传上传mysql并显示图片_java + mysql + jdbc实现图片上传
  8. 【王道计组笔记】主存与CPU的连接
  9. 一种H.264高清视频的无参考视频质量评价算法(基于QP和跳过宏块数)
  10. CImage 对话框初始化时候显示透明 PNG