第三篇:java.lang.Object 类源码分析

Object所包含的方法如下:

① public Object();

构造函数: 大部分情况下,类对象的声明,都是通过构造函数完成的(Java中规定:在类定义过程中,对于未定义构造函数的类,默认会有一个无参数的构造函数), 并不是所有类构造方法都是public。

② private static native void registerNatives();

作用:RegisterNatives方法是JNI环境提供的,用于注册Java需要调用的Native方法 。

以下为RegisterNatives对应C语言的源码:

① JNINativeMethod包含三个元素: 方法名, 方法签名, native函数指针。

② sizeof:c语言中用来求字节运算符,用来求一个对象(类型,变量,……)所占的内存大小(以字节为单位)。

③ native:修饰的方法并非Java完成,通过C/C++去完成,并编译成.dll文件,由Java进行调用。native修饰,则表示操作系统需提供此方法的实现,并交给Java使用。

④ registerNatives:此方法主要作用是将C/C++中的方法映射到Java中的native方法,实现方法命名的解耦。

 

③ protected native Object clone() throws CloneNotSupportedException;

① 主要作用:克隆,方法返回引用,指向clone出来的对象,此对象与原对象分别占用不同的堆空间。

② 子类必须实现Cloneable 接口,否则重写clone方法的子类同样会抛出CloneNotSupportedException异常,以指示无法复制某个实例。

③ 软件设计模式中原型模式原理就是克隆,具体类实现接口中的clone()方法,并由调用者调用具体类的clone()方法进行克隆,为原型模式。

原型模式具备三项:实现了Cloneable的接口、父类、或者具体类本身,具体类实现接口或父类中的clone()方法,调用类调用具体类的clone()方法进行克隆。

原型模式的应用场景:① 当对象之间相同或者相似。② 当对象中含有大量属性,并且其中大部分属性相似,只有某几个属性有区别时。

 

④ public final native Class<?> getClass();

① 同样为native方法,返回的是此Object对象的类对象/运行时类对象Class<?>,效果与Object.class相同。

② 原理:用到了java的反射机制。(后续博客详细讲解)

 

⑤ public boolean equals(Object obj);

==和equals的区别(主要指String类型对象,其他对象描述不准)

① == 表示的是变量值完全相同(对于基本类型,存储的是值,对于引用类型,存储的是指向堆的地址)。

② equals 表示的是对象的内容完全相同,此处的内容多指对象的特征/属性。

以下为Object类的equals实现方法

 

① Object类中的equals方法内部使用的标尺是==,但是对于不同的引用类型,可能判断的标尺并非是==,那么则需要重写equals方法来改变衡量相同的标尺,否则会继承父类的equals,如果父类也未重写此方法,逐级查找,直至Object基类。

 

⑥ public native int hashCode();

 hashCode()会返回一个int的整数值。

② 如果两个对象相等(依据:调用equals()方法),那么这两个对象调用hashCode()返回的哈希码也必须相等。

③ 由②可推理出:两个对象相等,则equals相等,则hashCode相等。反之,当hashcode不相等,则equals不相等,对象也不相等。

④ 由②和③可推理出:如果重写了equals()方法,则必须重写hashCode()方法,要保持逻辑的一致性。

⑤ hash取模:求哈希简单的做法是先求取出键值的hashcode,然后在将hashcode得到的int值对数组长度进行(%)取模,为了考虑性能,Java总采用按位与操作实现取模操作。

 

JNI学习笔记(可参考以下博客内容):

https://www.jianshu.com/p/216a41352fd8

C语言和Java的互调原理(可参考以下博客内容):

https://blog.csdn.net/Wedfrend/article/details/78833877

native关键字(可参考以下博客内容):

https://www.jb51.net/article/79348.htm

Object总结篇(可参考以下博客内容):

https://www.cnblogs.com/lwbqqyumidi/p/3693015.html

HashCode的作用(可参考以下博客内容):

https://www.cnblogs.com/xrq730/p/4842028.html

Hash散列图:

 

hashCode含义:是散列的意思(就是把任意长度的输入,通过散列算法变换成固定长度的输出,该输出就是散列值)。

hashCode作用:hashCode主要作用是提高查找的效率(通过取模判定存取位置)

HashCode关键点:

HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址。

② 如果两个对象equals相等,那么这两个对象的HashCode一定也相同。

③ 如果对象的equals方法被重写,那么对象的HashCode方法也尽量重写

④ 如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置

针对散列值的关键结论:

① 如果散列表中存在和散列原始输入K相等的记录,那么K必定在f(K)的存储位置上

② 不同关键字经过散列算法变换后可能得到同一个散列地址,这种现象称为碰撞

③ 如果两个Hash值不同(前提是同一Hash算法),那么这两个Hash值对应的原始输入必定不同

 

hash取模(实例):

https://www.jianshu.com/p/e910ff6a5579

① 取模含义(hashCode值%数组长度)

② 计算一个数与2的N次幂取模:X % 2^n = X & (2^n - 1) ,参考知识点,为二进制的移码和按位与操作。

示例:可参考Integer类中的formatUnsignedInt()方法,就是通过按位与(&)代替取余(%),digits[val & mask] = digits[val % radix]。

③ 位运算(&)效率要比代替取模运算(%)高很多,主要原因是位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。 

 

java类加载机制和反射机制(可参考以下博客内容)

https://www.cnblogs.com/echola/p/9491950.html

① 加载机制:把java文件编译为Class文件

② 反射机制:通过class文件获取类方法和属性

类加载的过程:加载--> 链接 (检验 --> 准备 --> 解析) -->初始化

准备与初始化的区别:

例如 private static int a = 10; 

准备阶段:给a分配内存,因为a是int类型,所以赋初始值为0。

初始化阶段:a会被赋值为10。

Class.forName和反射机制的区别:

Class.forName()方法底层同样是调用类加载,唯一的区别是调用loadClass(String name, boolean resolve(是否解析))方法时传递的第二个布尔参数的值。

Class.forName()第二个参数为true,类加载第二个参数为false,为true时会调用链接,执行静态代码块,false则不会。

所以Class.forName()方法是加载并解析,类加载器是只加载不解析,当调用newInstance()是才进行解析并执行静态代码块。

new与newInstance的区别:

newInstance只能调用无参构造函数。

new则可以调用任意参数的构造函数。

 

ClassLoader的分析和使用(可参考以下博客内容):

https://melonwxd.github.io/2017/10/17/classloader1/

深入理解Java类加载器(1):Java类加载原理解析:

https://blog.csdn.net/zhoudaxia/article/details/35824249

ClassLoader详解:

https://blog.csdn.net/m0_38075425/article/details/81627349

 

Java自带三大类加载器:

① BootstrapClassLoader  加载Jar包路径:System.getProperty("sun.boot.class.path") 

② ExtClassLoader  加载Jar包路径:System.getProperty("java.ext.dirs") 

③ AppClassLoader  加载Jar包路径:System.getProperty("java.class.path") 

④ OS操作系统位数:System.getProperty("os.arch");

⑤ java系统库路径:System.getProperty("java.library.path")

⑥ AppClassLoader → ExtClassLoader → BootstrapClassLoader (继承关系,从左向右)

ClassLoader继承关系图:

 

ClassLoader加载机制:

① 全盘负责:除非显式用其他的ClassLoader加载,否则此ClassLoader负责此类及此类所依赖引用的类的载入。

② 双亲委派:Java推荐的加载机制,并不强制;继承java.lang.ClassLoader实现自定义ClassLoader类加载器,如需保持双亲委派原则,重写findClass(name)方法即可,不需保持,则重写loadClass(name)方法即可。

③ 缓存机制:缓存机制会保证所有加载过的Class都会被缓存起来,当程序需要使用某个Class时,类加载器先从缓存区中搜索,缓存区不存在该Class对象时,系统会读取该类的二进制数据,来生成Class对象并放入缓存区。

注意:修改Class后,必须重启JVM,程序做的修改才可以生效,原因就是缓存机制。

双亲委派原理:

① 判断源ClassLoader是否加载此Class,是则返回class,否则由子到父,逐级递归操作,直至BootstrapClassLoader;

② BootstrapClassLoader如未加载过此Class,则需寻找Class字节码文件并载入,成功返回class,失败由父到子,逐级递归操作,直至源ClassLoader,如ClassLoader加载失败,则抛出ClassNotFindException异常。

 

ClassLoader相关面试题(可参考以下博客内容):

https://melonwxd.github.io/2017/10/17/classloader2/

① 自己声明的类的包路径,不可以用java开头,原因是在ClassLoader类的preDefineClass方法内部做了限制,并且外层调用此方法的defineClass方法声明为final(不可被重写)。

posted @ 2019-08-28 16:42  bobwuming  阅读(329)  评论(0)    收藏  举报