JDK1.8源码阅读(1):java.lang.Object

 

一、hashcode()

1、hashCode方法返回值是int类型的散列码,对象的散列码是为了更好的支持基于哈希机制的java集合类,例如Hashtable,HashMap,HashSet。如果重写equals方法,也要重写hashCode方法

2、hashCode方法的一致约定要求
(1)在java应用的一次执行过程中,对于同一个对象的hashCode方法的多次调用,他们应该返回同样的值(前提是该对象的信息没有发生变化);
(2)对于两个对象来说,如果使用equals方法比较返回true,那么这两个对象的hashCode值一定是相同的;
(3)对于两个对象来说,如果使用equals方法返回false,那么这两个对象的hashCode值不要求一定不同(可以相同,可以不同),但是如果不同则可以提高应用的性能。
(4)对于Object类来说,不同Object对象的hashCode值是不同的(Object类的hashcode值表示的是对象的地址)。

3、 hashCode方法应用举例:
  当使用HashSet时,hashCode()方法就会得到调用,判断已经存储在集合对象中的hashCode值是否与增加的对象的hashCode值一致;如果不一致,直接加进去;如果一致,在进行equals方法比较,equals方法返回true,表示对象已经加进去了,就不会再增加新的对象,否则加进去。

4、hashCode编写指导
  在编写hashCode时,由于返回值是个int值,故不能溢出。不同对象的hash尽量不同,避免hash冲突。下面是解决方案:

  • 定义一个int类型的变量hash,初始化为7。
  • 接下来将你认为重要的字段(equals中衡量相等的字段)参与散列运算,每一个重要字段都会产生一个hash分量,为最终的hash值做出贡献
  • 最后通过递归计算所有的分量的总和起,注意并不是简单的相加。选择一个倍乘的数字31,参与计算。 
int hash = 7;
hash = 31 * hash + 字段1贡献分量;
hash = 31 * hash + 字段2贡献分量;
.....
return hash;

二、getClass()

  用于获取对象的运行时对象的类。与.class区别:String.class 是能对类名的引用取得在内存中该类型class对象的引用,而new String().getClass() 是通过实例对象取得在内存中该实际类型class对象的引用。

我们可以使用一个小例子来看两者的不同:

1.抽象类

package com.kang;
public abstract class Animal {
}

2.实例类

package com.kang;

public class Dog extends Animal {
    public static void main(String[] args) {
        Animal animal = new Dog();
        System.out.println(animal.getClass().getName());
        //输出com.kang.Dog
          System.out.println(Animal.class.getName());
        //输出com.kang.Animal
    }
}

3.结果

com.kang.Dog
com.kang.Animal

4.解释

  animal.getClass().getName()是在程序运行时获得运行时实例的类类型。而Animal.class.getName()是在编译阶段就确定了的,与运行时的状态无关。

三、equals()

  Object中的equals方法是直接判断this和obj本身的值是否相等,即用来判断调用equals的对象和形参obj所引用的对象是否是同一对象,所谓同一对象就是指内存中同一块存储单元,如果this和obj指向的是同一块内存对象,则返回true,如果this和obj指向的不是同一块内存,则返回false,注意:即便是内容完全相等的两块不同的内存对象,也返回false。

那么equals()方法与之前的“==”有什么区别呢?

public class Equals{
    public static void main(String[] args){
        String s1="apple";
        String s2="apple";
        System.out.println(s1==s2);    //true
        System.out.println(s1.equals(s2));    //equals比较的是内容,true
        String s3=new String("apple");
        String s4=new String("apple");
        System.out.println(s3==s4);  //false
        System.out.println(s3.equals(s4));  //true
    }
}            

从上面的实例可以看出,“==”比较的是两个引用的对象是否相等,而equals()方法比较的是两个对象的实际内容。我们结合上面的内存的划分来理解这个区别。 

String str1=new String("apple");
String str2=new String("apple");
System.out.println(s3==s4);  //false
System.out.println(s3.equals(s4));  //true

上述几行代码内存分析如下图所示:

 

因为“==”比较的是两个引用的对象是否相等,从上图很容易看出来不等,所以System.out.println(s3==s4),结果为False;而equals()方法比较的是两个对象的实际内容,从图中可以看出s3和s4都指向apple,内容是相同的,所以System.out.println(s3.equals(s4)),结果为True。

再来看 

String s1="apple";
String s2="apple";

内存分析如下图:

 很容易看出System.out.println(s1==s2)的结果为True。

四、clone()

 

Object clone() 方法用于创建并返回一个对象的拷贝。

 

clone 方法是浅拷贝,对象内属性引用的对象只会拷贝引用地址,而不会将引用的对象重新分配内存,相对应的深拷贝则会连引用的对象也重新创建。

 

使用Object的clone方法必须实现 Cloneable 接口,否则调用会发生 CloneNotSupportedException 异常。

以下实例创建了 obj1 对象,然后拷贝 obj1 给 obj2,通过 obj2 输出变量的值: 

class RunoobTest implements Cloneable {
 
    // 声明变量
    String name;
    int likes;
 
    public static void main(String[] args) {
 
        // 创建对象
        RunoobTest obj1 = new RunoobTest();
 
        // 初始化变量
        obj1.name = "Runoob";
        obj1.likes = 111;
 
        // 打印输出
        System.out.println(obj1.name); // Runoob
        System.out.println(obj1.likes); // 111
 
        try {
 
            // 创建 obj1 的拷贝
            RunoobTest obj2 = (RunoobTest) obj1.clone();
 
            // 使用 obj2 输出变量
            System.out.println(obj2.name); // Runoob
            System.out.println(obj2.likes); // 111
        } catch (Exception e) {
            System.out.println(e);
        }
 
    }
}

以上程序执行结果为: 

Runoob
111
Runoob
111

五、toString()

用于返回对象的字符串表示形式。

默认返回格式:对象的 class 名称 + @ + hashCode 的十六进制字符串。

以下实例演示了 toString() 方法的使用:

class RunoobTest {
    public static void main(String[] args) {
         // toString() with Object
        Object obj1 = new Object();
        System.out.println(obj1.toString());
 
        Object obj2 = new Object();
        System.out.println(obj2.toString());
 
        Object obj3 = new Object();
        System.out.println(obj3.toString());
    }
}

以上程序执行结果为:

java.lang.Object@d716361
java.lang.Object@6ff3c5b5
java.lang.Object@3764951d

六、finalize()

当对象的没有被引用时,GC在收集垃圾时就会调用这个方法,即对象在被回收时回回调此方法

举例:

public class MyClass extends Object {
 
    public static void main(String[] args) {
        new MyObject();
                System.gc();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    static class MyObject extends Object{
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("finalize");
        }
    }
} 

控制台输出结果:

finalize

 

 
posted @ 2020-11-27 17:31  夕阳醉了  阅读(206)  评论(0编辑  收藏  举报