zoukankan      html  css  js  c++  java
  • 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()没有对锁释放。

  • 相关阅读:
    Java读取Excel文件(包括xls和xlsx)的样例程序
    Node.js中使用pipe拷贝大文件不能完全拷贝的解决办法
    Spring Boot中一个Servlet主动断开连接的方法
    算法学习笔记1.3.3 质因数分解
    算法学习笔记1.3.2 素数判定
    算法学习笔记1.3.1 素数筛法
    算法学习笔记1.2.2 扩展欧几里得
    算法学习笔记1.2.1 欧几里得算法
    算法学习笔记1.1.3 矩阵的逆
    Windows下Tesseract-OCR的安装
  • 原文地址:https://www.cnblogs.com/oldthree3/p/9285675.html
Copyright © 2011-2022 走看看