Java常用类--Object详解

在Java中,Object类位于继承层次的顶层,所有Java类都直接或间接继承Object类,如果一个类声明时没有包含extends关键字,那么这个类就直接继承Object类。

Object类有一下主要的成员方法:

public的有:

1.getClass方法

/**
* {@code Number n = 0;                             }
* {@code Class<? extends Number> c = n.getClass(); }
* 
* @return The {@code Class} object that represents the runtime
*/
public final native Class<?> getClass();

getClass方法返回该对象的运行时类的java.lang.Class对象,该方法被native修饰,是一个本地方法,所谓本地方法就是一个java调用非java代码的接口,该方法的实现由非java语言实现,比如C。这种方法并不提供方法体,因为其实现是由非java语言在外面实现的。而且该方法被final修饰,不能被重写。

该方法经常用于在反射中,例如:

Type type = this.getClass().getGenericSuperclass();
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
Class<T> clazz = (Class) types[0];
Field[] fields = clazz.getDeclaredFields();

2.hashCode方法

public native int hashCode();

该方法也是一个本地方法,但是可以被子类重写,用于返回对象的哈希码。
重写该方法有一些通用的约定,下面是约定的内容,摘自Object的规范[JavaSE6]:

  • 在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须一致地返回同一个整数。在一个应用程序的多次执行中,每次执行所返回的整数可以不一致。

  • 如果两个对象根据equals方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。

  • 如果两个对象根据equals方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果。但是给不相等的对象产生截然不同的整数结果有可能提高散列表(hash table)的性能。

在每个重写了equals方法的类中,也必须重写hashCode方法,如果不这样做,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常工作,这样的集合有HashMap、HashSet和HashTable。

String类重写hashCode方法的例子:

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

3.equals方法

比较两个对象是否相等。仅当被比较的两个引用变量指向同一对象时,equals方法才返回true。

如果子类有自己的逻辑相等,而不是比较两个对象是否是同一个时,就需要重写equals方法,在重写equals方法时,有一些通用约定,这些约定来自于Object的规范[JavaSE6]:

  • 自反性。对于任何非null的引用值x,x.equals(x)必须返回true。

  • 对称性。对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。

  • 传递性。对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true。

  • 一致性。对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会返回一致的结果。

  • 对于任何非null的引用值x,x.equals(null)必须返回false。

实现高质量equals方法的诀窍:

  1. 使用==操作符检查“参数是否为这个对象的引用”。如果是,则返回true。这只不过是一种性能优化,如果比较操作有可能很昂贵,就值得这么做。

  2. 使用instanceof操作符检查”参数是否为正确类型”。

  3. 把参数转换成正确的类型。

  4. 对于该类中的每一个关键域,检查参数中的域是否与该对象中对应的域相匹配。域的比较顺序可能会影响到equals方法的性能,为了获得最佳的性能,应该最先比较最有可能不一致的域,或者是开销最低的域,最理想的情况是两个条件同时满足的域。

  5. 编写单元测试检验equals方法是否满足对称性、传递性和一致性。

    例子:

public class Toy {

    private int number;
    private String name;
    private double price;
    private double weigth;
    private Date createDate;

    public int getNumber() {
        return number;
    }
    public void setNumber(int number) {
        this.number = number;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public double getWeigth() {
        return weigth;
    }
    public void setWeigth(double weigth) {
        this.weigth = weigth;
    }

    public Date getCreateDate() {
        return createDate;
    }
    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }

        if (!(obj instanceof Toy)) {
            return false;
        }
        Toy toy = (Toy) obj;
        return toy.price == this.price && toy.name.equals(this.name) ;
    }
}

4.toString方法

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

该方法返回当前对象的字符串表示,格式为“类名@对象的十六进制哈行码”。通常建议覆盖该方法,使其返回带有对象中包含的值得关注的信息,这样也方便测试。

toString方法来自于Object的规范[JavaSE6]的通用约定:

  • 被放回的字符串是一个简洁的,但信息丰富,并且易于阅读的表达形式。

在实际应用中,toString方法应该返回对象中包含的所有值得关注的信息。如果对象太大或者对象中包含的状态信息难以用字符串来表达,那么就应该返回一个摘要信息。

例如:

@Override
    public String toString() {
        return "Toy [number=" + number + ", name=" + name + ", price=" + price + ", weigth=" + weigth + ", createDate=" + createDate + "]";
    }

接下来的这几个public的方法都是不可被重写的方法,而且与多线程有关。

5.notify方法

public final native void notify();

作用:从等待池中唤醒一个线程,把它转移到锁池。

6.notifyAll方法

public final native void notifyAll();

作用:从等待池中唤醒所有的线程,把它们转移到锁池。

7.wait方法

wait方法有多个重载方法。

public final native void wait(long timeout) throws InterruptedException;

public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
            timeout++;
        }

        wait(timeout);
    }
public final void wait() throws InterruptedException {
        wait(0);
    }
  • wait(long timeout)方法:使当前的线程进入等待,直到其他线程调用此对象的notify() 方法或 notifyAll()
    方法,或者超过指定的时间量唤醒它。

  • wait(long timeout, int nanos)方法:使当前的线程进入等待,直到其他线程调用此对象的notify() 方法或 notifyAll() 方法,或者超过指定的时间量唤醒它,相对于一个参数的wait方法,该方法提供更好的时间控制。参数timeout的单位为毫秒, 参数nanos 的单位为纳秒。

  • wait()方法:使当前的线程进入等待,直到其他线程调用此对象的notify()方法或notifyAll()方法唤醒它。

protected的方法:

8.clone方法

protected native Object clone() throws CloneNotSupportedException;

clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象。所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。

在Java中有Cloneable接口,它表明这样的对象允许被克隆,这个接口中没有任何方法,它是用来决定Object中protected的clone方法实现的行为:如果一个类实现了Cloneable接口,Object中protected的clone方法就返回该对象的逐域拷贝,否则就会抛出CloneNotSupportedException异常。

clone方法提供了另外一种创建对象的机制:无需调用构造器就可以创建对象。

这与用new关键字创建对象的区别在于:

用new创建对象时, 首先去看new操作符后面的类型以确定要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕, 可以把该对象的引用发布到外部。

clone在第一步是和new相似的, 都是分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

克隆又分浅拷贝跟深拷贝:当被克隆的对象中存在不是基本数据类型的成员变量时,浅拷贝是将被克隆对象的成员变量的引用拷贝给新对象,所有虽然克隆出来的两个对象的引用不相等,但是对象中成员变量的引用地址是相等的。深克隆的做法是将被克隆对象中的成员变量也进行克隆,把该实例赋给新对象的成员变量,所以深拷贝出来的两个对象不止其引用不同,其成员变量的引用也不相等。值得注意的是Object中clone方法是浅拷贝。

有关于clone方法的详细解析请阅读:http://blog.csdn.net/zhangjg_blog/article/details/18369201/

9.finalize方法

protected void finalize() throws Throwable { }

对于一个已经不被任何引用变量引用的对象,当垃圾回收器装备回收该对象所占有的内存空间时,将自动调用该对象的finalize方法。

在Java中,有垃圾回收器来负责释放那些经由new分配的内存,但是也有特殊情况:假定你的对象(并非用new创建)获得一块“特殊”的内存区域,垃圾回收器并不能对该对象进行正确的回收。finalize方法可以应对这种情况,一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存。所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除或清扫工作。

前面介绍过本地方法是一种Java中调用非Java代码的方式,所以本地方法里可能会出现不经由new而创建的对象(不一样的分配存储空间的方式),所以该部分的存储空间将不会被垃圾回收器释放,此时就需要用到finalize方法来编写代码释放该部分存储空间。

finalize方法的缺点是在于不能保证会被及时地执行。从一个对象变得不可到达开始到它的finalize方法被执行,所花费的这段时间是任意长。这意味着,注重时间的任务不应该由finalize方法来完成。而且使用finalize方法有一个严重的性能损失。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值