Object类是Java一个比较特殊的类,它是类层次结构的根,位于继承树的顶层,即Java中所有的类从根本上都继承自Object类。它是Java中唯一没有父类的类。 如果一个类没有使用extends关键字明确标识继承另外一个类,那么这个类就默认继承Object类,因此,Object类是Java类层中的最高层类,是所有类的超类。换句话说,Java中任何一个类都是它的子类。由于所有的类都是由Object类衍生出来的,所以Oject类中的方法适用于所有类,因此下面的两种类的定义形式,从本质上讲是完全一样的。

public class Person {	//当没有指定父类时,会默认Object类为其父类
	//...
}
// 上面的程序等价于:
public class Person extends Object {
	//...
}

以下介绍几种Object类中的常用的方法:

返回值类型

方法名

输入参数

抛出异常

操作功能

构造方法

Object

创建Object对象

Object

clone

CloneNotSupportedException

创建并返回对象的一个副本

boolean

equals

Object

指示其他某个对象是否与此对“相等”

void

finalize

Throwable

当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法

Class

getClass

返回此Object的运行时类

int

hashCode

返回该对象的哈希码值

void

notify

IlleagalMonitorStateException

唤醒在此对象监视器上等待的某个线程

void

notifyAll

IlleagalMonitorStateException

唤醒在此对象监视器上等待的所有线程

void

wait

InterruptedException

在其他线程调用此对象的notifyAll()方法时,导致当前线程等待

String

toString

返回该对象的字符串表示

void

wait

long

InterruptedException

在其他线程调用此对象的 notify() 或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待

void

wait

long,int

InterruptedException

在其他线程调用此对象的 notify() 或 notifyAll() 方法,或者其他某个线程中断当前线程,或者超过指定的时间量前,导致当前线程等待

1、取得对象信息:toString()

Object类的toString()方法是在打印对象时被调用,将对象信息变为字符串返回。 默认的toString()方法有一个特点:为了适用于所有的子类,toString()在默认情况下输出对象地址,当然,每一个子类也可以自己进行修改。

例:

package object;
class Person extends Object {
	String name = "张三";
	int age = 25;
}
public class ObjectDemo1 {
	public static void main(String[] args) {
		Person p = new Person();
		System.out.println(p);	// 直接输出对象p
		System.out.println(p.toString());	// 调用toString()
	}
}

【结果】

子类实例没有父类实例的值 java java没有子类的类称为_equals

对象输出时,会默认调用Object类的toString()方法,将对象信息变为字符串返回。 但是从程序中可以看到,在打印对象p的时候实际上打印出来的是一些无序的字符串,这样的字符串很少有人能看懂是什么意思。

再观察下面的范例,覆写了Object类中的toString()方法:

package object;
class Person extends Object {
	String name = "张三";
	int age = 25;
	public String toString() {	// 覆写toString()
		return "我是:" + this.name + ",今年:" + this.age + "岁。";
	}
}
public class ObjectDemo1 {
	public static void main(String[] args) {
		Person p = new Person();
		System.out.println(p);	// 直接输出对象p
		System.out.println(p.toString());	// 调用toString()
	}
}

【结果】

子类实例没有父类实例的值 java java没有子类的类称为_Object_02

2、对象相等判断方法:equals()

equals(),此方法用于比较对象是否相等,而且此方法必须被覆写。

为什么要覆写它呢?请看下面的范例,这是一个没有覆写equals()方法的范例。

package object;
class Person {
	private String name;
	private int age;
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
}
public class ObjectEquals {
	public static void main(String[] args){
		Person p1 = new Person("张三", 25);
		Person p2 = new Person("张三", 25);
		// 判断p1和p2的内容是否相等
		System.out.println(p1.equals(p2));
	}
}

【结果】

子类实例没有父类实例的值 java java没有子类的类称为_toString_03

从程序中可以看到,两个对象的内容完全相等,但为什么比较的结果是不相等呢?这是因为p1与p2的内容分别在不同的内存空间指向了不同的内存地址。在用equals对两个对象进行比较时,实际上是比较两个对象的地址

若想比较两个对象的内容,则必须覆写equals()方法,如下:

package object;
class Person {
	private String name;
	private int age;
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	// 覆写父类(Object类)中的equals()方法
	public boolean equals(Object obj) {
		boolean temp = true;
		// 声明一个p1对象,此对象实际上就是当前调用equals()方法的对象
		Person p1 = this;
		
		// 判断Object类对象是否是Person的实例
		if(obj instanceof Person) {
			// 如果是Person类实例,则进行向下转型
			Person p2 = (Person)obj;
			// 调用String类中的equals()方法,String类中的方法已经覆写过,可用于比较内容
			if(!(p1.name.equals(p2.name)&&p1.age == p2.age)) {
				temp = false;
			}
		}
		else {
			// 如果不是Person类的实例,则直接返回false
			temp = false;
		}
		return temp;
	}
}
public class ObjectEquals {
	public static void main(String[] args){
		Person p1 = new Person("张三", 25);
		Person p2 = new Person("张三", 25);
		// 判断p1和p2的内容是否相等
		System.out.println(p1.equals(p2));
	}
}

【结果】

子类实例没有父类实例的值 java java没有子类的类称为_Java_04

由上例可以看出通过覆写后的equals方法能够准确的对两个对象进行比较。所以在开发中往往需要覆写equals方法。

3、对象签名的hashCode()

Object类有两种方法来推断对象的标识:equals() 和 hashCode()。

如果根据equals() 方法判断两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode()方法都必须生成相同的整数结果

但是反过来,如果两个hashCode()返回的结果相等,两个对象的equals()方法却不一定相等。

在默认情况下equals()方法用来比较两个对象的地址值,而原始的hashCode()方法用来返回其所在对象的物理地址。

class Person {
	private String name;
	private int id;
	public Person(String name, int id) {
		this.name = name;
		this.id = id;
	}
	
	public int hashCode() {	// 覆写hashCode方法
		return id*(name.hashCode());
	}
	
	// 覆写父类(Object类)中的equals()方法
	public boolean equals(Object obj) {
		boolean temp = true;
		// 声明一个p1对象,此对象实际上就是当前调用equals()方法的对象
		Person p1 = this;
		
		// 判断Object类对象是否是Person的实例
		if(obj instanceof Person) {
			// 如果是Person类实例,则进行向下转型
			Person p2 = (Person)obj;
			// 调用String类中的equals()方法,String类中的方法已经覆写过,可用于比较内容
			if(!(p1.name.equals(p2.name)&&p1.id == p2.id)) {
				temp = false;
			}
		}
		else {
			// 如果不是Person类的实例,则直接返回false
			temp = false;
		}
		return temp;
	}
	

}
public class HashCode {
	public static void main(String[] args) {
		Person p1 = new Person("小刚", 1);
		Person p2 = new Person("小刚", 1);
		Person p3 = new Person("小光", 2);
		
		System.out.println(p1.equals(p2));
		System.out.println(p1.equals(p3));
		System.out.println(p1.hashCode());
		System.out.println(p2.hashCode());
		System.out.println(p3.hashCode());
	}
}

【结果】

子类实例没有父类实例的值 java java没有子类的类称为_子类实例没有父类实例的值 java_05

有结果可以看出p1.equals(p2)输出为true,p1.equals(p3)输出为false。由于重写了equals(),此时比较的不再是对象地址而是对象内容。 此时p1和p2的hash值相同,p1和p3的hash值是不同的。由于重写了hashCode (),此时返回的不再是地址,而是根据对象内容算出的一个值。

在覆写equals()方法的时候也必须覆写hashCode()方法。这样才能确保相等的两个对象拥有相等的.hashCode。

4、使用Object接收任意引用类数据类型对象

由于Object类是所有类的父类,所有类的对象都可以使用Object接收,Object类不光可以接收对象,还可以接收任意的引用数据类型(类、接口、数组)。

看下面这个例子:

public class ObjectArray {
	public static void main(String[] args) {
		int[] temp = {1,2,3,4,5};
		Object obj = temp;	// 用Object接收数组
		
		print(obj);
	}
	
	public static void print(Object obj) {
		if(obj instanceof int[]) { // 判断是否是整型数组
			int[] x = (int[])obj;
			for(int i = 0; i < x.length; i++) {
				System.out.print(x[i] + "\t");
			}
		}
	}
}

【结果】

子类实例没有父类实例的值 java java没有子类的类称为_子类实例没有父类实例的值 java_06

虽然数组和Object类之间是不存在任何的定义关系的,但是因为数组是引用类型,所以照样可以使用Object接收。

接口和Object更不会有任何的关系,因为接口本身不可能去继承任何的一个类,可是在Java设计的时候由于很多地方都需要接口的支持,所以Object依然可以接收接口类型。

如下:

interface A {
	public String getInfo();
}
class B implements A {
	public String getInfo() {
		return "Hello World!";
	}
}

public class ObjectInterface {
	public static void main(String[] args) {
		A a = new B();	// 向上转型,为接口实例化
		Object obj = a;	// 向上转型,使Object接收a
		
		A x = (A)obj;	// 向下转型
		System.out.println(x.getInfo());
	}
}

【结果】

子类实例没有父类实例的值 java java没有子类的类称为_子类实例没有父类实例的值 java_07

由上例知,只要是个引用类型,都可以通过Object接收,可以先把a向上转型为Object类型,因为Object是所有类的父类,也就是基类,所以所有的类都可以向上转型成为Object,然后他又将obj强制转换回了A,第1System.out里面调用了x的getInfo()方法,因为x一直是指向B的实例的,所以调用的就是B的getInfo()方法。