Java之路:Object类

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

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

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

返回值类型方法名输入参数抛出异常操作功能
构造方法Object创建Object对象
ObjectcloneCloneNotSupportedException创建并返回对象的一个副本
booleanequalsObject指示其他某个对象是否与此对“相等”
voidfinalizeThrowable当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
ClassgetClass返回此Object的运行时类
inthashCode返回该对象的哈希码值
voidnotifyIlleagalMonitorStateException唤醒在此对象监视器上等待的某个线程
voidnotifyAllIlleagalMonitorStateException唤醒在此对象监视器上等待的所有线程
voidwaitInterruptedException在其他线程调用此对象的notifyAll()方法时,导致当前线程等待
StringtoString返回该对象的字符串表示
voidwaitlongInterruptedException在其他线程调用此对象的 notify() 或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待
voidwaitlong,intInterruptedException在其他线程调用此对象的 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()
	}
}

【结果】
在这里插入图片描述

对象输出时,会默认调用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()
	}
}

【结果】
在这里插入图片描述

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));
	}
}

【结果】
在这里插入图片描述

从程序中可以看到,两个对象的内容完全相等,但为什么比较的结果是不相等呢?这是因为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));
	}
}

【结果】
在这里插入图片描述

由上例可以看出通过覆写后的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());
	}
}

【结果】
在这里插入图片描述

有结果可以看出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");
			}
		}
	}
}

【结果】
在这里插入图片描述

虽然数组和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());
	}
}

【结果】
在这里插入图片描述

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值