Object

参考原文:https://www.cnblogs.com/Java3y/p/8985368.html

Object是所有类的基类,这个你可以查询jdk文档了解,所有类都继承自Object。

java 6 api:

实心的代表方法 
空心的代表属性 
绿色的圆表示公有public 
黄色的菱形表示保护protect 
红色的方形表示私有private 
蓝色的三角表示default 

图形后加字母S代表该属性或方法为static静态的,加字母F代表它为final的,加字母A表示抽象abstract,加c表示构造方法construction。 
方法后加蓝色三角代表它是继承至父类的方法 
断点为蓝色小圆形 
蓝色旗状图形代表书签 

白底上加蓝色对钩代表task

有兴趣可以看Eclipse中Outline里各种图标的含义:https://blog.csdn.net/frankarmstrong/article/details/61520279

java 8 api:

 

对其中几个函数进行描述。

 public final native Class<?> getClass();

该方法返回的是Object对象的类对象/运行时的类对象Class<?>

Class c = obj.getClass(); 通过对象c,我们可以获取该对象的所有成员方法,每个成员方法都是一个Method对象;我们也可以获取该对象的所有成员变量,每个成员变量都是一个Field对象;同样的,我们也可以获取该对象的构造函数,构造函数则是一个Constructor对象,具体见下面的例子:

 1 package xyz;
 2 
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.Field;
 5 import java.lang.reflect.Method;
 6 
 7 /**
 8  * 打印类的信息,包括类的构造函数,成员函数,成员变量
 9  * 
10  * 
11  */
12 public class ObjectTest {
13 
14     /**
15      * 获取对象的成员方法的信息
16      * 
17      * @param obj
18      */
19     public static void printClassMethodMessage(Object obj) {
20         // 要获取类的信息 首先要获取类的类类型,传递的是哪个子类的对象 c就是该子类的类类型
21         Class c = obj.getClass();
22         // 获取类的名称
23         System.out.println("类的名称是:" + c.getName());
24         /*
25          * Method类,方法对象 一个成员方法就是一个Method对象
26          * getMethods()方法获取的是所有的public的函数,包括父类继承而来的
27          * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
28          */
29         // c.getDeclaredMethods()
30         Method[] ms = c.getMethods();
31         for (int i = 0; i < ms.length; i++) {
32             // 得到方法的返回值类型的类类型
33             Class returnType = ms[i].getReturnType();
34             System.out.print(returnType.getName() + " ");
35             // 得到方法的名称
36             System.out.print(ms[i].getName() + "(");
37             // 获取参数类型--->得到的是参数列表的类型的类类型
38             Class[] paramTypes = ms[i].getParameterTypes();
39             for (Class class1 : paramTypes) {
40                 System.out.print(class1.getName() + ",");
41             }
42             System.out.println(")");
43         }
44     }
45 
46     /**
47      * 获取对象的成员变量的信息
48      * 
49      * @param obj
50      */
51     public static void printFieldMessage(Object obj) {
52         Class c = obj.getClass();
53         /*
54          * 成员变量也是对象 java.lang.reflect.Field Field类封装了关于成员变量的操作
55          * getFields()方法获取的是所有的public的成员变量的信息
56          * getDeclaredFields获取的是该类自己声明的成员变量的信息
57          */
58         // Field[] fs = c.getFields();
59         Field[] fs = c.getDeclaredFields();
60         for (Field field : fs) {
61             // 得到成员变量的类型的类类型
62             Class fieldType = field.getType();
63             String typeName = fieldType.getName();
64             // 得到成员变量的名称
65             String fieldName = field.getName();
66             System.out.println(typeName + " " + fieldName);
67         }
68     }
69 
70     /**
71      * 打印对象的构造函数的信息
72      * 
73      * @param obj
74      */
75     public static void printConMessage(Object obj) {
76         Class c = obj.getClass();
77         /*
78          * 构造函数也是对象 java.lang. Constructor中封装了构造函数的信息
79          * getConstructors获取所有的public的构造函数 getDeclaredConstructors得到所有的构造函数
80          */
81         Constructor[] cs = c.getDeclaredConstructors();
82         for (Constructor constructor : cs) {
83             System.out.print(constructor.getName() + "(");
84             // 获取构造函数的参数列表--->得到的是参数列表的类类型
85             Class[] paramTypes = constructor.getParameterTypes();
86             for (Class class1 : paramTypes) {
87                 System.out.print(class1.getName() + ",");
88             }
89             System.out.println(")");
90         }
91     }
92 }

回归正途:hashCode 与equals

hashCode:

public native int hashCode();

equals:

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

看上去都非常简单:

    hashCode()由native方法底层实现了(native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中)。

    equals就直接"=="来判断是否为同一对象。("=="我们知道对于对象而言,比较是它们的存储的地址是否一致)。

equals与hashCode

  

equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。
hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数。根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一 的;当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。之所以有hashCode方法,是因为在批量的对象比较中,hashCode要比equals来得快,很多集合都用到了hashCode,比如HashTable。

两个obj,如果equals()相等,hashCode()一定相等。
两个obj,如果hashCode()相等,equals()不一定相等(Hash散列值有冲突的情况,虽然概率很低)。
所以:
    可以考虑在集合中,判断两个对象是否相等的规则是:
    第一步,如果hashCode()相等,则查看第二步,否则不相等;
    第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。

1、首先equals()和hashcode()这两个方法都是从object类中继承过来的。

  equals()是对两个对象的地址值进行的比较(即比较引用是否相同)。

  hashCode()是一个本地方法,它的实现是根据本地机器相关的。

2、Java语言对equals()的要求如下,这些要求是必须遵循的:

  A 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。

  B 反射性:x.equals(x)必须返回是“true”。

  C 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。

  D 一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。

  任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。

3、equals()相等的两个对象,hashcode()一定相等;

  反过来:hashcode()不等,一定能推出equals()也不等;

  hashcode()相等,equals()可能相等,也可能不等。 

为什么要重写equals方法?
  因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。
  说道这个地方我相信很多人会有疑问,相信大家都被String对象的equals()方法和"=="纠结过一段时间,当时我们知道String对象中equals方法是判断值的,而==是地址判断。
那照这么说equals怎么会是地址的比较呢?
  那是因为实际上JDK中,String、Math等封装类都对Object中的equals()方法进行了重写。
  我们先看看Object中equals方法的源码:(上面有)
  我们都知道所有的对象都拥有标识(内存地址)和状态(数据),同时“==”比较两个对象的的内存地址,所以说使用Object的equals()方法是比较两个对象的内存地址是否相等,即若object1.equals(object2)为true,则表示equals1和equals2实际上是引用同一个对象。虽然有时候Object的equals()方法可以满足我们一些基本的要求,但是我们必须要清楚我们很大部分时间都是进行两个对象的比较,这个时候Object的equals()方法就不可以了,所以才会有String这些类对equals方法的改写,依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。希望大家不要搞混了。

改写equals时总是要改写hashcode

 

java.lnag.Object中对hashCode的约定:
   1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
   2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
   3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
根据上一个问题,实际上我们已经能很简单的解释这一点了,比如改写String中的equals为基于内容上的比较而不是内存地址的话,那么虽然equals相等,但并不代表内存地址相等,由hashcode方法的定义可知内存地址不同,没改写的hashcode值也可能不同。所以违背了第二条约定。
又如new一个对象,再new一个内容相等的对象,调用equals方法返回的true,但他们的hashcode值不同,将两个对象存入HashSet中,会使得其中包含两个相等的对象,因为是先检索hashcode值,不等的情况下才会去比较equals方法的。

String怎么实现的equals和hashCode方法

equals:

 

hashCode:

 

toString()方法

 

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

 返回的是该对象的字符串表现形式,一般都会重写该方法。

可以看出原型的字符串表现形式,并不是我们需要的,看不出任何东西,重写该方法,把需要的属性输出。

clone方法

 protected native Object clone() throws CloneNotSupportedException;

用来创建并返回此对象的副本,实际返回的是该对象的一个引用,指向的是新clone出来的对象,此对象与原对象占用不同的内存空间。(有浅拷贝与深拷贝之分)

finalize()方法

  protected void finalize() throws Throwable { }

该方法主要跟垃圾回收有关,我们暂时不需要关心此方法

 

wait和notify方法

无论是wait、notify还是notifyAll()都需要由监听器对象(锁对象)来进行调用。

 

简单来说:他们都是在同步代码块中调用的,否则会抛出异常!notify()唤醒的是在等待队列的某个线程(不确定会唤醒哪个),notifyAll()唤醒的是等待队列所有线程

导致wait()的线程被唤醒可以有4种情况

  该线程被中断。

  wait()时间到了。

  被notify()唤醒。

  被notifyAll()唤醒。

调用wait()的线程会释放掉锁。

为什么wait和notify在Object方法上?

从一开始我们就说了:wait()notify()是Java给我们提供线程之间通信的API,既然是线程的东西,那什么是在Object类上定义,而不是在Thread类上定义呢?

因为我们的锁是对象锁,每个对象都可以成为锁。让当前线程等待某个对象的锁,当然应该通过这个对象来操作了

  • 锁对象是任意的,所以这些方法必须定义在Object类中

notify方法调用后,会发生什么?

上面已经说了,notify会唤醒某个处于等待队列的线程。

但是要注意的是:

  notify方法调用后,被唤醒的线程不会立马获得到锁对象。而是等待notify的synchronized代码块执行完之后才会获得锁对象

sleep和wait有什么区别?

  Thread.sleep()Object.wait()二者都可以暂停当前线程,释放CPU控制权。

  主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。

  而Thread.sleep()没有对锁释放。

 

posted @ 2018-07-09 19:40  星辰忧沙  阅读(479)  评论(0编辑  收藏  举报