本文出自:http://blog.csdn.net/dt235201314/article/details/78318399

一丶概述

JAVA中所有的类都继承自Object类,就从Object作为源码解析的开始。

二丶常见方法

注: 以上绿色方法为 非native方法  粉色方法为 native方法)

什么是native方法?

native关键字标识的java方法为本地方法,底层是有c/c++编写的程序编译后dll文件,java加载dll文件后,可用通过本地方法调用dll中函数,如有疑问可用参考JNI使用方式。

什么是JNI方法?

向东是底层,向西是应用,咱们先一路向西。向东参考:JNI方法使用

1.Object():默认构造函数(源码无系统默认提供)

2.void registerNatives()

  1. /* 一个本地方法,具体是用C(C++)在DLL中实现的,然后通过JNI调用。*/
  2. private static native void registerNatives();
  3. /* 对象初始化时自动调用此方法*/
  4. static {
  5. registerNatives();
  6. }

3.final getClass()

  1. /* 返回此 Object 的运行时类。*/
  2. public final native Class<?> getClass();

例:

  1. public class tests
  2. {
  3. public static void main(String[] args)
  4. {
  5. A te = new B();
  6. System.out.println(te.getClass());
  7. }
  8. }
  9. class A{
  10. }
  11. class B extends A
  12. {
  13. }

运行结果:class B

A类的引用,但是运行时te这个对象的实际类是B。

4.int hashCode()方法

  1. /*
  2. hashCode 的常规协定是:
  3. 1.在应用程序执行期间,如果一个对象用于equals()方法的属性没有被修改的话,
  4. 那么要保证对该对象多次返回的hashcode值要相等。
  5. 2.如果2个对象通过equals()方法判断的结果为true,那么要保证二者的hashcode值相等。
  6. 3.如果2个对象通过equals()方法判断的结果为false,那么对二者hashcode值是否相等并没有明确要求。
  7. 如果不相等,那么能够提升散列表的性能。
  8. */
  9. public native int hashCode();

实际计算方法:

  1. public int hashCode() {
  2. int h = hash;
  3. if (h == 0 && value.length > 0) {
  4. char val[] = value;
  5. for (int i = 0; i < value.length; i++) {
  6. h = 31 * h + val[i];
  7. }
  8. hash = h;
  9. }
  10. return h;
  11. }

5.boolean equals(Object obj)

  1. public boolean equals(Object obj) {
  2. return (this == obj);
  3. }

从这里我们可以看到,equals(obj)方法最根本的实现就是‘==’,因此对于一些自定义类,如果没有重写hashcode()方法和equals()方法的话,利用‘==’和equals()方法比较的结果是一样的。对于‘==’比较的是地址,equals()方法比较的是内容这种说法,是片面的。(虽然在最常用的String类中是这样的)。

equal方法常被重写

例:String(先比较String对象内存地址相同,若相同则返回true,否则判断String对象对应字符的内容是否相等,若相等则返回true)

  1. public boolean equals(Object anObject) {
  2. if (this == anObject) {
  3. return true;
  4. }
  5. if (anObject instanceof String) {
  6. String anotherString = (String)anObject;
  7. int n = value.length;
  8. if (n == anotherString.value.length) {
  9. char v1[] = value;
  10. char v2[] = anotherString.value;
  11. int i = 0;
  12. while (n-- != 0) {
  13. if (v1[i] != v2[i])
  14. return false;
  15. i++;
  16. }
  17. return true;
  18. }
  19. }
  20. return false;
  21. }

6.clone()

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

一起看下native方法 位于openjdk\hotspot\src\share\vm\prims\jvm.cpp中 JVM_Clone的实现  片段

  1. JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
  2. JVMWrapper("JVM_Clone");
  3. Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  4. const KlassHandle klass (THREAD, obj->klass());
  5. JvmtiVMObjectAllocEventCollector oam;
  6. #ifdef ASSERT
  7. // Just checking that the cloneable flag is set correct
  8. if (obj->is_javaArray()) {
  9. guarantee(klass->is_cloneable(), "all arrays are cloneable");
  10. } else {
  11. guarantee(obj->is_instance(), "should be instanceOop");
  12. bool cloneable = klass->is_subtype_of(SystemDictionary::Cloneable_klass());
  13. guarantee(cloneable == klass->is_cloneable(), "incorrect cloneable flag");
  14. }
  15. #endif
  16. // Check if class of obj supports the Cloneable interface.
  17. // All arrays are considered to be cloneable (See JLS 20.1.5)
  18. if (!klass->is_cloneable()) {
  19. ResourceMark rm(THREAD);
  20. THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name());
  21. }
  22. // Make shallow object copy
  23. const int size = obj->size();
  24. oop new_obj = NULL;
  25. if (obj->is_javaArray()) {
  26. const int length = ((arrayOop)obj())->length();
  27. new_obj = CollectedHeap::array_allocate(klass, size, length, CHECK_NULL);
  28. } else {
  29. new_obj = CollectedHeap::obj_allocate(klass, size, CHECK_NULL);
  30. }
  31. // 4839641 (4840070): We must do an oop-atomic copy, because if another thread
  32. // is modifying a reference field in the clonee, a non-oop-atomic copy might
  33. // be suspended in the middle of copying the pointer and end up with parts
  34. // of two different pointers in the field.  Subsequent dereferences will crash.
  35. // 4846409: an oop-copy of objects with long or double fields or arrays of same
  36. // won't copy the longs/doubles atomically in 32-bit vm's, so we copy jlongs instead
  37. // of oops.  We know objects are aligned on a minimum of an jlong boundary.
  38. // The same is true of StubRoutines::object_copy and the various oop_copy
  39. // variants, and of the code generated by the inline_native_clone intrinsic.
  40. assert(MinObjAlignmentInBytes >= BytesPerLong, "objects misaligned");
  41. Copy::conjoint_jlongs_atomic((jlong*)obj(), (jlong*)new_obj,
  42. (size_t)align_object_size(size) / HeapWordsPerLong);
  43. // Clear the header
  44. new_obj->init_mark();
  45. // Store check (mark entire object and let gc sort it out)
  46. BarrierSet* bs = Universe::heap()->barrier_set();
  47. assert(bs->has_write_region_opt(), "Barrier set does not have write_region");
  48. bs->write_region(MemRegion((HeapWord*)new_obj, size));
  49. // Caution: this involves a java upcall, so the clone should be
  50. // "gc-robust" by this stage.
  51. if (klass->has_finalizer()) {
  52. assert(obj->is_instance(), "should be instanceOop");
  53. new_obj = instanceKlass::register_finalizer(instanceOop(new_obj), CHECK_NULL);
  54. }
  55. return JNIHandles::make_local(env, oop(new_obj));
  56. JVM_END

看不懂,这里参考大神讲解

隐含意思:数组类型默认可以直接克隆,而其他对象实现clone需要先实现Cloneable接口,否则抛出CloneNotSupportedException异常
问题1:对象的创建有多中方式,类似 new 、getInstance、clone等 clone有什么好处?
问题2:对象调用clone方法生成的对象 和 原对象是否还有什么关联关系?
问题3 : 对象clone存在 “浅复制”、“深复制”概念,怎么区分?
带着这3个问题,理解Object clone方法:
1、一般native方法比java中非native方法执行效率高 ,看示例

  1. public class ObjectCloneTest1 {
  2. static final int N = 100000;
  3. public static void main(String[] args) {
  4. final Date date = new Date();
  5. {
  6. final long startTime = System.currentTimeMillis();
  7. for (int i = 0; i < N; i++) {
  8. Date date2 = (Date) date.clone();
  9. }
  10. final long endTime = System.currentTimeMillis();
  11. System.out.println("clone:" + (endTime - startTime) + "ms");
  12. }
  13. {
  14. final long startTime = System.currentTimeMillis();
  15. for (int i = 0; i < N; i++) {
  16. final Calendar cal = Calendar.getInstance();
  17. cal.setTime(date);
  18. final Date date2 = cal.getTime();
  19. }
  20. final long endTime = System.currentTimeMillis();
  21. System.out.println("Calender.setTime:" + (endTime - startTime) + "ms");
  22. }
  23. }
  24. }

2、clone生成的新对象与原对象的关系,需要区别2个对象建是否存在相同的引用或对应的内存地址是否存在共用情况,若存在则 该次clone为 “浅复制”,否则为“深复制”, 而且Object的clone方法是属于 “浅复制”,看示例

  1. public class ObjectCloneTest2 {
  2. public static void main(String[] args) {
  3. Animal a1 = new Animal(1, "pig");
  4. Animal a2 = (Animal) a1.clone();
  5. System.out.println(a1.getName() == a2.getName() ? "浅复制" : "深复制");
  6. System.out.println(a1);
  7. a1.setAge(11);
  8. a1.setName("big pig");
  9. System.out.println(a1.age + ":" + a1.name);
  10. System.out.println(a2);
  11. System.out.println(a2.age + ":" + a2.name);
  12. }
  13. }
  14. class Animal implements Cloneable{
  15. int age;
  16. String name;
  17. Animal(int age, String name) {
  18. this.age = age;
  19. this.name = name;
  20. }
  21. public Animal clone() {
  22. Animal o = null;
  23. try {
  24. o = (Animal) super.clone();
  25. } catch (CloneNotSupportedException e) {
  26. e.printStackTrace();
  27. }
  28. return o;
  29. }
  30. public int getAge() {
  31. return age;
  32. }
  33. public void setAge(int age) {
  34. this.age = age;
  35. }
  36. public String getName() {
  37. return name;
  38. }
  39. public void setName(String name) {
  40. this.name = name;
  41. }
  42. }

"深复制"时,需要将共同关联的引用也复制完全看示例

  1. public class ObjectCloneTest3 {
  2. public static void main(String[] args) {
  3. Person p1 = new Person(10, "ll", new Race("yellow", "Asia"));
  4. Person p2 = (Person) p1.clone();
  5. System.out.println(p1.getRace() == p2.getRace());
  6. System.out.println(p1.getTestArray() == p2.getTestArray());
  7. }
  8. }
  9. class Person implements Cloneable {
  10. int age;
  11. String name;
  12. Race race;
  13. int[] testArray = { 1, 23, 5, 6, 0 };
  14. Person(int age, String name, Race race) {
  15. this.age = age;
  16. this.name = name;
  17. this.race = race;
  18. }
  19. public Person clone() {
  20. Person o = null;
  21. try {
  22. o = (Person) super.clone();
  23. o.setRace(this.race.clone());
  24. o.setTestArray(testArray.clone());
  25. } catch (CloneNotSupportedException e) {
  26. e.printStackTrace();
  27. }
  28. return o;
  29. }
  30. public int getAge() {
  31. return age;
  32. }
  33. public void setAge(int age) {
  34. this.age = age;
  35. }
  36. public String getName() {
  37. return name;
  38. }
  39. public void setName(String name) {
  40. this.name = name;
  41. }
  42. public Race getRace() {
  43. return race;
  44. }
  45. public void setRace(Race race) {
  46. this.race = race;
  47. }
  48. public void setTestArray(int[] testArray) {
  49. this.testArray = testArray;
  50. }
  51. public int[] getTestArray() {
  52. return testArray;
  53. }
  54. }
  55. class Race implements Cloneable {
  56. String color; // 颜色
  57. String distribution; // 分布
  58. public Race(String color, String distribution) {
  59. super();
  60. this.color = color;
  61. this.distribution = distribution;
  62. }
  63. public Race clone() throws CloneNotSupportedException {
  64. return (Race) super.clone();
  65. }
  66. }

false

false

7.toString()

  1. /*返回该对象的字符串表示。非常重要的方法*/
  2. public String toString() {
  3. return getClass().getName() + "@" + Integer.toHexString(hashCode());
  4. }

默认返回对象的名称及引用地址,但一般被子类重写用于说明子类相关属性值描述

8.final notify()

  1. /*不能被重写,唤醒在此对象监视器上等待的单个线程。*/
  2. public final native void notify();

9.final notifyAll()

  1. /*唤醒在此对象监视器上等待的所有线程。*/
  2. public final native void notifyAll();

10.final  void wait()方法

  1. /*在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。
  2. 当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。*/
  3. public final void wait() throws InterruptedException {
  4. wait(0);
  5. }

11.final native void wait(long timeout)

  1. /*在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。*/
  2. public final native void wait(long timeout) throws InterruptedException;

该方法使当前线程等待,直到另外一个线程调用该对象的notify或notifyAll方法,或者等待时间已到,当前线程才会从等待池移到运行池。 
如果在wait之前或者wait的时候,当前线程被中断了,那么直到该线程被恢复的时候才会抛出中断异常(InterruptedException)

12.final void wait(long timeout,int nanos)

  1. /* 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。*/
  2. public final void wait(long timeout, int nanos) throws InterruptedException {
  3. if (timeout < 0) {
  4. throw new IllegalArgumentException("timeout value is negative");
  5. }
  6. if (nanos < 0 || nanos > 999999) {
  7. throw new IllegalArgumentException(
  8. "nanosecond timeout value out of range");
  9. }
  10. if (nanos > 0) {
  11. timeout++;
  12. }
  13. wait(timeout);
  14. }

 

13.protected void finalize()

  1. /*当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。*/
  2. protected void finalize() throws Throwable { }

垃圾回收器在认为该对象是垃圾对象的时候会调用该方法。子类可以通过重写该方法来达到资源释放的目的。 
在方法调用过程中出现的异常会被忽略且方法调用会被终止。 
任何对象的该方法只会被调用一次。

三丶参看文章
Object类源码解析
【java基础之jdk源码】Object

四丶相关面试题

【码农每日一题】Java equals 与 hashCode 相关面试题

Java源码之Object的更多相关文章

  1. java源码阅读Object

    1 类注释 Class {@code Object} is the root of the class hierarchy. Every class has {@code Object} as a s ...

  2. Java源码分析 | Object

    本文基于 OracleJDK 11, HotSpot 虚拟机. Object 定义 Object 类是类层次结构的根.每个类都有 Object 类作为超类.所有对象,包括数组等,都实现了这个类的方法. ...

  3. Java源码分析 | CharSequence

    本文基于 OracleJDK 11, HotSpot 虚拟机. CharSequence 定义 CharSequence 是 java.lang 包下的一个接口,是 char 值的可读序列, 即其本身 ...

  4. Programming a Spider in Java 源码帖

    Programming a Spider in Java 源码帖 Listing 1: Finding the bad links (CheckLinks.java) import java.awt. ...

  5. 解密随机数生成器(二)——从java源码看线性同余算法

    Random Java中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linear congruential formula线性同余方程(Donald Knuth的编程艺术 ...

  6. Java源码解读(一)——HashMap

    HashMap作为常用的一种数据结构,阅读源码去了解其底层的实现是十分有必要的.在这里也分享自己阅读源码遇到的困难以及自己的思考. HashMap的源码介绍已经有许许多多的博客,这里只记录了一些我看源 ...

  7. 【java集合框架源码剖析系列】java源码剖析之TreeSet

    本博客将从源码的角度带领大家学习TreeSet相关的知识. 一TreeSet类的定义: public class TreeSet<E> extends AbstractSet<E&g ...

  8. 【java集合框架源码剖析系列】java源码剖析之HashSet

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于HashSet的知识. 一HashSet的定义: public class HashSet&l ...

  9. 从Java源码到Java字节码

    Java最主流的源码编译器,javac,基本上不对代码做优化,只会做少量由Java语言规范要求或推荐的优化:也不做任何混淆,包括名字混淆或控制流混淆这些都不做.这使得javac生成的代码能很好的维持与 ...

随机推荐

  1. 【MyBatis学习12】MyBatis中的一级缓存

    缓存的作用是减轻数据库的压力,提高数据库的性能的.mybatis中提供了一级缓存和二级缓存,先来看一下两个缓存的示意图:   从图中可以看出: 一级缓存是SqlSession级别的缓存.在操作数据库时 ...

  2. go项目布局(摘录)

    go的项目结构布局 或 包结构布局 这一块大家似乎还在摸索吧, 常用的应该还是类似于java的mvc布局, 但网上也有不同的布局方式,查阅github上的一些源码,也有大量的采用. 我把自己碰到的资料 ...

  3. 当你输入一个网址/点击一个链接,发生了什么?(以www.baidu.com为例)

    >>>点击网址后,应用层的DNS协议会将网址解析为IP地址: DNS查找过程: 浏览器会检查缓存中有没有这个域名对应的解析过的IP地址,如果缓存中有,这个解析过程就将结束. 如果用户 ...

  4. 使用BMap.Label给百度地图的BMap.Marker上加上数字序号

    marker = new BMap.Marker(pointList[i]) marker.setLabel(getNumberLabel(i)); function getNumberLabel(n ...

  5. jQuery读取json文件

    转 http://www.jb51.net/article/36678.htm 1.userInfo.html <!DOCTYPE html PUBLIC "-//W3C//DTD X ...

  6. PILE读书笔记_基础知识

    程序的构成 Linux下二进制可执行程序的格式一般为ELF格式. 我们可以用readelf命令来读取二进制的信息. ELF文件的主要内容就是由各个section及symbol表组成的. 下面来分别介绍 ...

  7. java 使用Date类、Calendar类,实现增加日期

    Date date= new Date(); System.out.println("Date date= new Date()中的date: "+date); 输出对象date: ...

  8. DJI SDK iOS 开发之二:搭建主要的开发环境

    本文想介绍搭建主要的DJI SDK iOS下的开发环境,只是DJI官方已经给出了非常具体的执行其demo的教程.网址例如以下: https://dev.dji.com/cn/guide 我这里总结一下 ...

  9. 谁是云的王者?OpenStack与VMware优劣对比

    [编者按]在云计算生态系统中,有两种类型的用户需要使用云计算资源:传统型(Traditional IT applications)和在互联网大潮下逐渐崛起云计算应用型(Cloud-aware appl ...

  10. eclipse 打开的时候弹出 'Building workspace' has encountered a problem. Errors occurred during

    Eclipse 里面project->Build Automatically上的对勾去掉