Java之Object类

#################

  object类

#################

JDK中所有类的基类--java.lang.Object

Object类的结构图

 什么是native方法?

  native关键字标识的Java方法为本地方法,底层是由C/C++程序编译后dll文件,Java加载dll文件后,可通过本地方法调用dll函数。

1.类构造器

  是创建Java对象的途径之一,通过new关键字调用构造器完成对象的实例化,或通过构造器对象进行相应的初始化。在JDK的object类源码中,系统会自动添加一个无参构造器。

1 public Object(){}
2 Object obj =new  Object();    //构造一个Object类的对象

2.registerNatives方法

1 private static native void registerNatives();
2     static {
3         registerNatives();
4     }

  静态代码块是一个类在初始化过程中必定会执行的内容,所以在类加载时会执行该方法,通过该方法来注册本地方法。

3.getClass方法

public final native Class<?> getClass();

  首先,该方法由final声明本地方法,不能被重写,作用是返回运行时类对象,通过这个类对象可以获取该运行时类的相关属性和方法。

  class是一个类的属性,能获取该类编译时的类对象;而getClass()是一个类的方法,它是获取该类运行时的类对象。

4.hashcode方法

1 public native int hashCode()

  这是一个由native声明的本地方法,作用是返回对象的哈希码(是int类型的数值)。

  哈希算法也称为散列算法,是将数据依据特定算法产生的结果直接指定到一个地址上,这个结果就是由hashcode方法产生的。当集合要添加新元素时,会先调用这个元素的hashcode方法,就能定位到它应该放置的物理位置上。

    1)如果这个位置上没有元素,就直接存储在这个位置上,不用再进行任何比较;

    2)如果这个位置上已经有元素,就调用它的equals方法与新元素进行比较,相同的话就不存了;不同的话(也就是产生了hash冲突),那么就在这个key的位置产生一个链表,将所有hashcode相同的对象存放在这个单链表上。

  如果两个对象的equals值比较相等,那么它们的hashcode值一定相等;如果两个对象的equals值比较不相等,那么他们的hashcode值可能相等,也可能不相等。

5.equals方法

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

  5.1 Object中的equals方法比较的是对象的地址是否相同;equals方法可以被重写,重写后equals方法比较的是两个对象值是否相同。  

  5.2 在Java规范中,对equals方法的使用必须遵循以下几个规则:

    自反性:对于任何非空引用值X,X.equals(X)都应返回true;

    对称性:对于任何非空引用值X和Y,当且仅当Y.equals(X)返回true时,X.equals(Y)也应该返回true;

    传递性:对于任何非空引用值X,Y,Z,如果X.equals(Y)返回true,并且Y.equals(Z)返回true,那么X.equals(Z)应返回true;

    一致性:对于任何非空引用值X和Y,多次调用X.equals(Y)始终返回true或始终返回false。

  5.3 equals和==的区别?

    equals比较的是两个对象值是否相等,如果没有被重写,比较的是对象的引用地址是否相同;

    ==用于比较基本数据类型的值是否相等,或比较两个对象的引用地址是否相等;

1 String hello = new String("hello");
2 String hello1 = new String("hello");
3 System.out.println(hello.equals(hello1));        //重写了,比较的是值,输出结果为true
4 System.out.println(hello == hello1);    //比较的是引用地址,输出结果为false
5 //比较基本类型的值
6 int age = 10;
7 int age2 = 10;
8 System.out.println(age == age2);    //输出为true

6.clone方法

1 protected native Object clone() throws CloneNotSupportedException;

  clone方法是创建并返回一个对象复制后的结果。

  如果一个类没有实现Cloneable接口(只是一个标记接口),那么对此类对象进行赋值时,会出现CloneNotSupportedException异常。

  clone生成的新对象与原对象的关系,区别在于两个对象间是否存在相同的引用或对应的内存地址是否存在共用情况;若存在,则为“浅复制”,否则为“深复制”,“深复制”时需要将共同关联的引用也复制完全。

7.toString方法

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

  打印某个对象时,默认是调用toString()方法。

  比如System.out.print(person)等价于System.out.print(person.toString());  //默认返回对象的地址

  getClass().getName是返回对象的全类名,Integer.toHexString(hashCode())是以16进制无符号整数形式返回此哈希码的字符串表示形式。

8.notify方法

1 public final native void notify();  

  唤醒可能等待该对象的对象锁的其他线程。由JVM(与优先级无关)随机挑选一个处于wait状态的线程。

  在调用notify()之前,线程必须获取该对象的对象锁,执行完notify()方法后,不会马上释放锁,直到退出synchronized代码块,当前线程才会释放锁;notify一次只能随机通知一个线程进行唤醒。

9.notifyAll方法

1 public final native void notifyAll();

  使所有正在等待池中等待同一个共享资源的全部线程从等待状态退出,进入可运行状态,让它们同时竞争对象锁,只有获得锁的线程才能进入就绪状态。

10.wait(long timeout)方法

1 public final native void wait(long timeout) throws InterruptedException;

11.wait(long timeout,int nanos)方法

 1 public final void wait(long timeout, int nanos) throws InterruptedException {
 2         if (timeout < 0) {
 3             throw new IllegalArgumentException("timeout value is negative");
 4         }
 5 
 6         if (nanos < 0 || nanos > 999999) {
 7             throw new IllegalArgumentException(
 8                                 "nanosecond timeout value out of range");
 9         }
10 
11         if (nanos > 0) {
12             timeout++;
13         }
14 
15         wait(timeout);
16     }

  wait(long timeout , int nanos)方法的实现只要nanos大于0,那么timeout时间就加上一毫秒,主要是更精确地控制时间,其他的跟wait(long timeout)一样。

12.wait方法

1  public final void wait() throws InterruptedException {
2         wait(0);
3     }

 wait方法会引起当前线程阻塞,直到另外一个线程在对应的对象上调用notify或notifyAll方法,或达到了方法参数中指定的时间。

  调用wait方法的当前线程一定要拥有对象的监视器锁。

  wait方法会把当前线程放在对应的等待队列中,在这个对象上的所有同步请求都不会得到响应。线程调用将不会调用线程,线程一直处于休眠状态。要注意的是,wait方法把当前线程放置到这个对象的等待队列中,解锁也仅仅是在这个对象上;当前线程在等待过程中仍然持有其他对象的锁。

  如果当前线程被其他线程在当前线程等待之前或正在等待时调用了interrupt()中断了,那么就会抛出InterruptException异常。

  13.1 为什么wait方法一般要写在while循环里?

   答:在某个线程调用notify到等待线程被唤醒的过程中,有可能出现另一个线程得到了锁并修改了条件使得条件不再满足;只有某些等待线程的条件满足了,但通知线程调用了notifyAll有可能出现“伪唤醒”。

  13.2 wait方法和sleep方法的区别?

   答:wait方法属于object类,当调用wait方法时,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify方法后本线程才会进入对象锁定池,准备获取对象锁进入运行状态。sleep方法属于thread类,sleep方法导致程序暂停执行指定的时间,让出CPU给其他线程,但是它的监控状态依然保持,当指定的时间到了又会恢复运行状态。在调用sleep方法过程中,线程不会释放对象锁。

13.finalize方法

1 protected void finalize() throws Throwable { }

  该方法用于垃圾回收,一般由JVM自动调用,不需要程序员手动调用该方法。

原文地址:https://www.cnblogs.com/HuiH/p/11677018.html