转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/77198401,建议读者阅读原文,确保获得完整的信息
1.Object描述
先来看看Object的API说明:
public class Object
Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.
Since:
JDK1.0
See Also:
Class
意思是说,Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
2.Object方法摘要
返回值 | 方法主体 | 说明 |
---|---|---|
protected Object | clone() | 创建并返回此对象的一个副本。 |
boolean | equals(Object obj) | 指示其他某个对象是否与此对象“相等”。 |
protected void | finalize() | 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。 |
Class | getClass() | 返回此 Object 的运行时类。 |
int | hashCode() | 返回该对象的哈希码值。 |
void | notify() | 唤醒在此对象监视器上等待的单个线程。 |
void | notifyAll() | 唤醒在此对象监视器上等待的所有线程。 |
String | toString() | 返回该对象的字符串表示。 |
void | wait() | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。 |
void | wait(long timeout) | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。 |
void | wait(long timeout, int nanos) | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。 |
3.拓展说明
3.1 equals(Object obj)方法
equals比较的是两个对象是否“相等”,即引用是否指向同一个对象,侧重判断对象内容是否相同。“==”号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。
public class ObjectTest {
private class Pikachu{
private String name;
private Pikachu(String name){
this.name = name;
}
}
public static void main(String[] args){
Pikachu a = new ObjectTest().new Pikachu("A");
Pikachu b = new ObjectTest().new Pikachu("A");
Pikachu m = a;
String c = "AB";
String d = "AB";
String e = new String("AB");
String f = new String("AB");
System.out.println("a.equals(b):" + a.equals(b));
System.out.println("c.equals(d):" + c.equals(d));
System.out.println("e.equals(d):" + e.equals(d));
System.out.println("e.equals(f):" + e.equals(f));
System.out.println("m.equals(a):" + m.equals(a));
System.out.println("a hashcode:" + a.hashCode());
System.out.println("b hashcode:" + b.hashCode());
System.out.println("c hashcode:" + c.hashCode());
System.out.println("d hashcode:" + d.hashCode());
System.out.println("e hashcode:" + e.hashCode());
System.out.println(e==f);
System.out.println(c==d);
}
}
输出结果:
a.equals(b):false
c.equals(d):true
e.equals(d):true
e.equals(f):true
m.equals(a):true
a hashcode:1580066828
b hashcode:491044090
c hashcode:2081
d hashcode:2081
e hashcode:2081
false
true
从输出结果可以看出,对于new出来的对象,equals返回肯定是false,但有一个特例就是String,如果对象是new String(“XXX”),则只会比较其值。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
比较对象是否相同时需要温习Java堆、栈和常量池相关知识,后面专门讨论下这块内容。
3.2 toString()方法
API中的解释就是,返回该对象的字符串表示。
private void toStringTest(){
Pikachu a = new ObjectTest().new Pikachu("A");
Pikachu b = new ObjectTest().new Pikachu("A");
System.out.println(a.toString());
System.out.println(b.toString());
}
输出结果形如类名+对象内存地址:
com.loongshawn.ObjectTest$Pikachu@5e2de80c
com.loongshawn.ObjectTest$Pikachu@1d44bcfa
如果本意是想输出这个对象的名字呢,则需要重写toString()方法,如下:
private class Pikachu{
private String name;
private Pikachu(String name){
this.name = name;
}
public String toString(){
return name;
}
}
输出结果如下:
A
A
3.3 hashCode()方法
hashCode() 方法用于返回字符串的哈希码。不是什么内存地址,所以理解不要偏了。以字符串对象为例,其哈希码根据以下公式计算:
s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]
s[i]为字符,n为字符数组长度
对应源码为:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
hashCode()与equals()需要配合起来用,下面总结几点之间的关系:
- hashCode值相等,不能肯定的说两个对象equals为true。
- hashCode值不等,两个对象equals结果为false。
- 两个对象equals结果true,则其hashCode一定相等。
一个对象在任何时刻,其hashCode值不能变,因此在设计程序重写hashCode时,需要选取一个不变的常量来参与hashCode计算,在《Java编程思想》一书中有一条类似的一段话:
“设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该产生同样的值。如果在讲一个对象用put()添加进HashMap时产生一个hashCdoe值,而用get()取出时却产生了另一个hashCode值,那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化时,hashCode()方法就会生成一个不同的散列码”。
3.4 Integer说明
比较Integer对象
Integer i = 3;
int j = 3;
Integer k = 128;
Integer l = 128;
System.out.println(i==j); // true
System.out.println(k==l); // false
值类型int与引用类型Integer比较时,仅比较值;引用类型Integer与引用类型Integer比较时,比较其内存地址。Integer值范围(-128~127)会在第一次使用时进行初始化,因此这个范围内的对象不会新建,返回已存在的内存地址。具体源码如下:
// 赋值操作
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
// 对象初始化(-128~127)
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}