Object 通用方法

概览

public final native Class<?> getClass()

public native int hashCode()

public boolean equals(Object obj)

protected native Object clone() throws CloneNotSupportedException

public String toString()

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

public final void wait() throws InterruptedException

protected void finalize() throws Throwable {}

equals()

1. 等价关系

(一)自反性

x.equals(x); // true

(二)对称性

x.equals(y) == y.equals(x); // true

(三)传递性

if (x.equals(y) && y.equals(z))
x.equals(z); // true;

(四)一致性

多次调用 equals() 方法结果不变

x.equals(y) == x.equals(y); // true

(五)与 null 的比较

对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false

x.equals(null); // false;

2. equals() 与 ==

  • 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
  • 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
Integer x = new Integer(1);
Integer y = new Integer(1);
System.out.println(x.equals(y)); // true
System.out.println(x == y); // false

3. 实现

  • 检查是否为同一个对象的引用,如果是直接返回 true;
  • 检查是否是同一个类型,如果不是,直接返回 false;
  • 将 Object 对象进行转型;
  • 判断每个关键域是否相等。
public class EqualExample {
private int x;
private int y;
private int z; public EqualExample(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; EqualExample that = (EqualExample) o; if (x != that.x) return false;
if (y != that.y) return false;
return z == that.z;
}
}

hashCode()

hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。

在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。

下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。

EqualExample e1 = new EqualExample(1, 1, 1);
EqualExample e2 = new EqualExample(1, 1, 1);
System.out.println(e1.equals(e2)); // true
HashSet<EqualExample> set = new HashSet<>();
set.add(e1);
set.add(e2);
System.out.println(set.size()); // 2

理想的散列函数应当具有均匀性,即不相等的对象应当均匀分布到所有可能的散列值上。这就要求了散列函数要把所有域的值都考虑进来,可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。

一个数与 31 相乘可以转换成移位和减法: 31*x == (x<<5)-x,编译器会自动进行这个优化。

@Override
public int hashCode() {
int result = 17;
result = 31 * result + x;
result = 31 * result + y;
result = 31 * result + z;
return result;
}

toString()

默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。

public class ToStringExample {
private int number; public ToStringExample(int number) {
this.number = number;
}
}
ToStringExample example = new ToStringExample(123);
System.out.println(example.toString());
ToStringExample@4554617c

clone()

1. cloneable

clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。

public class CloneExample {
private int a;
private int b;
}
CloneExample e1 = new CloneExample();
// CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'

重写 clone() 得到以下实现:

public class CloneExample {
private int a;
private int b; @Override
protected CloneExample clone() throws CloneNotSupportedException {
return (CloneExample)super.clone();
}
}
CloneExample e1 = new CloneExample();
try {
CloneExample e2 = e1.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
java.lang.CloneNotSupportedException: CloneExample

以上抛出了 CloneNotSupportedException,这是因为 CloneExample 没有实现 Cloneable 接口。

应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。

public class CloneExample implements Cloneable {
private int a;
private int b; @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

2. 浅拷贝

拷贝对象和原始对象的引用类型引用同一个对象。

public class ShallowCloneExample implements Cloneable {
private int[] arr; public ShallowCloneExample() {
arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
} public void set(int index, int value) {
arr[index] = value;
} public int get(int index) {
return arr[index];
} @Override
protected ShallowCloneExample clone() throws CloneNotSupportedException {
return (ShallowCloneExample) super.clone();
}
}
ShallowCloneExample e1 = new ShallowCloneExample();
ShallowCloneExample e2 = null;
try {
e2 = e1.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
e1.set(2, 222);
System.out.println(e2.get(2)); // 222

3. 深拷贝

拷贝对象和原始对象的引用类型引用不同对象。

public class DeepCloneExample implements Cloneable {
private int[] arr; public DeepCloneExample() {
arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
} public void set(int index, int value) {
arr[index] = value;
} public int get(int index) {
return arr[index];
} @Override
protected DeepCloneExample clone() throws CloneNotSupportedException {
DeepCloneExample result = (DeepCloneExample) super.clone();
result.arr = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
result.arr[i] = arr[i];
}
return result;
}
}
DeepCloneExample e1 = new DeepCloneExample();
DeepCloneExample e2 = null;
try {
e2 = e1.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
e1.set(2, 222);
System.out.println(e2.get(2)); // 2

4. clone() 的替代方案

使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。

public class CloneConstructorExample {
private int[] arr; public CloneConstructorExample() {
arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
} public CloneConstructorExample(CloneConstructorExample original) {
arr = new int[original.arr.length];
for (int i = 0; i < original.arr.length; i++) {
arr[i] = original.arr[i];
}
} public void set(int index, int value) {
arr[index] = value;
} public int get(int index) {
return arr[index];
}
}
CloneConstructorExample e1 = new CloneConstructorExample();
CloneConstructorExample e2 = new CloneConstructorExample(e1);
e1.set(2, 222);
System.out.println(e2.get(2)); // 2

Object 通用方法的更多相关文章

  1. java基础 3 Object通用方法(1)

    Object通用方法(1) clone: 浅复制    被复制对象的所有变量都含有与原对象相同的值,而所有对其他对象的引用仍然指向原来的对象,换言之,浅复制仅仅复                   ...

  2. Java基础:(五)Object通用方法

    一.Object对象的九个方法 getClass():hashCode():equals():clone():toString():notify():notifyAll():wait():finali ...

  3. Object类中通用方法之:toString()方法

    1.Java所有的对象都是Object类的实例,都可以直接调用该类中定义的方法,这些方法称为通用方法 2.toString()方法即为Object类中定义的通用方法之一 3.平时我们如果在控制台直接打 ...

  4. C# IComparable接口、IComparer接口和CompareTo(Object x)方法、Compare()方法

    在项目中经常会用到字符串比较,但是有时候对字符串的操作比较多,规则各异.比如有的地方我们需要用排序规则,有的地方需要忽略大小写,我们该如何写一个比较容易操作的比较方法呢?重新实现IComparer接口 ...

  5. DataTable数据赋值给Model通用方法

    注:该文属本人原创,今后项目中发现该方法存在BUG会实时更新,转载记得附上原文出处,方便大家获得最新代码. 相信大家在做项目中,经常会根据不同的表new各种不同的Model,当需要对Model进行实例 ...

  6. hibernate学习笔记4---HQL、通用方法的抽取实现

    一.通用方法的抽取实现 由于hibernate中对增删改查的一切操作都是面向对象的,所以将增删改查抽取成通用方法,以满足不同的表的增删改查操作,简化jdbc代码. 具体例子如下: package cn ...

  7. 使用JsPlumb绘制拓扑图的通用方法

    转自:http://www.it165.net/pro/html/201311/7616.html 使用JsPlumb绘制拓扑图的通用方法 一. 实现目标 绘制拓扑图, 实际上是个数据结构和算法的问题 ...

  8. Java连接MySQL数据库增删改查通用方法

    版权声明:本文为博主原创文章,未经博主允许不得转载. Java连接MySQL数据库增删改查通用方法 运行环境:eclipse+MySQL 以前我们Java连接MySQL数据库都是一个数据库写一个类,类 ...

  9. excel导出导入通用方法

    /** * 方法说明:批量导出通用方法 * 创建时间:2018年8月24日 *** * @param filePath 文件地址 * @param sheetName 分页名称 * @param ti ...

  10. (C#)生成指定长度的随机字符串的通用方法

    .NET(C#)生成指定长度的随机字符串的通用方法,此方法可以指定字符串的长度,是否包含数字,是否包含符号,是否包含小写字母,是否包含大写字母等, 源码: #region 生成指定长度的随机字符串 / ...

随机推荐

  1. 解决未定义的count键“报错为:"Uncaught ReferenceError: count is not defined"

    报错: 源码:Vuex仓库.js let state = {     count } export default state   解决:未赋值的count键

  2. Idea 配置 tomacat

    步骤 1.点击settings 2.创建tomcat 并找到tomcat的目录 添加完成 3.创建Idea项目

  3. iOS自动化测试

    学习步骤: 1.能够搭建iOS自动化测试所需要的环境 2.能够使用模拟器进行iOS自动化测试 3.能够使用真机进行iOS自动化测试 一.环境搭建 应用场景 想要进行iOS自动化测试,前提条件需要进行环 ...

  4. 在CentOS7中安装Redis

    一.检查操作系统中是否安装gcc依赖 [root@192 bin]# yum list installed gcc 如果出现上面图片内容则是已经安装.(由于我是安装了的,所以会存在) 二.安装gcc- ...

  5. Abp Abp.AspNetZeroCore 2.0.0 2.1.1 Path

    纯手工修改,移除校验代码可调试. 将文件复制到 %userprofile%\.nuget\packages\abp.aspnetzerocore 目录中 替换对应的文件 Abp.AspNetZeroC ...

  6. vue 项目页面刷新router-view控制

    vue项目开发过程中,需要在页面提交表单信息之后清空还原,即恢复页面初始状态,第一想法就是对当前页面刷新,重新加载. 想起location.reload()方式和this.$router.go(0)方 ...

  7. NOIP2015普及组

    T1 金币 很简单的题,控制天数这个变量 #include<iostream> #include<cstring> #include<cmath> #include ...

  8. String类型时间与Date时间转换

    1. String类型的时间转为DateTime public static Date transferString2Date(String s) { Date date = new Date(); ...

  9. 关于TIdTCPClient的几种方法

    关于TIdTCPClient的几种方法 收藏  其实Indy比较简单,但是可以提供的方法太多了.我找了很久,才搞明白. 比方说这个读取缓冲区的数据,就有很多种方法.相对于TTcpClient的几种方法 ...

  10. Python使用socks代理

    Python使用socks代理 参考:How to make python Requests work via socks proxy - Stack Overflow 使用pysocks库 - Ji ...