`

关于Java中使用容器的几个注意点

    博客分类:
  • java
阅读更多

关于Java中使用容器的几个注意点

在看老代码时,看到一处使用HashSet的场景,检查了放入HashSet的类型参数,发现这个类型并没有重写equals和hashCode方法,这个后果的严重程度可想而知。就此暂时总结了以下几点,并配合测试代码,共勉!

总结点如下:

1.  使用HashSet/HahsMap时,定义的元素/key的类型必须同时重写equals和hashCode方法。

2.      TreeSet来说,只需实现Comparable接口,不需要重写equals和hashCode方法,至少java6是这样

3.      对其他容器(无hash),建议都重写equals方法,否则无法支持查找和删除操作。比如使用PriorityQueue时,若仅实现Comparable只支持对象的插入,只有在自定义类实现了equals方法后,才支持查找、删除等操作了。

其中,最重要的就是第一条,需谨记。若不确定对象会被如何使用,建议对任何自定义类型重写equals、hashCode和toString方法。

测试代码中示例类型的说明:

BasicType

 

  • 一个基础的类,包含三个字段,只重写了toString方法

 

ComparableType

 

  • 一个可比较的类,只实现了Comparable接口

 

EqualsType

 

  •  在BasicType的基础上重写了equals方法

 

HashCodeType

 

  • 在BasicType的基础上重写了hashCode方法

 

EqualsComparableType

 

  • 在ComparableType的基础上重写了equals方法

 

HashType

 

  • 在EqualsType基础上重写了hashCode方法

 

设计的类图结构:

测试用例

对HashSet的测试

使用BasicType对HashSet进行测试

[java] view plaincopy
 
  1. /** 
  2.      * 使用{@link BasicType}对HashSet进行测试,对不同对象,equals为false,hashCode不相等<br> 
  3.      * 因此任一{@link BasicType}的对象在HashSet中都是唯一的,见测试{@link #testBasicTypeInHashSet} 
  4.      *  
  5.      * @see BasicType 
  6.      * @see test.HashTypeTest#testHashTypeInHashSet testHashTypeInHashSet 
  7.      */  
  8.     @Test  
  9.     public void testBasicTypeInHashSet() {  
  10.         Set<BasicType> set = new HashSet<BasicType>();  
  11.         set.add(new BasicType());  
  12.         set.add(new BasicType());  
  13.         set.add(new BasicType());  
  14.         set.add(new BasicType());  
  15.   
  16.         BasicType t = new BasicType();  
  17.         set.add(t);  
  18.         set.add(t);  
  19.   
  20.         // size为5,不是我们想要的  
  21.         Assert.assertEquals(set.size(), 5);  
  22.     }  

使用EqualsType对HashSet进行测试

[java] view plaincopy
 
  1. /** 
  2.      * 使用{@link EqualsType}对HashSet进行测试,对不同对象,equals可能为true,hashCode不相等<br> 
  3.      * 任一{@link EqualsType}的对象在HashSet中都是唯一的 
  4.      *  
  5.      * @see EqualsType 
  6.      * @see test.HashTypeTest#testHashTypeInHashSet testHashTypeInHashSet 
  7.      */  
  8.     @Test  
  9.     public void testEqualsTypeInHashSet() {  
  10.         Set<EqualsType> set = new HashSet<EqualsType>();  
  11.         set.add(new EqualsType());  
  12.         set.add(new EqualsType());  
  13.         set.add(new EqualsType());  
  14.         set.add(new EqualsType());  
  15.   
  16.         EqualsType t = new EqualsType();  
  17.         set.add(t);  
  18.         set.add(t);  
  19.   
  20.         // size为5,不是我们想要的  
  21.         Assert.assertEquals(set.size(), 5);  
  22.     }  


使用HashCodeType对HashSet进行测试

[java] view plaincopy
 
  1. /** 
  2.      * 使用{@link HashCodeType}对HashSet进行测试,对不同对象,equals可能为false,hashCode可能相等<br> 
  3.      * 任一{@link HashCodeType}的对象在HashSet中都是唯一的 
  4.      *  
  5.      * @see HashCodeType 
  6.      * @see test.HashTypeTest#testHashTypeInHashSet testHashTypeInHashSet 
  7.      */  
  8.     @Test  
  9.     public void testHashCodeTypeInHashSet() {  
  10.         Set<HashCodeType> set = new HashSet<HashCodeType>();  
  11.         set.add(new HashCodeType());  
  12.         set.add(new HashCodeType());  
  13.         set.add(new HashCodeType());  
  14.         set.add(new HashCodeType());  
  15.   
  16.         HashCodeType t = new HashCodeType();  
  17.         set.add(t);  
  18.         set.add(t);  
  19.         // size为5,不是我们想要的  
  20.         Assert.assertEquals(set.size(), 5);  
  21.     }  


使用HashType对HashSet进行测试

[java] view plaincopy
 
  1. /** 
  2.      * 使用{@link HashType}对HashSet进行测试,对不同对象,equals可能为true,hashCode可能相等<br> 
  3.      * 此时可以用HashSet去除重复对象(hashCode相等且是equals的),正是我们想要的 
  4.      *  
  5.      * @see HashType 
  6.      */  
  7.     @Test  
  8.     public void testHashTypeInHashSet() {  
  9.         Set<HashType> set = new HashSet<HashType>();  
  10.         set.add(new HashType());  
  11.         set.add(new HashType());  
  12.         set.add(new HashType());  
  13.         set.add(new HashType());  
  14.   
  15.         HashType t = new HashType();  
  16.         set.add(t);  
  17.         set.add(t);  
  18.         // 相等值对象被去除,size为1, 正是我们想要的  
  19.         Assert.assertEquals(set.size(), 1);  
  20.     }  


对TreeSet的测试

使用ComparableType对TreeSet进行测试

[java] view plaincopy
 
  1. /** 
  2.      * 使用ComparableType对TreeSet进行测试<br> 
  3.      * 使用TreeSet的类必须实现Comparable接口,但不必重写equals和hashCode方法,与TreeSet的内部实现有关 
  4.      *  
  5.      * @see tijava.container.type.ComparableType 
  6.      */  
  7.     @Test  
  8.     public void testComparableTypeInTreeSet() {  
  9.         Set<ComparableType> q = new TreeSet<ComparableType>();  
  10.         q.add(new ComparableType('d'3null));  
  11.         q.add(new ComparableType('d'4null));  
  12.         q.add(new ComparableType());  
  13.         q.add(new ComparableType());  
  14.         q.add(new ComparableType());  
  15.         q.add(new ComparableType());  
  16.         q.add(new ComparableType());  
  17.   
  18.         Assert.assertEquals(q.size(), 3);  
  19.         Assert.assertTrue(q.contains(new ComparableType('d'3null)));  
  20.   
  21.         q.remove(new ComparableType('d'3null));  
  22.         //remove ok  
  23.         Assert.assertEquals(q.size(), 2);  
  24.     }  


对PriorityQueue的测试

使用ComparableType对PriorityQueue进行测试

[java] view plaincopy
 
  1. /** 
  2.      * 使用ComparableType对PriorityQueue进行测试<br> 
  3.      * 在PriorityQueue中使用自定义类时,若只实现Comparable接口的类型,不支持查找和删除等操作 
  4.      *  
  5.      * @see test.EqualsComparableTypeTest#testEqualsComparableTypeInPriorityQueue 
  6.      *      testEqualsComparableTypeInPriorityQueue 
  7.      */  
  8.     @Test  
  9.     public void testComparableTypeInPriorityQueue() {  
  10.         Queue<ComparableType> q = new PriorityQueue<ComparableType>();  
  11.         q.add(new ComparableType('C'4"Empty trash"));  
  12.         q.add(new ComparableType('A'2"Feed dog"));  
  13.         q.add(new ComparableType('B'7"Feed bird"));  
  14.         q.add(new ComparableType('C'3"Mow lawn"));  
  15.         q.add(new ComparableType('A'1"Water lawn"));  
  16.         q.add(new ComparableType('B'1"Feed cat"));  
  17.   
  18.         Assert.assertEquals(q.size(), 6);  
  19.         Assert.assertFalse(q  
  20.                 .contains(new ComparableType('C'4"Empty trash")));  
  21.         Assert.assertFalse(q.remove(new ComparableType('C'4"Empty trash")));  
  22.           
  23.         //siz is still 6, not remove success  
  24.         Assert.assertEquals(q.size(), 6);  
  25.     }  


使用EqualsComparableType对PriorityQueue进行测试

[java] view plaincopy
 
  1. /** 
  2.      * 使用EqualsComparableType对PriorityQueue进行测试<br> 
  3.      * 在使用PriorityQueue是,在自定义类实现了equals方法后,就支持查找、删除等操作了 
  4.      *  
  5.      * @see test.ComparableTypeTest#testComparableTypeInPriorityQueue 
  6.      *      testComparableTypeInPriorityQueue 
  7.      */  
  8.     @Test  
  9.     public void testEqualsComparableTypeInPriorityQueue() {  
  10.         Queue<EqualsComparableType> q = new PriorityQueue<EqualsComparableType>();  
  11.         q.add(new EqualsComparableType('C'4"Empty trash"));  
  12.         q.add(new EqualsComparableType('A'2"Feed dog"));  
  13.         q.add(new EqualsComparableType('B'7"Feed bird"));  
  14.         q.add(new EqualsComparableType('C'3"Mow lawn"));  
  15.         q.add(new EqualsComparableType('A'1"Water lawn"));  
  16.         q.add(new EqualsComparableType('B'1"Feed cat"));  
  17.   
  18.         Assert.assertEquals(q.size(), 6);  
  19.         Assert.assertTrue(q.contains(new EqualsComparableType('C'4,  
  20.                 "Empty trash")));  
  21.         Assert.assertTrue(q.remove(new EqualsComparableType('C'4,  
  22.                 "Empty trash")));  
  23.           
  24.         // remove ok  
  25.         Assert.assertEquals(q.size(), 5);  
  26.     }  
分享到:
评论

相关推荐

    14个Java并发容器,你用过几个?.docx

    不考虑多线程并发的情况下,容器类一般使用ArrayList、HashMap等线程不...上面提到的线程安全容器都在java.util.concurrent包下,这个包下并发容器不少,今天全部翻出来鼓捣一下。 仅做简单介绍,后续再分别深入探索。

    JAVA上百实例源码以及开源项目

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    JAVA上百实例源码以及开源项目源代码

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    java开源包8

    它是 Spring HttpInvoker的一个轻量级选择,特别适合于当你不想在客户端程序中使用Spring框架。 API访问授权的开放标准 OAuth OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式...

    java 课程 实验

    最后显示“中了几个号”。同时,如果中了7个号,显示一等奖;如果中了6个号,显示二等奖;如果中了5个号,显示三等奖。要求:首先写出程序的实现思想,特别是程序所使用的数据结构,然后写出Java实现代码。【说明:...

    几个小小的Java案例

    不幸的是,很多企业级项目根本没有这么复杂,却承担了EJB的这种编写多个Java文件和部署文件,运行中量级容器的负担。只要用了EJB,不管系统要解决的问题是否复杂,甚至一个简单的系统,其复杂程度都会很高。使用...

    java开源包11

    它是 Spring HttpInvoker的一个轻量级选择,特别适合于当你不想在客户端程序中使用Spring框架。 API访问授权的开放标准 OAuth OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式...

    java开源包6

    它是 Spring HttpInvoker的一个轻量级选择,特别适合于当你不想在客户端程序中使用Spring框架。 API访问授权的开放标准 OAuth OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式...

    java开源包9

    它是 Spring HttpInvoker的一个轻量级选择,特别适合于当你不想在客户端程序中使用Spring框架。 API访问授权的开放标准 OAuth OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式...

    java面试宝典

    156、在jsp:useBean语法中使用beanName有何好处? 37 157、当我使用时,在浏览器的地址栏没有改变? 37 158、如何转换JSP 0.9版本的文件到JSP1.1? 37 160、JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么...

    java开源包101

    它是 Spring HttpInvoker的一个轻量级选择,特别适合于当你不想在客户端程序中使用Spring框架。 API访问授权的开放标准 OAuth OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式...

    java开源包4

    它是 Spring HttpInvoker的一个轻量级选择,特别适合于当你不想在客户端程序中使用Spring框架。 API访问授权的开放标准 OAuth OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式...

    java开源包5

    它是 Spring HttpInvoker的一个轻量级选择,特别适合于当你不想在客户端程序中使用Spring框架。 API访问授权的开放标准 OAuth OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式...

    Java2实用教程.rar

    12 5JavaApplet中使用套接字 习题 第13章常见数据结构的Java实现 13 1链表 13 2栈 13 3树集 13 4树映射 13 5散列集 13 6散列表 13 7向量 习题 第14章图形与图像 14 1绘制文本 14 2绘制基本图形 14 3建立字体 14 4...

    《Java并发编程的艺术》源代码

    Java并发编程的艺术 作者:方腾飞 魏鹏 程晓明 著 丛书名:Java核心技术系列 出版日期 :2015-07-25 ISBN:978-7-111-50824-3 第1章介绍Java并发编程的...第11章介绍几个并发编程的实战,以及排查并发编程造成问题的方法。

    java开源包10

    它是 Spring HttpInvoker的一个轻量级选择,特别适合于当你不想在客户端程序中使用Spring框架。 API访问授权的开放标准 OAuth OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式...

    Java中的正则表达式笔记

    然后引入外部创建的css和js文件,可以先定义几个text容器,用于调整样式;CSS是为文字雨效果增色添彩的关键,使动画效果更加丰富,关于一些 CSS 样式: 使用了自定义的颜色变量来为背景色和文本颜色提供值,有助于...

    java 面试题 总结

    创建了几个String Object? 两个 28、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。 public class ThreadTest1{ ...

    java 程序设计 期中考试.doc

    1.Java的源代码中定义几个类,编译结果就生成几个以.class为后缀的字节码文件.( √ ) 2.Java程序里,创建新的类对象用关键字new,回收无用的类对象使用关键字free. ( × ) 3.Java有垃圾回收机制,内存回收...

    JAVA面试题最全集

    5.j2me程序的必需的几个部分 6.c/s与b/s的区别 7.构建一个connect pool,然后再调用它, 8.j2ee平台与dotnet平台的区别 9.ejb的life cycle 10.session bean 和 entity bean的区别 11.ejb中的transaction机制 ...

Global site tag (gtag.js) - Google Analytics