欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java基础教程(19)--Object类

程序员文章站 2022-04-09 18:02:37
Object类是所有类的始祖,如果一个类没有使用extends关键字明确地指出它的父类,那么它就会继承Object类。可以说,所有类都直接或间接地继承了Object类。本文将对Object类中常用的方法进行介绍。 ......

  object类位于类结构树的最顶端,所有的类都是它的直接或间接子类,因此所有的类都继承了object类的方法,我们可以在需要的时候覆盖这些方法。下面是一些将会在本文中讨论的object类的方法:

  • protected object clone() throws clonenotsupportedexception
      创建并返回此对象的副本。
  • public boolean equals(object obj)
      判断某个对象是否与这个对象“相等”。
  • protected void finalize() throws throwable
      当垃圾回收器将对象从内存中清理出去之前要做的清理工作。
  • public final class getclass()
      返回对象所属的类类型。
  • public int hashcode()
      返回对象的hash值。
  • public string tostring()
      返回对象的字符串表示形式。

  下面的notify,notifyall和wait方法在同步独立运行的线程的活动中扮演着不同的角色,本文不会去介绍它们,有关这一部分的内容将会在以后的文章中讨论:

  • public final void notify()
  • public final void notifyall()
  • public final void wait()
  • public final void wait(long timeout)
  • public final void wait(long timeout, int nanos)

一.equals方法

  object了类中的equals方法用于检测一个对象是否等于另外一个对象。在object类中,这个方法将会判断两个对象是否具有相同的引用。如果两个对象具有相同的引用,它们一定是相等的。从这点上看,将其作为默认操作也是合乎情理的。然而,对于大多数类来说,这种判断并没有什么意义。我们在判断两个对象是否相等时,应该比较它们的内容,而不仅仅是判断它们是不是同一个对象。因此,大多数情况下,当我们需要使用equals方法时,都应该对它进行重写。
  为了演示,我们首先编写一个apple类:

public class apple {
    private string color;
    private int weight;
    public void setcolor(string color) {
        this.color = color;
    }
    public string getcolor() {
        return color;
    }
    public void setweight(int weight) {
        this.weight = weight;
    }
    public int getweight() {
        return weight;
    }
}

  当两个苹果的重量和颜色一样时,我们就认为它们是相等的。因此,apple类的equals方法可以这么写:

public boolean equals(object obj) {
    if (obj == null) {
        return false;
    }
    if (this == obj) {
        return true;
    }
    if (this.getclass() != obj.getclass()) {
        return false;
    }
    apple apple = (apple) obj;
    return weight == apple.getweight() && objects.equals(color, apple.getcolor());
}

  为了防备color为null的情况,上面的例子中使用了objects.equals(object a,object b)方法。如果a和b都是null,这个方法将会返回true;如果其中只有一个参数为null,则返回false;如果a和b都不为null,则会返回a.equals(b)的结果。
  实际上,上面的equals还存在一定的问题。不过本文属于基础教程系列,因此不会深入讲解这其中的问题。有兴趣的读者可以查阅java规范中对于equals方法的要求以及参考其他深入讨论equals方法的文章。

二.hashcode方法

  hashcode方法的返回值是根据对象本身所计算出来的散列值(也称哈希值)。如果两个对象是相等的,那么对它们调用hashcode方法得到的返回值也应该是相等的。如果重写了equals方法,那么默认的hashcode方法也不再适用。因此,如果重写了equals方法,则必须同时重写hashcode方法。在重写hashcode方法时,原则上只需要保证两个相等的对象的散列值是相同的即可。不过如何减少冲突以及编写更高效的哈希函数,可以参考其他文章或查阅计算机算法书中关于哈希的内容。下面编写了一个apple类的hashcode方法作为示例:

public int hashcode() {
    return 7 * (color == null ? 0 : color.hashcode()) + 11 * weight;
}

三.clone方法

  如果一个类或它的某个超类实现了cloneable接口,那么就可以使用clone()方法从这个类的实例上创建一个副本。在调用clone()方法时,编译器会检查这个类是否实现了cloneable接口。如果没有,编译器将会抛出一个clonenotsupportedexception异常。有关异常的内容会在后面的文章中介绍,现在你只需要知道要覆盖clone()方法,必须将它声明为:

protected object clone() throws clonenotsupportedexception

public object clone() throws clonenotsupportedexception

  如果调用clone方法的对象实现了cloneable接口,则继承自object类的clone()方法将会创建与原始对象相等的对象,使其具有与原始对象的相应成员变量相同的值。因此,如果想要让类可以clone,只需要将implements cloneable添加到类的声明中即可。
  对于某些类,objects类的clone方法可以正常工作。但是,如果对象包含对外部对象的引用,则可能需要覆盖clone方法。否则,即使克隆的对象与元对象不是一个对象,但它们内部引用的还是相同的对象。这样一来,对内部对象所做的更改也会影响到另一个对象。如果需要克隆出一个完全与原对象隔离的新对象,则需要重写clone方法,将每个内部对象再拷贝一次。

四.finalize方法

  finalize方法用于定义在回收对象前要执行的清理工作。object类的finalize方法什么也没做,只有一个空方法体,可以覆盖finalize方法来定义清理行为,例如释放资源等。finalize方法不需要也不建议手动调用,它会在垃圾回收器回收对象时自动调用。

五.tostring方法

  tostring方法用于返回表示对象值的字符串。为每个类提供tostring方法是一个良好的习惯。
  下面是object类的tostring方法:

public string tostring() {
    return getclass().getname() + "@" + integer.tohexstring(hashcode());
}

  可以看到,object类的tostring方法返回的是类名加对象的hashcode的十六进制表示,中间使用符号@隔开。不过在打印对象的信息时,这个方法的返回值并没有什么意义。因此,建议在编写的每一个类中都覆盖tostring方法。例如为上面的apple类编写tostring方法:

public string tostring() {
    return getclass().getname() + "[color = " + color + ",weight = " + weight + "]";
}

六.getclass方法

  class类是一个表示类的信息的类。对对象调用getclass方法会返回一个class类的实例,用来表示当前对象所属对象的信息。由于getclass方法是final的,因此无法对它进行重写。
  class类提供了非常多的方法,例如获取类名的方法getsimplename(),获取父类的方法geusuperclass(),获取实现的接口的方法getinterfaces()等。例如,下面的方法会打印出对象的类名:

void printclassname(object obj) {
    system.out.println("the object's" + " class is " + obj.getclass().getsimplename());
}

  有关class的内容会在后面有关反射的文章中进行介绍,这里只需要知道getclass方法的作用即可。