zoukankan      html  css  js  c++  java
  • 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
     
  • 相关阅读:
    Python 虚拟环境(VirtualEnv)
    python 枚举
    Python 面向对象编程
    Python 使用模块
    Python 函数
    Python dict & set
    JAVA-工具类
    09-12 练习题
    JAVA-数组
    java-语句
  • 原文地址:https://www.cnblogs.com/myshare/p/14049329.html
Copyright © 2011-2022 走看看