Java语言具有优秀的特点,在互联网位置上占有重要的位置,其特点介绍如下。由此可见,Java语言是一门纯正的面向对象程序设计语言。另外,Java的安全检查机制使得Java更具健壮性。在Java中,使用安全机制可以防止恶意代码的攻击。并且,Java还严格规定了各个基本数据类型的长度。11)Java语言是动态的:Java语言能够适应动态变化的环境。另外,Java中的类有一个运行时刻的表示,能够时刻检查运行的类型。......
2023-11-05
java语言中equals方法和hashCode方法源代码的研究
王善发 吴道勇
摘 要: java程序设计中,集合是很主要的一部分,文章深入Java Web编程中经常用到的API中的集合类的源代码,针对集合元素加载时不能有重复对象这一特性进行研究。深入浅出地讲解清楚集合中用到的equals方法和hashCode方法,让程序员在使用到集合的类时得心应手。
关键词: java Web 编程 对 象equals方法 hashCode 方法
一、引 言
在java中,Collection是集合类层次结构中的根接口。Collection表示一组对象,这些对象也称为Collection的元素。一些Collection允许有重复的元素,而另一些则不允许。一些Collection是有序的,而另一些则是无序的。JDK不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现。此接口通常用来传递Collection,并在需要最大普遍性的地方操作这些Collection。
Set接口是一个不包含重复元素的Collection。更确切地讲,Set不包含满足e1.equals(e2)的元素对e1和e2,并且最多包含一个null元素。正如其名称所暗示的,此接口模仿了数学上的Set抽象。
在所有构造方法以及add、equals和hashCode方法的基础上,Set接口还加入了其他规定,这些规定超出了从Collection接口所继承的内容。出于方便考虑,它还包括了其他继承方法的声明(这些声明的规范已经专门针对Set接口进行了修改)。对这些构造方法的其他规定是:所有构造方法必须创建一个不包含重复元素的Set。
Set接口是Java Collections Framework的成员。
二、在使用HashSet类时出现的一些问题
HashSet类是Set接口的一个实现类,该类由哈希表(实际上是一个HashMap实例)支持。它不保证Set的迭代顺序,特别是它不保证该顺序恒久不变。该类允许使用null元素。该类不能加载重复的对象,但是,有时该源代码对一些特殊问题的处理不能满足编程人员的要求,必须要编程人员自己根据实际情况去处理。
下面是HashSet集合的一个测试程序(Test. java):
importjava.util.*;
public class Test
{
public static void main(String[]args)
{
HashSet set1= new HashSet( );
HashSet set2= new HashSet( );
HashSet set3= new HashSet( );
HashSet set4= new HashSet( );
set1.add(new People("zhangsan"));
set1.add(new People("zhangsan"));
People p1= new People("lisi");
set2.add(p1);
set2.add(p1);
String str1= new String("wangwu");
String str2= new String("wangwu");
set3.add(str1);
set3.add(str2);
set4.add("Hello");
set4.add("Hello");
for(Iteratoriter= set1.iterator( ); iter.hasNext( );)
{
System.out.println("set1:"+((People) iter.next
( )).name);
}
for(Iterator iter= set2. iterator(); iter.hasNext( );)
{
System.out.println("set2:"+((People) iter.next
( )).name);
}
for(Iterator iter= set3. iterator(); iter.hasNext( );)
{
System.out.println("set3:"+(String)iter.next());
}
for(Iterator iter= set4. iterator(); iter.hasNext( );)
{
System.out.println("set4:"+(String)iter.next( ));
}
}
}
class People
{
public String name;
public People(String name)
{
this.name= name;
}
}
运行结果:
set1: zhangsan
set1: zhangsan
set2: lisi
set3: wangwu
set4: Hello
在上述程序运行结果中,用相同名字zhangsan为参数实例化的两个People对象被HashSet集合的对象set1调用add()方法两次,就被加载了两次。而用名字lisi为参数实例化的一个People对象被HashSet集合的对象set2调用add()方法两次,却只被加载了一次。用名字wangwu为参数实例化的两个String对象被HashSet集合的对象set3调用add()方法两次,也只被加载了一次。字面常量“Hello”被HashSet集合的对象set4调用add()方法两次,也只被加载了一次。
三、对使用Hash Set类出现问题的分析(www.chuimin.cn)
HashSet类从java. lang.Object类中继承了equals方法和hashCode方法。
(1)在java.util.Hash Set中add方法的特点如下:
publicboolean add(Ee)方法规定,如果此Set中尚未包含指定元素,则添加指定元素。更确切地讲,如果此Set没有包含满足(e== null? e2== null: e.equals(e2))的元素e2,则向此Set添加指定的元素e。如果此Set已包含该元素,则该调用不更改Set并返回false。
(2)在java. lang.Object中equals方法的特点如下:
publicboolean equals(Object obj)指示其他某个对象是否与此对象“相等”。
equals方法在非空对象引用上实现相等关系。
自反性:对于任何非空引用值x,x.equals(x)都应返回true。
对称性:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。
传递性:对于任何非空引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)应返回true。
一致性:对于任何非空引用值x和y,多次调用x.equals(y)始终返回true或始终返回false,前提是对象上equals比较中所用的信息没有被修改。
对于任何非空引用值x,x.equals(null)都应返回false。
Object类的equals方法实现对象上差别可能性最大的相等关系,即,对于任何非空引用值x和y,当且仅当x和y引用同一个对象时,此方法才返回true(x== y具有值true)。
注意:当此方法被重写时,通常有必要重写hashCode方法,以维护hashCode方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
(3)在java. lang.Object中hashCode方法的特点如下:
publicint hashCode()返回该对象的哈希码值。支持此方法是为了提高哈希表(例如java.util.Hashtable提供的哈希表)的性能。
hashCode的常规协定是:
在java应用程序执行期间,在对同一对象多次调用hash-Code方法时,必须一致地返回相同的整数,前提是将对象进行equals比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无须保持一致。
如果根据equals(Object)方法,两个对象是相等的,那么对这两个对象中的每个对象调用hashCode方法都必须生成相同的整数结果。
如果根据equals(java. lang.Object)方法,两个对象不相等,那么对这两个对象中的任一对象上调用hashCode方法不要求一定生成不同的整数结果。为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由Object类定义的hashCode方法确实会针对不同的对象返回不同的整数(这一般是通过将该对象的内部地址转换成一个整数来实现的)。
(4)当使用HashSet时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code值是否与增加的对象的hash code值一致。如果不一致,直接加进去;如果一致,再进行equals方法的比较,equals方法如果返回true,表示对象已经加进去了,就不会再增加新的对象,否则要再加进去。
(5)如果我们重写equals方法,那么也要重写hashCode方法,反之亦然。
从上面的分析就不难理解在Test. java程序中产生的结果。
由于参数名字相同的两个zhangsan产生了两个People对象,对象的地址不同。People继承了Object的equals方法和hashCode方法,equals方法比较的结果为false,hashCode方法返回的hash code不相同,所以被加载了两次。
由lisi为参数产生的一个People对象,对象的地址只有一个。People继承了Object的equals方法和hashCode方法,equals方法比较的结果为true,hashCode方法返回的hash code相同,所以只被加载了一次。
由于参数名字相同的两个wangwu被new了两个对象。虽然对象的地址不同,但是,由于String类已经重写了equals方法和hashCode方法,它们的hashCode方法返回的hash code相同,它们的equals比较结果是true,所以只被加载了一次。
由于Hello是用字面常量产生的对象,所以两个Hello只在string pool中产生一个字符串对象,由于String类已经重写了equals方法和hashCode方法,它们的hashCode方法返回的hash code相同,它们的equals比较结果是true,所以只被加载了一次。
四、对使用HashSet类出现特殊问题的处理
要想在Test. java程序中把People对象加载到HashSet集合中时,相同名字的不同对象只能加载一次,就要在People类重写equals方法和hashCode方法,让People类重写的equals方法和hashCode方法覆盖java. lang.Object类的equals方法和hashCode方法。
为了实现程序员的要求,改写后的People类代码如下:
class People
{
String name;
public People(String name)
{
this.name= name;
}
publicint hashCode()
{
return this.name.hashCode();
}
publicboolean equals(Object obj)
{
if(this== obj)
{
return true;
}
if(null!= obj&&obj instance of Student)
{
Student s=(Student) obj;
if(name.equals(s.name))
{
return true;
}
}
return false;
}
}
五、结束语
文章从HashSet类的元素加载(add方法)入手,追溯到java.util.AbstractSet类中继承了equals方法和hashCode方法、java. lang.Object类的equals方法和hashCode方法,直到程序员在自己编写的People类中重写equals方法和hashCode方法,理清了思路,解决了问题。
参考文献:
[1]John LewisWilliam Loftus. Java程序设计教程[M].北京:电子工业出版社,2009.
[2]李芝兴,杨瑞龙. Java程序设计之网络编程:第2版[M].北京:清华大学出版社,2009.
[3]林信良. JDK 6 Java学习笔记[M].北京:清华大学出版社,2007.
[4]阎宏. Java与模式[M].北京:电子工业出版社,2002.
[5]孙萍,迟耀丹. Java中Object类的方法应用[J].吉林建筑工程学院学报,2007(9).
[6]庞家乐,王兴斌,胡成玉. Java编程常见问题若干例[J].武汉科技学院学报,2004(8).
有关探索与创新: 保山学院教师学术论文选集的文章
Java语言具有优秀的特点,在互联网位置上占有重要的位置,其特点介绍如下。由此可见,Java语言是一门纯正的面向对象程序设计语言。另外,Java的安全检查机制使得Java更具健壮性。在Java中,使用安全机制可以防止恶意代码的攻击。并且,Java还严格规定了各个基本数据类型的长度。11)Java语言是动态的:Java语言能够适应动态变化的环境。另外,Java中的类有一个运行时刻的表示,能够时刻检查运行的类型。......
2023-11-05
在Java语言中,可将二维数组视为一维数组的数组,其中一维数组的每个元素都是一个一维数组。接下来主要以二维数组为例来介绍多维数组的使用。......
2023-11-22
语言与言语治疗/介入导向可依它的自然性,也就是与日常沟通情境一致性的程度。治疗师导向起源于行为主义的ABC理论。B指的是行为,是指个案表现语言与言语治疗的目标行为。所以在此种方法中,治疗师要做的就是设计前事及后果。个案中心法,是由个案引导介入的方案,包括治疗内容、时间及治疗顺序等。......
2023-07-02
本课题的研究内容主要是研究社会集群的复杂网络结构特征和群体演化过程,分析各种典型行为模型的特性,归纳建立个体的模型。本节主要研究步骤如下:图3-2研究思路和研究方法......
2023-07-02
向Applet中添加其他AWT组件及其事件处理的方式,与图形用户界面程序的设计是一样的。Applet中有3个与显示相关的方法,即paint()、update()和repaint()。这是除了与生命周期有关的4个基本方法之外,专门用于显示及刷新的重要的Applet方法,它们都是在java.awt.Component类中声明的。当Applet首次被装载,以及每次窗口放大、缩小、刷新时,都要调用paint()方法。......
2023-11-22
文本信息是搜索引擎主要处理的内容。自然语言处理,严格来说包括自然语言理解与自然语言生成两部分,这里我们只涉及自然语言理解部分。1)中文关键词提取在自然语言处理中,关键词提取是至关重要的一环。TF是词频Term Frequency的简称,IDF是逆文档频率指数Inverse Document Frequency的简称。2)中文自动摘要减少原文的长度而保留文章的主题意思叫做“摘要”。语义搜索引擎进行推理及知识积累的基础与关键是知识库,而Ontology(本体)是知识库的基础。......
2023-07-02
对于嵌套的结构体类型变量,访问其成员时应采用逐级访问的方法,直到获得所需访问的成员为止。利用结构体变量作函数参数,实现计算某学生3门课程平均成绩的功能。......
2023-11-20
这一问题以确定受访人员是否属于本研究的调研对象。本研究将“凡是出生地不是上海,但现在在上海生活、工作的人”界定为“新上海人”,也就是“上海城市新移民”,即本研究的研究对象。三名课题组成员分头调研。由于客观条件所限,本研究无法对所有新上海人进行全面抽样调查研究,因此,本研究不能确保统计结果全面反映在新上海人的特征。......
2023-11-08
相关推荐