-
前言
Java中的所有类都直接或间接继承自Object类,因此Object类具有的功能所有的类都具有。本文将对Object类当中的一些重要方法进行介绍,主要包括tosString、equals与hashCode方法。
一、toString方法
toString方法是Object中重要的方法之一,该方法将返回此对象的字符串表示,以便在实际运行或调试代码时可以获取字符串表示的对象信息,下面给出了该方法的定义形式。
public String toString()
Java中大多数类都重写了这个方法,通常的方式是将类名以及成员变量的状态信息组合转化为一个字符串返回。如下面例子给出了重载toString方法的例子:
package chapter04;
class Student
{
public String name;
public int age;
public int classNum;
public Student() //学生类无参构造器
{
}
public Student(String name,int age,int classNum) //学生类有参构造器
{
this.name=name;
this.age=age;
this.classNum=classNum;
}
public String toString() //重写toString方法
{
return "学生t【名字=" + this.name + ",年龄=" + this.age + ",班级=" + this.classNum + "】";
}
}
public class Sample4_19
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
Object oo=new Student("张三",21,97001);
System.out.println(oo.toString());
System.out.println(oo);
}
}
在实际使用过程中,有很多情况都是通过多态调用toString方法的,这样可以提供大大的方变,无论用什么类型的引用,都可以调用指向对象的toString方法。
从图可以看出,两次打印的结果完全相同,这是因为System.out.println方法在打印引用时若引用不为空,则首先调用引用指向对象的toString方法获取字符串,然后再打印字符串内容。
这也正是System.out.println方法可以打印任何对象的原因,不过如果没有重写toString方法,就按Object类的实现获取字符串,打印出来的内容就很难理解了。因此,开发自己的类时如果没有特殊要求都应该重写toSting方法,这是一个良好的习惯。
二、equals方法的意义
前面介绍比较两个String的类内容是否相同时,使用了equals方法。其实,equals方法都是来自Object类的,String类对其重写以满足比较字符串的内容要求。Object类中设计这个方法就是为了让它的类来重写,以满足比较不同类型对象是否等价的要求。
再Object类中,该方法的实现相当于如下代码
public boolean equals(Object obj)
{
return (this == obj);
}
从代码中可以看出,Object类的实现并没有比较两个对象是否等价的功能,而只是对两个引用进行了“==”的比较,相当于比较两个引用是否指向同一个对象。因此,想真正具有比较对象是否等价的功能,需要在特定的类中根据比较规则重写此方法。
注意字符串类型的StringBuffer 的 equals 方法不能比较内容是否相同,就是因为StringBuffer类没有重写equals方法。例,一个没有重写equals方法:
package chapter04;
class Student
{
public String name;
public int age;
public int classNum;
//无参构造函数
public Student() { }
//有参构造函数
public Student(String name,int age,int classNum)
{
this.name=name;
this.age=age;
this.classNum=classNum;
}
}
public class Sample4_20
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
Student s1=new Student("张三",21,97001);
Student s2=new Student("张三",21,97001);
if(s1.equals(s2))
System.out.println("学生对象s1和s2是相同的");
else
System.out.println("学生对象s1和s2是不同的");
}
}
从本例可以看出,通过继承而来的equals方法不能按照具体要求测试两个对象是否等价,这就需要在编写特定类时重写该方法,以便符合equals的实际需求。
三、hashCode方法
管理很多对象时,如果采用数组这一类线性表结构,在进行随机查找时效率将非常差,经常需要遍历整个线性表,随着被管对象的增多性能急剧下降。因此希望采取一种高效的管理方式,这时一般会用到哈希存储的方式。
使用哈希时被存储的对象需要提供一个哈希码(hash code),一般是一个整数值。hashCode方法的功能就是用来提供所在对象的额哈希码,根据对象的不同哈希码的值有所不同。一般每定义一个新的类,都要为其重写一个hashCode的方法。
进入哈希存储前,首先调用对象的hashcode方法获取哈希码,定位对象所在的哈希桶。在哈希桶内部,所有的哈希码相同的不同对象是按照线性表的方式存储的。
- 如果管理的对象很多,直接用线性表存储,查找的量非常大,而采用哈希以后,对哈希桶的定位是由计算一步完成的吗,与对象的个数无关,速度很快。
- 在定位了哈希桶之后,只要保证桶里的对象个数不多,进行线性查找也是很快的。
假如有1021个对象,如果在长度为1021的线性表中查找一个特定的对象,需要很长的时间。如果将这1021个对象按照某种排序算法分成1000份放在哈希桶里,则只要先确定要找的对象在哪个桶里,然后在桶里对1000个对象进行先行查找即可,速度提高了1000倍。
那么为什么不让每个对象的哈希码不一样呢?查找效率不是更高吗?是的,查找效率会更高,但是维护数量庞大的哈希桶会占用太多的时间,另外空间利用率也太低。因此,采用了兼顾查找与维护两方面性能的哈希桶策略。
哈希码决定了分离度,而分离度是否合适很重要。太高不好,太低也不好。若分离度太高,如100%分离度,每个对象独自占用一个哈希桶,这样使得桶的数量太多,维护消耗太大;分离度太低也不好,如将所有对象独自占用一个哈希桶,这样并没有达到将其分离,使先行查找次数降低的目的。
其实生活也是如此,例如将图书馆对书籍的管理,图书管理员总是将同一个类的书放在同一个书架上,当寻找书时,先确定在那个书架上然后去书架上找。管理员不可能将所有的书都放在一个书架上,也不可能一个书架上只放一本书。因为分离度太低或太高,要么查找慢,要么维护费用太高。