本文是我们名为“ 高级Java ”的学院课程的一部分。

本课程旨在帮助您最有效地使用Java。 它讨论了高级主题,包括对象创建,并发,序列化,反射等。 它将指导您完成Java掌握的过程! 在这里查看 !

目录

1.简介 2.方法等于和hashCode 3.方法toString 4.方法克隆 5.方法等于和==运算符 6.有用的助手类 7.下载源代码 8.接下来

1.简介

从本教程的第1部分“ 如何创建和销毁对象”中 ,我们已经知道Java是一种面向对象的语言(但是,不是纯粹的面向对象的语言)。 在Java类层次结构的顶部是Object类,Java中的每个类都隐式地继承自它。 因此,所有类都继承Object类中声明的方法集,最重要的是以下方法:

方法 描述
protected Object clone() 创建并返回此对象的副本。
protected void finalize() 当垃圾回收确定不再有对该对象的引用时,由垃圾回收器在对象上调用。 我们在本教程的第1部分“ 如何创建和销毁对象”中讨论了终结器。
boolean equals(Object obj) 指示其他某个对象是否与此对象“相等”。
int hashCode() 返回对象的哈希码值。
String toString() 返回对象的字符串表示形式。
void notify() 唤醒正在此对象的监视器上等待的单个线程。 我们将在本教程的第9部分 并发最佳实践中讨论此方法。
void notifyAll() 唤醒正在此对象的监视器上等待的所有线程。 我们将在本教程的第9部分 并发最佳实践中讨论此方法。
void wait()

void wait(long timeout)

void wait(long timeout, int nanos)

使当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法。 我们将在本教程的第9部分 并发最佳实践中讨论这些方法。

表格1

在本教程的这一部分中,我们将研究equalshashCodetoStringclone方法,它们的用法以及需要牢记的重要约束。

2.方法等于和hashCode

默认情况下,Java中的任何两个对象引用(或类实例引用)仅在它们引用相同的内存位置(引用相等)时才相等。 但是Java允许类通过重写Object类的equals()方法来定义自己的相等性规则。 听起来像一个强大的概念,但是正确的equals()方法实现应符合一组规则并满足以下约束:

  • 反身的 。 对象x必须等于自身,并且equals(x)必须返回true
  • 对称的 。 如果equals(y)返回true,y.equals(x)也必须返回true
  • 传递的 。 如果equals(y)返回true,y.equals(z)返回true ,则x.equals(z)也必须返回true
  • 一致 。 除非修改用于相等比较的任何属性,否则多次调用equals()方法必须得到相同的值。
  • 等于Nullequals(null)的结果必须始终为false

不幸的是,Java编译器无法在编译过程中强制执行这些约束。 但是,不遵循这些规则可能会导致非常怪异且难以解决问题。 一般建议是这样的:如果您要编写自己的equals()方法实现,请在实际需要时三思而后行。 现在,有了所有这些规则,让我们为Person类编写一个equals()方法的简单实现。

package com.javacodegeeks.advanced.objects;public class Person {private final String firstName;private final String lastName;private final String email;public Person( final String firstName, final String lastName, final String email ) {this.firstName = firstName;this.lastName = lastName;this.email = email;}public String getEmail() {return email;}public String getFirstName() {return firstName;}public String getLastName() {return lastName;}// Step 0: Please add the @Override annotation, it will ensure that your// intention is to change the default implementation.@Overridepublic boolean equals( Object obj ) {// Step 1: Check if the 'obj' is nullif ( obj == null ) {return false;}// Step 2: Check if the 'obj' is pointing to the this instanceif ( this == obj ) {return true;}// Step 3: Check classes equality. Note of caution here: please do not use the // 'instanceof' operator unless class is declared as final. It may cause // an issues within class hierarchies.if ( getClass() != obj.getClass() ) {return false;}// Step 4: Check individual fields equalityfinal Person other = (Person) obj;if ( email == null ) {if ( other.email != null ) {return false;} } else if( !email.equals( other.email ) ) {return false;}if ( firstName == null ) {if ( other.firstName != null ) {return false;} } else if ( !firstName.equals( other.firstName ) ) {return false;}if ( lastName == null ) {if ( other.lastName != null ) {return false;}} else if ( !lastName.equals( other.lastName ) ) {return false;}return true;}
}

并非偶然的是,本节的标题中还包含hashCode()方法。 最后要记住的规则是:每当您重写equals()方法时,也始终要重写hashCode()方法。 如果对于任何两个对象, equals()方法返回true ,则这两个对象中的每个对象的hashCode()方法必须返回相同的整数值(但是相反的语句不那么严格:如果对于任何两个对象, equals()方法返回false ,则这两个对象中的每个对象的hashCode()方法都可能会或可能不会返回相同的整数值)。 让我们看一下Person类的hashCode()方法。

// Please add the @Override annotation, it will ensure that your
// intention is to change the default implementation.
@Override
public int hashCode() {final int prime = 31;int result = 1;result = prime * result + ( ( email == null ) ? 0 : email.hashCode() );result = prime * result + ( ( firstName == null ) ? 0 : firstName.hashCode() );result = prime * result + ( ( lastName == null ) ? 0 : lastName.hashCode() );return result;
}

为了避免意外,请尽可能在实现equals()hashCode()同时尝试使用final字段。 这将确保这些方法的行为不会受到字段更改的影响(但是,在实际项目中,并非总是可能的)。

最后,始终确保在equals()hashCode()方法的实现中使用相同的字段。 如果有任何更改影响所讨论的字段,它将保证两种方法的行为一致。

3.方法toString

toString()可能是其他方法中最有趣的方法,并且被更频繁地覆盖。 它的目的是提供对象(类实例)的字符串表示形式。 正确编写的toString()方法可以大大简化实际系统中问题的调试和故障排除。

默认的toString()实现在大多数情况下不是很有用,只是返回完整的类名和对象哈希码,以@ ,fe分隔:

com.javacodegeeks.advanced.objects.Person@6104e2ee

让我们尝试改善实现,并为我们的Person类示例重写toString()方法。 这是使toString()更有用的一种方法。

// Please add the @Override annotation, it will ensure that your
// intention is to change the default implementation.
@Override
public String toString() {return String.format( "%s[email=%s, first name=%s, last name=%s]", getClass().getSimpleName(), email, firstName, lastName );
}

现在, toString()方法提供了Person类实例的字符串版本,包括其所有字段。 例如,在执行以下代码片段时:

final Person person = new Person( "John", "Smith", "john.smith@domain.com" );
System.out.println( person.toString() );

以下输出将在控制台中打印出来:

Person[email=john.smith@domain.com, first name=John, last name=Smith]

不幸的是,标准Java库对简化toString()方法实现的支持有限,尤其是,最有用的方法是Objects.toString()Arrays.toString() / Arrays.deepToString() 。 让我们看一下Office类及其可能的toString()实现。

package com.javacodegeeks.advanced.objects;import java.util.Arrays;public class Office {private Person[] persons;public Office( Person ... persons ) {this.persons = Arrays.copyOf( persons, persons.length );}@Overridepublic String toString() {return String.format( "%s{persons=%s}", getClass().getSimpleName(), Arrays.toString( persons ) );}public Person[] getPersons() {return persons;}
}

以下输出将在控制台中打印出来(如我们所见, Person类实例也已正确转换为字符串):

Office{persons=[Person[email=john.smith@domain.com, first name=John, last name=Smith]]}

Java社区已经开发了两个非常全面的库,这些库在很大程度上toString()实现的工作。 其中包括Google Guava's Objects.toStringHelper和Apache Commons Lang ToStringBuilder 。

4.方法克隆

如果Java中有一种声誉不佳的方法,则肯定是clone() 。 它的目的很明确–返回正在调用的类实例的确切副本,但是有很多原因使它不像听起来那么容易。

首先,如果您决定实现自己的clone()方法,则可以遵循Java文档中规定的许多约定。 其次,该方法在Object类中声明为protected ,因此为了使其可见,应使用重写类本身的返回类型将其重写为public 。 第三,重写的类应实现Cloneable接口(这只是一个没有定义方法的标记或mixin接口),否则将引发CloneNotSupportedException异常。 最后,实现应首先调用super.clone() ,然后在需要时执行其他操作。 让我们看看如何为我们的示例Person类实现它。

public class Person implements Cloneable {// Please add the @Override annotation, it will ensure that your// intention is to change the default implementation.@Overridepublic Person clone() throws CloneNotSupportedException {return ( Person )super.clone();}
}

该实现看起来非常简单明了,那么这里可能出什么毛病? 几件事情,实际上。 在执行类实例的克隆时,不会调用任何类构造函数。 这种行为的结果是可能会出现意外的数据共享。 让我们考虑上一节介绍的Office类的以下示例:

package com.javacodegeeks.advanced.objects;import java.util.Arrays;public class Office implements Cloneable {private Person[] persons;public Office( Person ... persons ) {this.persons = Arrays.copyOf( persons, persons.length );}@Overridepublic Office clone() throws CloneNotSupportedException {return ( Office )super.clone();}public Person[] getPersons() {return persons;}
}

在此实现中, Office类实例的所有克隆都将共享同一个人数组,这不太可能实现所需的行为。 为了使clone()实现能够做正确的事情,应该做一些工作。

@Override
public Office clone() throws CloneNotSupportedException {final Office clone = ( Office )super.clone();clone.persons = persons.clone();return clone;
}

现在看起来更好,但是即使此实现也非常脆弱,因为将人员字段定为final将导致相同的数据共享问题(因为不能重新分配final )。

总的来说,如果您想精确复制类,最好避免使用clone() / Cloneable并使用更简单的替代方法(例如,复制构造函数,具有C ++背景的开发人员熟悉的概念或工厂)方法,这是我们在本教程的第1部分“ 如何创建和销毁对象”中讨论的一种有用的构造模式。

5.方法等于和==运算符

Java ==运算符和equals()方法之间存在有趣的关系,这会引起很多问题和混乱。 在大多数情况下(比较原始类型除外), ==运算符执行引用相等:如果两个引用都指向同一个对象,则返回true,否则返回false 。 让我们看一个说明差异的简单示例:

final String str1 = new String( "bbb" );
System.out.println( "Using == operator: " + ( str1 == "bbb" ) );
System.out.println( "Using equals() method: " + str1.equals( "bbb" ) );

从人类的角度来看,str1 ==“ bbb”和str1.equals(“ bbb”)之间没有区别:在两种情况下,结果都应该相同,因为str1只是对“ bbb”字符串的引用。 但是在Java中并非如此:

Using == operator: false
Using equals() method: true

即使两个字符串看起来完全相同,在此特定示例中,它们也作为两个不同的字符串实例存在。 根据经验,如果您处理对象引用,请始终使用equals()Objects.equals() (请参阅下一部分有用的帮助程序类以获取更多详细信息)进行相等性比较,除非您确实有比较的意图如果对象引用指向同一实例。

6.有用的助手类

自Java 7发行以来,标准Java库附带了几个非常有用的帮助程序类。 其中之一是Objects类。 特别是,以下三种方法可以大大简化您自己的equals()hashCode()方法的实现。

方法 描述
static boolean equals(Object a, Object b) 如果参数彼此相等,则返回true;否则返回false
static int hash(Object... values) 为一系列输入值生成哈希码。
static int hashCode(Object o) 返回非空参数的哈希码,对于空参数返回0。

表2

如果我们使用这些帮助器方法为Person的类示例重写equals()hashCode()方法,则代码量将大大减少,并且代码的可读性也将大大提高。

@Override
public boolean equals( Object obj ) {if ( obj == null ) {return false;}if ( this == obj ) {return true;}if ( getClass() != obj.getClass() ) {return false;}final PersonObjects other = (PersonObjects) obj;if( !Objects.equals( email, other.email ) ) {return false;} else if( !Objects.equals( firstName, other.firstName ) ) {return false;            } else if( !Objects.equals( lastName, other.lastName ) ) {return false;            }return true;
}@Override
public int hashCode() {return Objects.hash( email, firstName, lastName );
}

7.下载源代码

  • 您可以在此处下载源代码: advanced-java-part-2

8.接下来

在本节中,我们介绍了Object类,它是Java中面向对象编程的基础。 我们已经看到了每个类如何覆盖从Object类继承的方法并强加其自己的相等性规则。 在下一节中,我们将切换编码方式,并讨论如何正确设计类和接口。

翻译自: https://www.javacodegeeks.com/2015/09/using-methods-common-to-all-objects.html

使用所有对象通用的方法相关推荐

  1. java通用对象_有效的Java –所有对象通用的方法

    java通用对象 所有对象共有的方法(第3章) 这是Joshua Blochs的有效Java第3章的简短摘要.我仅包含与自己相关的项目. 一般 等值合约将等价关系描述为: x.equals(null) ...

  2. 有效的Java –所有对象通用的方法

    所有对象共有的方法(第3章) 这是Joshua Blochs的< 有效的Java>第3章的简短摘要.我仅包括与自己相关的项目. 一般 等值合约将等价关系描述为: x.equals(null ...

  3. Effective Java:对于全部对象都通用的方法

    前言: 读这本书第1条规则的时候就感觉到这是一本非常好的书.可以把我们的Java功底提升一个档次,我还是比較推荐的.这里我主要就关于覆盖equals.hashCode和toString方法来做一个笔记 ...

  4. Effective java -- 2 对于所有对象都通用到方法

    第八条:覆盖equals时请遵守通用约定 什么时候需要覆盖equals方法?类具有自己的逻辑相等概念,并且父类的equals方法不能满足需要. 重写equals时需要遵循一下约定: 自反性:非null ...

  5. Effective Java:对于所有对象都通用的方法

    前言: 读这本书第1条规则的时候就感觉到这是一本很好的书,可以把我们的Java功底提升一个档次,我还是比较推荐的.这里我主要就关于覆盖equals.hashCode和toString方法来做一个笔记总 ...

  6. html是以一种通用的方法来,c++ 有一种通用的方法来使函数模板适应为多态函数对象吗?...

    我有一些功能模板,例如 template void foo(T); template void bar(T); // others 我需要将每一个传递给一种算法,它将被称为各种类型的算法. templ ...

  7. html是一种通用的方法来,()是以一种完全通用的方法来设计函数或类而不必预先说明将被使用的每个对象的类型。A.模板B.类C....

    ()是以一种完全通用的方法来设计函数或类而不必预先说明将被使用的每个对象的类型.A.模板B.类C. 更多相关问题 394.方案设计功能下可以设置的项目不包括 (). A limitation of p ...

  8. 打印对象和toString方法

    JAVA对象 java对象是都是Object类的实例,都可直接调用该类中定义的方法,这些方法提供了处理java对象的通用方法. > > 6.2.1打印对象和toString方法     先 ...

  9. axios框架里面如何使用get,post,通用ajax方法请求。

    回到文章总目录 本篇文章介绍的内容为axios框架里面如何使用get,post,通用ajax方法请求. axios是目前前端ajax中最热门的工具库,是vue和react官方推荐的ajax工具包 作用 ...

最新文章

  1. Nginx配置文件nginx.conf中文详解(总结)
  2. 《JavaScript面向对象编程指南》——1.3 分析现状
  3. 6月Top 20榜单出炉啦! 万万没想到区块链大佬竟在忙这个...
  4. python控制树莓派led_Python 控制树莓派 GPIO 输出:控制 LED 灯
  5. linux组群账户存放在,linux用户和群组
  6. C/C++中调用api设置mysql连接的编码方式
  7. SQLite的基本使用一
  8. js-权威指南学习笔记7
  9. 忍“乳”负重,身材好的女孩子究竟有多不容易?我从科学的角度算出来了……...
  10. 识别产品外观的合格软件_你还在犹豫?外观检测设备使用已成主流!
  11. 利用iperf进行WiFi吞吐量的测试方法
  12. oracle视图无法使用rowid,请问:无法从没有键值保存表的连接视图中选择 ROWID 这个是什么原因啊?...
  13. aws rds监控慢sql_使用AWS Database迁移服务进行AWS RDS SQL Server迁移
  14. Windows Server 2012活动目录基础配置与应用(新手教程)之1---为什么需要域?
  15. 对称 symmetric
  16. Spring MVC实现服务端数据验证 服务端数据校验 Spring Boot 服务端数据校验
  17. Web前端开发精品课HTML与CSS基础教程 (莫振杰著) 完整pdf扫描版
  18. 火山PC隐藏任务栏程序图标教程
  19. bad assignment报错
  20. linux最上层目录是什么,Linux基础知识之--目录组成结构,当前目录及上层目录表示方法,目录访问权限...

热门文章

  1. 今天,我们就来抽个奖!
  2. 最全、最详细的配置jdk十步法!
  3. 老师不能把你怎样,但外面的世界可以!
  4. 统计单词出现的次数并进行排
  5. Hibernate框架(1)
  6. Error:(1, 10) java: 需要class, interface或enum
  7. 柱状图python_python柱状图一行
  8. java本地创建zk节点
  9. React学习途径和资料分享
  10. 官网下载mysql实例数据库