Object类是所有java类的父类。

用户定义了如下一个Person类

public class Person{}

在类定义中并没有明确继承Object类,但是编译器会自动的完成这个过程。

既然所有类都继承自Object,那么它所具有的方法一定很重要。接下来就看看Object所具有的一些方法。

  1. public class Object {
  2. public final native Class<?> getClass();
  3. public native int hashCode();
  4. public boolean equals(Object obj) {
  5. return (this == obj);
  6. }
  7. protected native Object clone() throws CloneNotSupportedException;
  8. public String toString() {
  9. return getClass().getName() + "@" + Integer.toHexString(hashCode());
  10. }
  11. public final native void notify();
  12. public final native void notifyAll();
  13. public final native void wait(long timeout) throws InterruptedException;
  14. public final void wait(long timeout, int nanos) throws InterruptedException {
  15. if (timeout < 0) {
  16. throw new IllegalArgumentException("timeout value is negative");
  17. }
  18. if (nanos < 0 || nanos > 999999) {
  19. throw new IllegalArgumentException(
  20. "nanosecond timeout value out of range");
  21. }
  22. if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
  23. timeout++;
  24. }
  25. wait(timeout);
  26. }
  27. public final void wait() throws InterruptedException {
  28. wait(0);
  29. }
  30. }

Object类定义

当前主要关注hashCode、equals这两个方法。其它的后面涉及到相关内容的时候再做总结。

1、hashCode()方法总结

默认行为:

从定义我们看出,它是一个native方法,也就是它的具体实现不在java中,而是在操作系统的c/c++中。默认的hashCode方法会利用对象的地址来计算hashcode值,也就是说,不同对象的hashcode值是不一样的(即便是对象类型相同、属性值完全相同)。

hashCode方法应该满足的基本原则:

①、java应用的同一次执行过程中,在对象上 equals 比较中所用的信息没有被修改的前提下,多次调用相同对象的hashCode()必须得到相同的hashCode。上一次应用执行与下一次应用执行中的产生的hashCode值不要求保持一致。

②、如果obj1.equals(obj2)判定两个对象相等,那么obj1.hashCode()必须等于obj2.hashCode()。

③、如果obj1.equals(obj2)判定两个对象不相等,那么obj1.hashCode()与obj2.hashCode()的值可以相等,也可以不相等。当然,程序员应该注意到不相等的对象产生不相等的hashCode会提升hash表的性能(比如HashMap中使用到的)。

2、equals()方法

默认行为:

  1. public boolean equals(Object obj) {
  2. return (this == obj);
  3. }

可以看出Object类中的equals方法与“==”是等价的,也就是说判断对象的地址是否相等。也就是说,Object类中的equals方法进行的是基于内存地址的比较,而不是基于内容的比较。

默认行为不符合编程的需要,所以在自定义类中需要重写equals方法,使得其基于内容来比较。

当然,这也告诉我们这样一件事情,判断对象的不同引用是否指向同一个对象有两种方法:①使用“==”;②调用超类的equls方法(只能是子类的内部)。

tips:

有一个问题值得注意:如果在类的外部(比如main方法中),能否通过一个对象调用已经被重写过的父类方法??

如果不是类内部,而是外部调用,比如你例子中的main方法,答案是 
不能。你不能调用已经被覆盖掉的父类的方法。 
这也是覆盖override的最初设计意图之一。 
大多数时候,覆盖父类意味着子类想做些特殊的处理。如果能够跳过子类的特殊处理,就会打开一个无法控制的缺口,会导致很多很多问题。 
唯一可以调用父类方法的地方,就只有类内部。子类自己控制,什么时候该调用父类,什么时候做自己的处理。

在Java规范中,equals 方法在非空对象引用上实现相等关系,需要遵循以下几个原则:

①、自反性:对于任何的非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。

④、一致性:对于任何非空引用值 x 和 y,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false。

⑤、对于任何非空引用值 x,x.equals(null)应该返回false。

注意:一般来讲当重写equals方法以后都需要重写hashCode方法,使得相同的对象必须有相同的hashcode值(相同的hashcode值不一定是相同的对象)

在java中进行比较,我们需要根据比较的类型来选择合适的比较方式

  1、对象域,使用equals方法。自定义类一般需要重写此方法。

  2、类型安全的枚举,使用equals或== 。

  3、可能为null的对象域 : 使用 ==  或 equals 。( 比如:if(obj != null && obj.equels(o)){//...} )

  4、数组域:使用Arrays.equals。

  5、所有原始数据类型(非包装类型): 使用== 。

  6、除了Float和Double外的包装类型,使用 == 或 equals。

  7、Float包装类型,使用equals。(实际上,equals底层使用Float.foatToIntBits转换成int类型,然后使用== )。

  8、Double包装类型:使用equals。(实际上,equals底层使用Double.doubleToLongBit转换成long类型,然后使用==)。

至于7)、8)为什么需要进行转换,我们可以参考他们相应封装类的equals()方法,下面的是Float类的:

  1. public boolean equals(Object obj) {
  2.   return (obj instanceof Float)
  3.     && (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
  4. }

下面是一组测试代码:

  1. public static void main(String[] args){
  2. System.out.println("\n-------int---------");
  3. Integer I1 = 10, I2 = 10;
  4. int i3 = 10;
  5. System.out.println("I1 == I2: " + (I1 == I2));
  6. System.out.println("I1 == i3: " + (I1 == i3));
  7.  
  8. System.out.println("\n-------float---------");
  9. Float F1 = 2f, F2 = 2f;
  10. System.out.println("F1 == F2: " + (F1==F2));
  11. System.out.println("F1.equals(F2): " + F1.equals(F2));
  12.  
  13. float f3 = 2f, f4 = 2f;
  14. System.out.println("f3 == f4: " + (f3 == f4));
  15. System.out.println("F1 == f3: " + (F1 == f3));
  16.  
  17. System.out.println("\n-------double---------");
  18. Double D1 = 12.5, D2 = 12.5;
  19. System.out.println("D1 == D2:" + (D1==D2));
  20. System.out.println("D1.equals(D2): " + D1.equals(D2));
  21.  
  22. double d3 = 12.5, d4 = 12.5;
  23. System.out.println("d3 == d4: " + (d3==d4));
  24. System.out.println("D1 == d3: " + (D1 == d3));
  25. }

运行结果:

3、Object对象的两大方法(hashCode-equals)总结的更多相关文章

  1. JSON对象的两个方法

    JSON对象有两个方法,stringify()和parse(). 最简单的方法,这两个方法分别用于吧JavaScript对象序列化为JSON字符串和把JSON字符串解析为原生JavaScript值. ...

  2. 读取xml文件转成List<T>对象的两种方法(附源码)

    读取xml文件转成List<T>对象的两种方法(附源码) 读取xml文件,是项目中经常要用到的,所以就总结一下,最近项目中用到的读取xml文件并且转成List<T>对象的方法, ...

  3. 取xml文件转成List<T>对象的两种方法

    读取xml文件转成List<T>对象的两种方法(附源码)   读取xml文件转成List<T>对象的两种方法(附源码) 读取xml文件,是项目中经常要用到的,所以就总结一下,最 ...

  4. Android中Intent传递对象的两种方法(Serializable,Parcelable)

    今天要给大家讲一下Android中 Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是 Bundle.putP ...

  5. 在Delphi中使用C++对象(两种方法,但都要改造C++提供的DLL)

    Delphi是市场上最好的RAD工具,但是现在C++占据着主导地位,有时针对一个问题很难找到Delphi或Pascal的解决方案.可是却可能找到了一个相关的C++类.本文描述几种在Delphi代码中使 ...

  6. Intent传递对象的两种方法(Serializable,Parcelable) (转)

    今天讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是Bundle.putParcela ...

  7. [转]Android中Intent传递对象的两种方法(Serializable,Parcelable)

    http://blog.csdn.net/xyz_lmn/article/details/5908355 今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种 ...

  8. Android高手进阶教程(十七)之---Android中Intent传递对象的两种方法(Serializable,Parcelable)!

    [转][原文] 大家好,好久不见,今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object); ...

  9. Intent传递对象的两种方法

    Android为intent提供了两种传递对象参数类型的方法 分别需要使实体类实现Serializable接口.Parcelable接口 首先我们要知道,传递对象,需要先将对象序列化 一.那么为什么要 ...

随机推荐

  1. Abstract Class与 Interface 的区别

    表格                                                                                               Abs ...

  2. 添加swap分区

    1.创建swap文件,可以单独划分一个分区出来,也可以直接生成一个swap文件 dd if=/dev/zero of=swap bs=1M count=1024 2.格式化为swap文件 mkswap ...

  3. (转载)HTML:模拟链接被按下,在新标签页打开页面,不使用window.open(可能被拦截)

    原文: http://www.cppblog.com/biao/archive/2010/08/21/124196.html 当按下一个按钮时,想打开一个新的标签页,可以使用window.open去实 ...

  4. android开发 根据Uri获取真实路径

    Uri uri = data.getData(); String[] proj = { MediaStore.Images.Media.DATA }; Cursor actualimagecursor ...

  5. 13、主线程任务太多导致异常退出(The application may be doing too much work on its main thread)

    今天花费了一天的时间来解决这个bug. 这种在程序运行期间出现的问题比较棘手,如果再没有规律的话就更难解决. 还好这个bug是由规律的,也就是说在程序执行半个小时左右后就会因为此异常而导致程序退出:那 ...

  6. 网页数据采集 - 系列之Flash数据采集

    经常看到一些朋友在讨论如何采集flash中的数据,讨论来讨论区,结论就是:flash不能采集,其实也不总是这样.本篇就跟大家分享如何采集flash中的数据. 在开始之前,先说明一下:一般来说flash ...

  7. 《我是一只IT小小鸟》阅读笔记

    <我是一只IT小小鸟>,这本书对我来说,有可能我现在并不懂得那其中的道理,但是,我觉得它写的很好,很现在的我很相似,但是在里面,我看到了他们都在说,一开始可能并不对IT这门课有很深的见解, ...

  8. JS 学习笔记--8---Function类型

    练习使用的浏览器IE11   JS 中Function类型实际上是一种对象,每一个函数实际上都是Function类型的一个实例,每一个函数都有一些默认的属性和方法.由于函数是对象,故函数名实际上也是一 ...

  9. ubuntu 安装完成后的工作

    以安装 ubuntu 15.10 为例 1. 备份并更改源 cd /etc/apt sudo cp source.list source.list.bak sudo vi source.list 删除 ...

  10. SQLServer中查询的数字列前面补0返回指定长度的字符串

    SQLServer中查询的数字列前面补0返回指定长度的字符串: 如: 角本如下: /****** Script for SelectTopNRows command from SSMS ******/ ...