Object类
Object类
java.lang.Object
要点:
java.lang包在使用的时候无需显示导入,编译时由编译器自动导入。
Object类是类层次结构的根,每个类都使用 Object 作为超类。
Java中所有的类从根本上都继承自这个类。每个类都直接或者间接的继承自Object类。
Object类是Java中唯一没有父类的类。
其他所有的类,包括标准容器类,比如数组,都继承了Object类中的方法
1 int hashCode()
Returns a hash code value for the object.
返回该对象的哈希码值。
* 哈希值是根据哈希算法计算出来的一个值,这个值和地址值有关,但是不是实际地址值。
* 你可以理解为地址值。(不是对象的实际地址值,可以理解为逻辑地址值)
* 不同对象的,hashCode()一般来说不会相同。但是,同一个对象的hashCode()值肯定相同
* 默认的hashcode方法即使是同一个对象 每一次也都会返回不同的值
当你覆写(override)了equals()方法之后,必须也覆写hashCode()方法,反之亦然。
这个方法返回一个整型值(hash code value),如果两个对象被equals()方法判断为相等,那么它们就应该拥有同样的hash code。
Object类的hashCode()方法为不同的对象返回不同的值,Object类的hashCode值表示的是对象的地址。
hashCode的一般性契约(需要满足的条件)如下:
1.在Java应用的一次执行过程中,如果对象用于equals比较的信息没有被修改,那么同一个对象多次调用hashCode()方法应该返回同一个整型值。
应用的多次执行中,这个值不需要保持一致,即每次执行都是保持着各自不同的值。
2.如果equals()判断两个对象相等,那么它们的hashCode()方法应该返回同样的值。
3.并没有强制要求如果equals()判断两个对象不相等,那么它们的hashCode()方法就应该返回不同的值。
即,两个对象用equals()方法比较返回false,它们的hashCode可以相同也可以不同。
但是,应该意识到,为两个不相等的对象产生两个不同的hashCode可以改善哈希表的性能。
示例:
1 String id; 2 String name ; 3 int age; 4 5 @Override 6 public int hashCode() { 7 final int prime = 31; 8 int result = 1; 9 result = prime * result + age; 10 result = prime * result + ((id == null) ? 0 : id.hashCode()); 11 result = prime * result + ((name == null) ? 0 : name.hashCode()); 12 return result; 13 }
2 boolean equals(Object obj)
Indicates whether some other object is "equal to" this one.
“==”运算符判断两个引用是否指向同一个对象。(地址)
对于Object类的equals()方法来说,它判断调用equals()方法的引用于传进来的引用是否一致,即这两个引用是否指向的是同一个对象。(内容)
Object类中的equals()方法如下:
public boolean equals(Object obj)
{
return (this == obj);
}
即Object类中的equals()方法等价于==。
只有当继承Object的类覆写(override)了equals()方法之后,继承类实现了用equals()方法比较两个对象是否相等,才可以说equals()方法与==的不同。
equals()方法需要具有如下特点:
自反性(reflexive):任何非空引用x,x.equals(x)返回为true。
对称性(symmetric):任何非空引用x和y,x.equals(y)返回true当且仅当y.equals(x)返回true。
传递性(transitive):任何非空引用x和y,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)返回true。
一致性(consistent):两个非空引用x和y,x.equals(y)的多次调用应该保持一致的结果,(前提条件是在多次比较之间没有修改x和y用于比较的相关信息)。
约定:对于任何非空引用x,x.equals(null)应该返回为false。
并且覆写equals()方法时,应该同时覆写hashCode()方法,反之亦然。
具体步骤:
1 比较是否为一个对象 return (this == obj);
2 比较是否为空值 return (obj == null);
3 比较类型 return this.getClass() == obj.getClass();
4 比较具体内容
示例:
1 String id; 2 String name ; 3 int age; 4 5 6 @Override 7 public boolean equals(Object obj) { 8 if (this == obj) 9 return true; 10 if (obj == null) 11 return false; 12 if (getClass() != obj.getClass()) 13 return false; 14 ObjecDemo other = (ObjecDemo) obj; 15 if (age != other.age) 16 return false; 17 if (id == null) { 18 if (other.id != null) 19 return false; 20 } else if (!id.equals(other.id)) 21 return false; 22 if (name == null) { 23 if (other.name != null) 24 return false; 25 } else if (!name.equals(other.name)) 26 return false; 27 return true; 28 }
要点:
* ==:
基本类型:比较的就是值是否相同
引用类型:比较的就是地址值是否相同
* equals:
引用类型:默认情况下,比较的是地址值。
不过,我们可以根据情况自己重写该方法。
一般重写都是自动生成(myeclipse可以帮助我们上生成高质量的equals和hashcode方法,快捷键:shift+alt+s 选择相应的项目),比较对象的成员变量值是否相同
3 String toString()
Returns a string representation of the object.
当打印引用,如调用System.out.println()时,会自动调用对象的toString()方法,打印出引用所指的对象的toString()方法的返回值,
因为每个类都直接或间接地继承自Object,因此每个类都有toString()方法。
Object类中的toString()方法定义如下:
1 public String toString() 2 { 3 return getClass().getName() + "@" + Integer.toHexString(hashCode()); 4 }
Integer类下的一个静态方法:public static String toHexString(int i):把一个整数转成一个十六进制表示的字符串
Integer类下的一个静态方法:public static String toHexString(int i):把一个整数转成一个十六进制表示的字符串
A:返回该对象的字符串表示。
底层源码:
1 public static String valueOf(Object obj) { 2 return (obj == null) ? "null" : obj.toString(); 3 }
B:它的值等于:getClass().getName() + '@' + Integer.toHexString(hashCode())
C:由于默认情况下的数据对我们来说没有意义,一般建议重写该方法。
@Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; }
4 public final Class getClass():返回此 Object 的运行时类
A:返回此 Object 的运行时类。
B:可以通过Class类中的一个方法,获取对象的真实类的全名称。
C:反射
5 protected void finalize()
A:当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
B:垃圾回收器不会马上回收垃圾,但是我们可以建议它尽快回收垃圾。(System.gc()方法)
C:主要针对堆内存。
6 protected Object clone()
Creates and returns a copy of this object.
Object类中的说明是:
protected Object clone()
throws CloneNotSupportedException
这个方法比较特殊:
首先,使用这个方法的类必须实现java.lang.Cloneable接口,否则会抛出CloneNotSupportedException异常。
Cloneable接口中不包含任何方法,所以实现它时只要在类声明中加上implements语句即可。
第二个比较特殊的地方在于这个方法是protected修饰的,覆写clone()方法的时候需要写成public,才能让类外部的代码调用
Cloneable:此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
* 这个接口是标记接口,告诉我们实现该接口的类就可以实现对象的复制了。
protected Object clone()
创建并返回此对象的一个副本,这种克隆机制十分高效,而且二者之间完全隔离。
自定义类实现克隆步骤:
A:自定义类实现Cloneable接口,这是一个标记性接口,实现这个接口的类的对象可以实现自我克隆。
B:自定义类中重写Object类的clone()方法。
C:重写clone()方法时通过super.clone()调用Object类的clone()方法来得到该对象的副本,并返回该副本。
注意:
A:克隆和两个引用指向同一个对象的区别?
B:Object类clone()方法虽然简单,易用,但仅仅是一种”浅克隆”,它只克隆该对象所有的Field值,不会
对引用类型的Field所引用的对象进行克隆。开发中,我们也可以实现对象的”深度克隆”。
7 与线程相关:
void notify()
唤醒在此对象监视器上等待的单个线程。
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
String toString()
返回该对象的字符串表示。
void wait()
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
void wait(long timeout)
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
void wait(long timeout, int nanos)
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
Object 原码及简单说明:
1 package java.lang; 2 public class Object { 3 4 /* 一个本地方法,具体是用C(C++)在DLL中实现的,然后通过JNI调用。*/ 5 private static native void registerNatives(); 6 7 /* 对象初始化时自动调用此方法*/ 8 static { 9 registerNatives(); 10 } 11 12 /* 返回此 Object 的运行时类。*/ 13 public final native Class<?> getClass(); 14 15 /* 16 hashCode 的常规协定是: 17 1.在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数, 18 前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 19 2.如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。 20 3.如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。 21 但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。 22 */ 23 24 public native int hashCode(); 25 26 27 public boolean equals(Object obj) { 28 return (this == obj); 29 } 30 31 /*本地CLONE方法,用于对象的复制。*/ 32 protected native Object clone() throws CloneNotSupportedException; 33 34 /*返回该对象的字符串表示。非常重要的方法*/ 35 public String toString() { 36 return getClass().getName() + "@" + Integer.toHexString(hashCode()); 37 } 38 39 /*唤醒在此对象监视器上等待的单个线程。*/ 40 public final native void notify(); 41 42 /*唤醒在此对象监视器上等待的所有线程。*/ 43 public final native void notifyAll(); 44 45 46 /*在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。 47 当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。 48 然后该线程将等到重新获得对监视器的所有权后才能继续执行。*/ 49 public final void wait() throws InterruptedException { 50 wait(0); 51 } 52 53 54 55 /*在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。*/ 56 public final native void wait(long timeout) throws InterruptedException; 57 58 /* 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。*/ 59 public final void wait(long timeout, int nanos) throws InterruptedException { 60 if (timeout < 0) { 61 throw new IllegalArgumentException("timeout value is negative"); 62 } 63 64 if (nanos < 0 || nanos > 999999) { 65 throw new IllegalArgumentException( 66 "nanosecond timeout value out of range"); 67 } 68 69 if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { 70 timeout++; 71 } 72 73 wait(timeout); 74 } 75 76 /*当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。*/ 77 protected void finalize() throws Throwable { } 78 }