使用所有对象共有的方法

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

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

目录

1.简介 2.方法equals和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.方法equals和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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337502.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言基础知识:指针与数组的区别是什么

点击蓝字关注我们在C语言教程中我们使用通过数组名通过偏移和指针偏移都可以遍历数组,那么指针和数组到底有什么区别??由于数组中的数据在内存中都是连续存放的,数组名默认就是数组的首地址,也是一个特殊的指针&#x…

Python3 三步爬楼梯问题

Python3 三步爬楼梯问题原题地址 https://leetcode-cn.com/problems/three-steps-problem-lcci/ 题目: 三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。…

python去重复功能_消除Python列表重复的几种方法,python,去,一些

做Python123平台上的列表去重题,复述题目: 去除列表中的重复元素,考虑以下几种情况: l [1, 1, 2, 3] l [[1], [1], [2], [3]] l [3, 2, 1, 1] 原文链接: 14025 总结一下网上的方法和我自己想的方法: 不考…

java java se_Java 8 SE可选,严格的方法

java java se大约两周前,Stephen Colebourne提出了使用Optional的实用方法 。 如果您阅读了它,您可能会从我以前的建议中猜到我不同意。 总览 我必须以免责声明开头,然后我将直接解释为什么我认为他的方法不那么理想。 所有不归因于他人的报…

std::thread 还有哪些使用“姿势”?

点击蓝字关注我们C11 线程创建每一个 C11 程序都包含一个主线程即 main() 函数。在 C11 中我们可以通过创建 std::thread 对象来创建新的线程。每个 std::thread 对象都可以与一个线程相关联。需要引用的头文件&#xff1a;1#include <thread>std::thread 的构造函数中接…

Python3反转字符串

Python3反转字符串原题 https://leetcode-cn.com/problems/reverse-string-ii/题目&#xff1a; 给定一个字符串和一个整数 k&#xff0c;你需要对从字符串开头算起的每个 2k 个字符的前k个字符进行反转。如果剩余少于 k 个字符&#xff0c;则将剩余的所有全部反转。如果有小于…

用python画皇冠_手把手教你用 Python 绘制酷炫的桑基图!

原标题&#xff1a;手把手教你用 Python 绘制酷炫的桑基图&#xff01;作者 | 周志鹏 责编 | 郭 芮 最近&#xff0c;不止一次收到小伙伴的截图追问&#xff1a;“这个图叫什么&#xff1f;&#xff1f;&#xff1f;” “这个图真好看&#xff01;&#xff01;&#xff01;怎么…

ejb能调用另一个ejb吗_异步EJB只是一个Gi头吗?

ejb能调用另一个ejb吗在之前的文章&#xff08; 此处和此处 &#xff09;中&#xff0c;我展示了当服务器负载沉重时&#xff0c;创建非阻塞异步应用程序可以提高性能。 EJB 3.1引入了Asynchronous批注&#xff0c;用于指定方法将在将来的某个时间返回其结果。 Javadocs声明必须…

为啥电脑从C盘开始?A、B盘去哪了?

点击蓝字关注我们前些天硬盘坏了&#xff0c;幸好不是系统盘&#xff0c;不然那些软件安装配置会把我折腾坏&#xff0c;或许这也是在暗示我该换电脑了。重要的数据部分没有遭到损坏&#xff0c;数据是无价的&#xff0c;还是要勤备份。于是换上了一张新的硬盘&#xff0c;当时…

Python3求最后一个单词长度

Python3求最后一个单词长度原题&#xff1a;https://leetcode-cn.com/problems/length-of-last-word/ 给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s&#xff0c;返回其最后一个单词的长度。如果字符串从左向右滚动显示&#xff0c;那么最后一个单词就是最后出现的单词。 …

java 锁_Java之线程并发的各种锁、锁、锁

因为两周没更新了...也不是懒&#xff0c;这两周确实有些忙&#xff0c;赶项目进度赶的不亦乐乎...终于赶在工期前&#xff0c;可以进入内测了&#xff0c;我也有了些时间&#xff0c;可以更新啦...线程并发锁是很常见的问题&#xff0c;而且在Java中锁的类型、概念、使用场景等…

threadsafe_Agrona的Threadsafe堆缓冲区

threadsafe这篇博客文章通过说明我们如何轻松访问线程内存来进行线程安全操作&#xff0c;继续了我在Agrona库上进行的系列文章 。 在继续讨论这是一个相当高级的主题之前&#xff0c;我可能应该警告一下&#xff0c;并且我不尝试解释诸如内存屏障之类的概念&#xff0c;仅概述…

C语言编程中错误异常该如何统一处理?1.8万字总结

点击蓝字关注我们本文主要总结嵌入式系统C语言编程中&#xff0c;主要的错误处理方式。一、错误概念1.1 错误分类从严重性而言&#xff0c;程序错误可分为致命性和非致命性两类。对于致命性错误&#xff0c;无法执行恢复动作&#xff0c;最多只能在用户屏幕上打印出错消息或将其…

Python3实现最小栈

Python3实现最小栈原题 https://leetcode-cn.com/problems/min-stack/ 设计一个支持 push&#xff0c;pop&#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 push(x) – 将元素 x 推入栈中。 pop() – 删除栈顶的元素。 top() – 获取栈顶元素。 getMin…

pycharm remote 远程项目 同步 本地_利器:PyCharm本地连接服务器搭建深度学习实验环境的三重境界...

作为实验室社畜&#xff0c;常需要在本地使用Pycharm写代码&#xff0c;然后将代码同步到服务器上&#xff0c;使用远程登录服务器并运行代码做实验。这其中有很多事情如果没有好的工具&#xff0c;做起来会非常麻烦。比如如何快速同步本地与服务器的代码&#xff1f;如何优雅地…

防御性编程技巧

点击蓝字关注我们在防御性编程的大框架之下&#xff0c;有许多常识性的规则。人们在想到防御性编程的时候&#xff0c;通常都会想到“断言”&#xff0c;这没有错。我们将在后面对此进行讨论。但是&#xff0c;还是有一些简单的编程习惯可以极大地提高代码的安全性。尽管看上去…

unity创建和销毁对象_如何创建和销毁对象

unity创建和销毁对象本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题&#xff0c;包括对象创建&#xff0c;并发&#xff0c;序列化&#xff0c;反射等。 它将指导您完成Java掌握的旅程&#xff01; 在这里查看 &…

Python3实现打家劫舍问题

Python3实现打家劫舍问题原题 https://leetcode-cn.com/problems/house-robber/ 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同…

cookie无法读取bdstoken_第二章(第12节):cookie操作

有时候我们需要验证浏览器中 cookie 是否正确&#xff0c;因为基于真实 cookie 的测试是无法通过白盒和集成测试进行的。WebDriver 提供了操作 cookie 的相关方法&#xff0c;可以读取、添加和删除 cookie信息。WebDriver 操作 cookie 的方法&#xff1a;get_cookies()&#xf…

js 序列化内置对象_内置序列化技术

js 序列化内置对象本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题&#xff0c;包括对象创建&#xff0c;并发&#xff0c;序列化&#xff0c;反射等。 它将指导您完成Java掌握的旅程&#xff01; 在这里查看 &#x…