首先简单的介绍一下Object类。java
java.lang.Objectc++
java.lang包使用的时候,不用显示导入,由编译器自动导入。多线程
Objec(即对象类)是JDK1.0就出现的,是类层次结构的根,是Java中的顶级父类,Java中全部的类都默认直接或者间接的继承Object类。Objec是Java中惟一没有父类的类,任何一个类的对象均可以用Object对象接收。以下:函数
//以下操做都是能够的。 Object o1=new Object(); Object o2=new String(); Object o3=new ArrayList<>(); Object o4=new HashSet<>(); Object o5=new HashMap<>(); Object o6=new Integer(1);
而后咱们看一下,Object这个类的总体结构。this
如上图,我使用的是1.8的jdk,总共13个方法,本博文将参照API文档以及源码进行介绍。spa
API文档中构造方法中提供的全部构造方法默认是public修饰的。操作系统
API文档中提供了:pulbic Object()的构造方法,在实际代码中,没有写出,使用的是JVM提供的默认构造。.net
此方法用来克隆对象。克隆完成以后会产生一个新的对象,这个新对象和原对象的地址不一样可是属性值是同样的。线程
此方法说的通俗一点,就是一间房子彻底仿照另一间房子建造,不一样的只是位置,其余的所有同样。code
一个对象要想被克隆,那么这个对象对应的类必须实现Cloneable接口,Cloneable接口中没有任何的方法和属性,仅仅用于标识这个类产生的对象能够被克隆。
源码以下:
//方法源码 protected native Object clone() throws CloneNotSupportedException; //接口源码 public interface Cloneable { }
此方法是一个受保护的本地方法。native关键字修饰的是本地方法,底层是用c/c++语言实现的,Java源码中看不到其具体实现。
下面提供一个示例:
public class T1 implements Cloneable { int i; public static void main(String[] args) throws CloneNotSupportedException { T1 t = new T1(); t.i = 5; T1 t1 = (T1) t.clone(); System.out.println(t); System.out.println(t1); } }
此方法用于判断两个对象是否一致。
以下是源码:
public boolean equals(Object obj) { return (this == obj); }
从源码中能够看出,默认使用的是==运算符,比较的是对象的地址,也能够得出另一个结论,Object类中的equals方法等价于==。在开发中通常都要重写这个方法。Eclipse中右键Sourec中有自动生成。
其实这些特色都是咱们很早就学过的数学上的相等的特色。如下说起的都是非空和不是NAN的状况。
自反性:a.equals(a)结果为true。即本身等于本身,数学上的1=1。
对称性:a.equals(b)结果为true,那么在a和b都不发生改变的状况下,b.equals(a)结果也为true。即数学上的a=b,那么b=a。
一致性:a.equals(b)结果为true,那么在a和b没有发生过改变的状况下a.equals(b)结果一直为true。即a永远和b相等,也就是1=1永远都是这样。
约定:a.equals(null)为false,即非空a永远不等于null。
只有当继承Object的类重写了equals方法以后,此类中的equals方法才和==才有可能不一样,但这两个比较的使用的本质上仍是有一些不一样。
抛开重写不说,当比较的是基本类型的时候,==判断的是实际数据,而且基本类型身上也没有equals方法能够调用。对于引用类型而言==判断的是地址,equals则默认和==是同样的。equals只能做用于引用类型,默认比较的是两个对象的地址。
当重写来equals的时候,按照重写以后的逻辑进行比较。此时比较的逻辑才和==有很大的不一样。
因此仅使用==是没法完全判断两个对象是否相等,咱们须要针对equals方法进行重写,步骤以下:
1.判断地址是否同样,即直接使用==运算符。
2.判断对象是否为空。
3.判断对象的建立类型是否一致。
4.判断属性值是否一致。判断以前要将对象强转为顶级父类。判断属性值的时候注意String类型的判断。
示例:
Public boolean equals(Object obj){ if (this == obj) //1.判断地址是否一致 return true; if (obj == null) //2.判断参数是否为空 return false; if (getClass() != obj.getClass()) //3.判断类型是否一致 return false; Person other = (Person) obj; //4.强制转换类别 if (age != other.age) //5.判断属性是否一致 return false; if (gender != other.gender) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }
通知gc回收垃圾对象,可是垃圾回收器不必定执行。
源码以下:
protected void finalize() throws Throwable { }
你没有看错,源码是个空方法,即便gc开始运行,也只回收当前对象而不回收其余对象。
首先,Object中定义finalize方法代表Java中每个对象都将具备finalize这种行为,其具体调用时机在:JVM准备对此对形象所占用的内存空间进行垃圾回收前,将被调用。由此能够看出,此方法并非由咱们主动去调用的(虽然能够主动去调用,此时与其余自定义方法无异)。
类似的:System.gc();通知gc回收对象,不限制范围。
获取对象的实际类型(建立类型)。
Object o1=new Object(); o1.getClass(); //上面等同于下面 Object.class
视具体场景而定,使用哪一种方法实现获取类型。
源码以下:
public final native Class<?> getClass();
由源码能够看出,此方法也使用native修饰。
返回对象的哈希码值的十进制。哈希码是一串32位的二进制数据,因为出现相同的数值的几率很是低,因此能够认为是惟一的。
源码以下:
public native int hashCode();
由源码能够看出,此方法也使用native修饰。通常重写equals方法的同时都会重写这个方法。可是不建议手动重写,使用IDE生成便可。
重写hashCode的时候,当equals值为true的时候,哈希码必须一致。可是哈希码一致equals不必定为true。
返回该对象的字符串表示。当打印对象的时候默认是调用了这个对象的toString方法。通常会重写。
源码以下:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串。因此切记不要搞混了,这里默认返回的不是对象的内存地址。
registerNatives函数前面有native关键字修饰,Java中,用native关键字修饰的函数代表该方法的实现并非在Java中去完成,而是由C/C++去完成,并被编译成了.dll,由Java去调用。方法的具体实现体在dll文件中,对于不一样平台,其具体实现应该有所不一样。用native修饰,即表示操做系统,须要提供此方法,Java自己须要使用。具体到registerNatives()方法自己,其主要做用是将C/C++中的方法映射到Java中的native方法,实现方法命名的解耦。
既然如此,可能有人会问,registerNatives()修饰符为private,且并无执行,做用何以达到?其实,在Java源码中,此方法的声明后有紧接着一段静态代码块,以下:
private static native void registerNatives(); static { registerNatives(); }
以下是这几个方法的源码:
//唤醒在此对象监听器上的单个等待的线程 public final native void notify(); //唤醒再次对象监听器上的全部等待的线程 public final native void notifyAll(); //线程处于等待timeout的时长,使用以上两个方法能够提早唤醒,也能够到时本身醒。 public final native void wait(long timeout) throws InterruptedException; //线程处于等待状态,只能被notify()/notifyAll()方法唤醒。 public final void wait() throws InterruptedException { //调用的wait方法,可是没有时长。 wait(0); } //timeout - 要等待的最长时间(以毫秒为单位)。 //nanos - 额外时间(以毫微秒为单位,范围是 0-999999)。 public final void wait(long timeout, int nanos) throws InterruptedException { //时间参数不合法 if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } //时间参数不合法 if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } //若是额外的时间大于500000毫微秒或者额外的时间不等于0等待时间为0 if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { //等待时间增长 timeout++; } //调用本地方法 wait(timeout); }