`

关于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.     }  
分享到:
评论

相关推荐

    JAVA容器效率深度分析List

    在Java编程中,容器是用于...总之,理解并掌握这些Java容器的特性和效率差异,能够帮助我们在实际开发中做出更合适的选择,提高程序的性能和可维护性。在具体应用时,还需要结合业务需求和性能测试,才能做出最佳决策。

    JAVA中AWT的几个实例

    这个压缩包文件包含了几个关于AWT的实际应用示例,对于初学者来说是非常有价值的参考资料。 首先,我们要理解AWT的基础概念。AWT是基于原生操作系统API的,这意味着它的组件在不同的操作系统上可能会有不同的表现。...

    Cognos在其他java容器中的部署

    ### Cognos在其他JAVA容器中的部署 #### 知识点概述 本文主要介绍如何将Cognos 8部署在TongWeb等不同JAVA容器上。Cognos是一款功能强大的商业智能工具,能够帮助企业实现数据可视化、报表制作等功能。为了确保...

    Java容器学习要点1136

    在Java容器API中,有几个重要的方法需要理解: - `size()`:返回集合中元素的数量。 - `isEmpty()`:检查集合是否为空。 - `clear()`:清空集合中的所有元素。 - `contains(Object element)`:检查集合是否包含特定...

    Java初学者 几个小游戏的代码

    在这个“Java初学者 几个小游戏的代码”压缩包中,包含了一系列适合新手学习的Java代码示例。让我们逐一探讨这些小游戏背后的编程知识。 1. **猜数字游戏**: 猜数字游戏通常涉及到随机数生成、循环控制和条件判断...

    Java容器简图.docx

    Java容器主要分为四大类:List、Set、Queue和Map,每种都有其特定的用途和实现方式。下面我们将深入探讨这些容器及其相关的实现版本。 1. **List**: List是一种有序的容器,允许重复元素,并且支持索引访问。Java...

    java JComboBox的使用

    在 Java GUI 应用程序中,`JComboBox` 的使用通常包括以下几个关键步骤: 1. **创建 `JComboBox` 对象**: 创建 `JComboBox` 需要调用其构造函数,可以传入一个 `Object` 数组或 `Vector` 作为选项。例如: ```...

    Java jdk api 1.8中文帮助手册

    在Java 1.8中,有几个核心的更新和增强,包括: 1. **Lambda表达式**:这是Java 8的一大亮点,引入了函数式编程的概念。Lambda表达式可以用来创建匿名函数,简化了对集合的操作,特别是`Stream API`的使用。例如,`...

    自己实现的ioc容器

    总结来说,实现一个简单的IoC容器涉及以下几个步骤: 1. 定义bean的配置(XML或注解)。 2. 解析配置,创建BeanDefinition。 3. 实现BeanFactory接口,包括bean的实例化、依赖注入和生命周期管理。 4. 使用反射处理...

    java程序 两个线程实现学生成绩的读写

    在设计这样的程序时,我们需要注意以下几个关键点: 1. **数据同步**:确保在读写操作时对共享数据的访问是安全的,避免数据不一致。 2. **线程交互**:合理安排线程间的执行顺序,防止读写冲突。 3. **资源管理**...

    java定时任务,每天定时执行任务

    Java 定时任务是指在 Java 语言中实现的定时执行任务的机制,通过使用 Timer 和 TimerTask 两个类,可以实现定时执行任务的功能。在这个例子中,我们将实现每天定时执行任务的功能,具体来说,就是在每天的凌晨 2 点...

    Java中图形界面设计中的几个Swing程序小例子

    在这个名为"Swingdemo"的压缩包中,我们可以期待找到一些使用Swing库创建的示例程序,这些程序对于初学者来说是非常有价值的实践资源。 Swing库提供了许多组件,用于构建桌面应用程序,如按钮(JButton)、文本框...

    03_关于互联网Java工程师面试突击训练课程的几点说明.zip

    在Java工程师面试中,面试者通常需要对以下几个关键知识点有深入理解: 1. **Java基础**:包括语法、面向对象特性(封装、继承、多态)、异常处理、集合框架(List、Set、Map等)、IO流、线程、反射等。 2. **JVM*...

    java GUI界面设计之窗口和容器

    JFrame 有几个重要的方法,例如 setUndecorated(true) 可以删除边框,getRootPane().setWindowDecorationStyle(JRootPane.NONE) 可以采用指定的窗口装饰风格。JFrame 还可以获取屏幕的宽度和高度,例如 Toolkit....

    Java开发学习之Java基础语法注意点共2页.pdf.z

    本资料“Java开发学习之Java基础语法注意点共2页.pdf”着重讲解了Java编程的基础语法,这对于初学者或者希望巩固基础知识的开发者来说至关重要。在Java的学习过程中,掌握好基础语法是构建强大编程能力的基石。 ...

    Java容器集合(equals 和 hashCode+基础数据结构+ArrayList+Vector和LinkedList)

    Java容器集合是Java中的一种基础数据结构,用于存储和管理数据。其中,equals和hashCode方法是Java容器集合中两个非常重要的方法,本文将详细介绍这两个方法,并结合ArrayList、Vector和LinkedList三个常见的容器...

    第一个Java程序HelloWorld

    一个 Java 程序通常由以下几个部分组成: 1. 包名(package):用于标识类所属的包名。 2. 导入语句(import):用于导入其他类或包。 3. 类定义(class):用于定义类的名称、属性和行为。 4. 主方法(main):...

    IOC容器简单实现

    本篇文章将深入探讨如何使用Java实现一个简单的IOC容器。 ### 1. IOC容器的基本概念 IOC的核心思想是“依赖注入”(Dependency Injection,DI)。在传统的编程中,对象A依赖于对象B,通常在A的构造函数或者初始化...

    Java开发中的容器概念、分类与用法深入详解

    Java容器是Java开发中非常重要的一部分,它提供了存储和管理对象的方式。在Java开发中,容器是指可以存储其他对象的类,或者说是集合,即将多个对象组合在一起形成一个整体。下面我们将详细介绍Java容器的概念、分类...

Global site tag (gtag.js) - Google Analytics