看一下API中关于Object的介绍:

类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。
所有对象(包括数组)都实现这个类的方法。

那么Object中到底有哪些方法,各自有什么应用呢?
这个问题也经常出现在面试中,如果平时没有关注,可能很难回答好,这里简单整理一下。

首先看一下java.lang.Object的源码:

public class Object {
private static native void registerNatives();
static {
registerNatives();
}
/**
* 创建并返回此对象的副本。
* “复制”的准确含义可能根据对象的不同有变化。
*/
public final native Class<?> getClass(); /**
* 1.在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,
* 前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
* 2.如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
* 3.如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode方法不 要求一定生成不同的整数结果
* 但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
*/
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
} protected native Object clone() throws CloneNotSupportedException; /**
* 返回该对象的字符串表示
*/
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
} public final native void notify();
public final native void notifyAll();
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);
}
/**
* 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
*/
protected void finalize() throws Throwable { }
}

源码的注释非常详细,现在针对这几个方法做分析。

>>hashCode()和equals(Object obj)方法

public native int hashCode();

native关键字表示该方法不是用java实现的,JDK源码中并不包含,对于不同的平台,这部分的实现也是不同的。

Java要实现对底层的控制,就需要其他语言的帮助,JVM将控制调用本地方法的所有细节。

hashCode方法的说明是:

Whenever it is invoked on the same object more than once during an execution of a Java application,the hashCode method must consistently return the same integer.

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

the programmer should be aware that producing distinct integer results
for unequal objects may improve the performance of hash tables.
开发人员应该知道,为不相等的对象产生不同的整数结果可能会提高哈希表的性能。
(这句没理解,再看)

This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java programming language.
hashcode一般是通过将该对象的内部地址转换成一个整数来实现的,不需要使用Java实现。

再来看equals()方法:

public boolean equals(Object obj) {
return (this == obj);
}

java中==运算符作用在基本数据类型和引用数据类型是不同的,
基本数据类型 byte, short, char, int, long, float, double, boolean
他们之间的比较,应用双等号(==),比较的是他们的值。

引用数据类型用(==)进行比较的时候,
比较的是在内存中的存放地址,所以,除非是实例化的同一个对象比较后的结果才为true,否则比较后结果为false。
注意一下,String,Integer,Date这些类重写了equals()方法,不再是比较类在堆内存中的存放地址了。

以String为例:

public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

可以看到String对内部的字符数组进行了逐个字符的判断是否相等,

《Effective JAVA》中认为,99%的情况下,当你覆盖了equals方法后,请务必覆盖hashCode方法。

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

当equals()方法被重写时,通常需要重写 hashCode 方法,以维护在hashCode 方法最开始的声明,即相等对象必须具有相等的哈希码。

1.notify()/notifyAll()和wait()

wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。
而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。

wait(),notify() 和 notifyAll() 可以让线程协调完成一项任务。例如,一个线程生产,另一线程消费。生产线程不能在前一产品被消费之前运行,而应该等待前一个被生产出来的产品被消费之后才被唤醒,进行生产。同理,消费线程也不能在生产线程之前运行,即不能消费不存在的产品,所以应该等待生产线程执行一个之后才执行。利用这些方法,就可以实现这些线程之间的协调。

来看一个例子:

public class WTThread extends Thread{
public WTThread(String name) {
super(name);
} public void run() {
//同步锁
synchronized (this) {
System.out.println(Thread.currentThread().getName()+" call notify()");
/**
* 这个线程执行的过程中会去唤醒当前对象的wait线程
*/
notify();
}
}
}

 主线程的执行方法:

public class UseWaitNotify {

	public static void main(String[] args) throws InterruptedException{
WTThread t1=new WTThread("t1");
//同步锁
synchronized(t1) {
//启动线程t1
System.out.println(Thread.currentThread().getName()+" start t1");
t1.start(); /**
* 主线程进入等待状态
* 同时wait()释放主线程持有的同步锁
*/
System.out.println(Thread.currentThread().getName()+" wait()");
t1.wait();
/**
* 主线程等待后,释放了锁,t1线程就可以执行了
* 于是会操作 下面的执行体
* System.out.println(Thread.currentThread().getName()+" call notify()");
* notify();
*/
/**
* t1执行完毕后,唤醒主线程,主线程持有锁,继续执行
* 打印查看目前正在执行的线程
*/
System.out.println(Thread.currentThread().getName()+" continue");
}
}
}

  控制台输出:

main start t1
main wait()
t1 call notify()
main continue

这段代码来自这篇文章,Java多线程系列--“基础篇”05之 线程等待与唤醒

这几个方法也都是native的,是调用的系统底层方法实现。

2.不同的wait()方法有什么区别

查看源码可以发现这里有三个不同wait方法:

public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {}
public final void wait() throws InterruptedException {
wait(0);
}

没有参数的 wait() 方法被调用之后,线程就会一直处于等待状态,直到本对象(就是 wait() 被调用的那个对象)调用 notify() 或 notifyAll() 方法。
相应的,wait(long timeout) 和wait(long timeout, int nanos) 方法中,
当等待时间结束或者被唤醒(无论哪一个先发生)时将会结束等待。

3.finalize()方法

/**
* Called by the garbage collector on an object when garbage collection
* determines that there are no more references to the object.
*/
protected void finalize() throws Throwable { }

可以看到这个方法是protected的。

特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。
使用finalize还需要注意一个事,调用super.finalize();
一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题。
一般来说,不推荐使用finalize()方法,它跟析构函数不一样。

4.getClass()方法

/**
* Returns the runtime class of this Object.
* The returned Class object is the object that is locked by
* "static""synchronized" methods of the represented class.
*/
public final native Class<?> getClass();

返回这个Object对象的运行时类。

5.clone()方法

clone方法就是复制对象。所谓的复制对象,就是要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。
这里涉及到浅拷贝和深拷贝的关系:

Person p = new Person(23, "zhang");
Person p1 = p;

这段代码中,P和P1其实是引用,指向同一个对象。

Person p = new Person(23, "zhang");
Person p1 = (Person) p.clone();

但是这段代码是创建了两个相同的对象,P和P1的引用分别指向不同的对象,

但是Clone执行的方法是浅拷贝,需要注意这个,P和P1里的name字段指向的是同一块堆内存。

具体的可以查看这篇文章:
详解Java中的clone方法

6.toString()方法

返回对象表示的字符串,实际上我们应用的都是对这个类的重写。

对Object类中方法的深入理解的更多相关文章

  1. Object类中方法详解

    目录 概述 hashCode方法 getClass方法 toString方法 equals方法 clone方法 finalize方法 概述 Object 是类层次结构的根类.每个类都使用 Object ...

  2. Object类clone方法的自我理解

    网上搜帖: clone()是java.lang.Object类的protected方法,实现clone方法: 1)类自身需要实现Cloneable接口 2)需重写clone()方法,最好设置修饰符mo ...

  3. Java:面向对象(继承,方法的重写(overide),super,object类及object类中方法的重写,父子类代码块执行顺序)

    继承: 1.继承是对某一匹类的抽象,从而实现对现实世界更好的建模. 2.提高代码的复用性. 3.extends(扩展),子类是父类的扩展. 4.子类继承父类可以得到父类的全部属性和方法.(除了父类的构 ...

  4. java Object类中方法介绍

  5. 【Java基础之Object类(一)】Java中Object类中的所有方法(toString、equals、hashCode、clone、finalize、wait和notify等)详解(转载)

    java中的hashcode.equals和toString方法都是基类Object的方法. 首先说说toString方法,简单的总结了下API说明就是:返回该对象的字符串表示,信息应该是简明但易于读 ...

  6. Object类中wait代餐方法和notifyAll方法和线程间通信

    Object类中wait代餐方法和notifyAll方法 package com.yang.Test.ThreadStudy; import lombok.SneakyThrows; /** * 进入 ...

  7. 重写Object类中的equals方法

    Object是所有类的父亲,这个类有很多方法,我们都可以直接调用,但有些方法并不适合,例如下面的student类 public class Student { //姓名.学号.年纪 private S ...

  8. Java基础(43):Java中的Object类与其方法(转)

    Object类 java.lang.Object java.lang包在使用的时候无需显示导入,编译时由编译器自动导入. Object类是类层次结构的根,Java中所有的类从根本上都继承自这个类. O ...

  9. -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中

     本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁  sleep()和wait()方法的区别 为什么wait( ...

随机推荐

  1. HTML5 localStorage 的使用

      在前端开发中,我们会常遇到要在两个甚至多个html之间通信,我们可以在url中添加参数,但是当要传递的数据量较大较多时呢,不妨试试html5 的localStorage吧. 1) 检测你的浏览器是 ...

  2. Delphi 中的 procedure of object

    转载:http://www.cnblogs.com/ywangzi/archive/2012/08/28/2659811.html 总结:TMyEvent = procedure of object; ...

  3. [CQOI2011]动态逆序对

    (又是一道树套树……自己真是玩疯了……) (题意略) 从网上也看过题解,好像解法很多……比如CDQ+树状数组,树状数组套主席树,树状数组套平衡树……我用的是树状数组套splay. (我会说是因为我不会 ...

  4. 微博地址url(id)与mid的相互转换 Java版

    原理: 新浪微博的URL都是如:http://weibo.com/2480531040/z8ElgBLeQ这样三部分. 第一部分(绿色部分)为新浪微博的域名,第二部分(红色部分)为博主Uid,第三部分 ...

  5. Github GUI 托管代码教程

    附录:克隆仓库到本地:git clone https://github.com/chzeze/WeiboHomeCrawl.git

  6. Bloom Filter 概念和原理

    Bloom filter 是由 Howard Bloom 在 1970 年提出的二进制向量数据结构,它具有很好的空间和时间效率,被用来检测一个元素是不是集合中的一个成员.如果检测结果为是,该元素不一定 ...

  7. SharePoint更改密码

    stsadm –o updatefarmcredentials –userlogin DomainName\UserName -password NewPassword –local  1. 通过管理 ...

  8. Python之socket简介

    http://goodcandle.cnblogs.com/archive/2005/12/10/294652.aspx http://yangrong.blog.51cto.com/6945369/ ...

  9. Python中用format函数格式化字符串的用法

    这篇文章主要介绍了Python中用format函数格式化字符串的用法,格式化字符串是Python学习当中的基础知识,本文主要针对Python2.7.x版本,需要的朋友可以参考下   自python2. ...

  10. linux学习之一些琐碎知识点

    一.python 问:django中project和app之间到底有什么不同? 答:他们的区别就是一个是配置,另一个是代码. 一个project包含很多个django app以及对它们的配置.技术上, ...