- 浏览: 62238 次
- 性别:
文章分类
最新评论
-
loamy:
能不能选择一行中的某一部分进行复制,比如一行50个字符,我只想 ...
vim命令 -
gaodadawei:
...
javascript函数和onsubmit用法讲解 -
gaodadawei:
...
javascript函数和onsubmit用法讲解
结构图:
|--------SortedSet--------TreeSet
|
|------------HashSet
Set---------
|
|------------LinkedHashSet
|
|------------CopyOnwriteArraySet
Set(interface): 存入Set的每个元素必须是唯一的,因为Set不保存重复元素。加入Set的Object必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。
HashSet: 为快速查找而设计的Set。存入HashSet的对象必须定义hashCode()。
TreeSet: 保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。
LinkedHashSet: 具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。
HashSet采用
散列函数
对元素进行排序,这是专门为快速查询而设计的;TreeSet采用
红黑树
的数据结构进行排序元
素;LinkedHashSet内部使用散列以加快查询速度,同时使用链表维护元素的次序,使得看起来元素是以插入的顺序保存的。需要注意的是,生成自己
的类时,Set需要维护元素的存储顺序,因此要实现Comparable接口并定义compareTo()方法。
1、TreeSet部分:
以下以TreeSet为例进行分析。
请看TreeSet的部分实体:
public class TreeSet<E> extends AbstractSet<E> implements SortedSet<E>, Cloneable, java.io.Serializable { // The backing Map private transient SortedMap<E,Object> m; // The keySet view of the backing Map private transient Set<E> keySet; // Dummy value to associate with an Object in the backing Map //这是每个键所指的对像 private static final Object PRESENT = new Object(); //constructor private TreeSet(SortedMap<E,Object> m) { this.m = m; keySet = m.keySet(); } public TreeSet() { this(new TreeMap<E,Object>()); } //以下省略.......... }
可以看到TreeSet使用了SortedMap作为其Map保存“键-值”对,而这个SortedMap的真正实体是TreeMap。
请看示例程序1:
import java.util.*; public class SetTest1 { public static void main(String[] args){ Set set = new TreeSet(); set.add(new SetElement1("aa")); set.add(new SetElement1("bb")); } static class SetElement1{ String s; public SetElement1(String s){ this.s = s; } public String toString(){ return s; } public boolean equals(Object obj) { return s.equals(((SetElement1)obj).s); } } }
该程序能够正常编译,但是运行时会抛出异常java.lang.ClassCastException。为什么?
请看示例程序2:
import java.util.*; public class SetTest2 { public static void main(String[] args){ Set set = new TreeSet(); set.add(new SetElement2("aa")); set.add(new SetElement2("aa")); set.add(new SetElement2("bb")); System.out.println(set); } static class SetElement2 implements Comparable{ String s; public SetElement2(String s){ this.s = s; } public String toString(){ return s; } public int compareTo(Object o){ return s.compareTo(((SetElement2)o).s); } public boolean equals(Object obj) { return s.equals(((SetElement2)obj).s); } } }
运行结果:
[aa, bb]
这正是我们所期望的结果。那“示例程序1”和“示例程序2”有什么区别?
是因为SetElement2实现了Comparable接口,而SetElement1没有。SetElement2实现Comparable接
口有什么用呢?因为在TreeSet的add方法中需要比较两个 元素的“值”。请看TreeMap中的compare方法:
private int compare(K k1, K k2) { return (comparator==null ? ((Comparable</*-*/K>)k1).compareTo(k2) : comparator.compare((K)k1, (K)k2)); }
可见这个方法先把要比较的元素down cast成Comparable类型。这里就可以解释“示例程序1”中为什么会抛出异常
java.lang.ClassCastException,因SetElement1没有实现Comparable接口,当然就不能down cast
成Comparable。可见,要用TreeSet来做为你的Set,那么Set中所装的元素都必须实现了Comparable接口。
说到这里,你是不是想到了TreeSet中是采用Comparable接口中的compareTo方法来判断元素是否相同(duplicate),而不是采用其他类似equals之类的东东来判断。
请看示例程序3:
import java.util.Set; import java.util.*; public class SetTest3 { public static void main(String[] args){ Set set = new HashSet(); set.add(new SetElement3("aa")); set.add(new SetElement3("aa")); set.add(new SetElement3("bb")); System.out.println(set); } static class SetElement3 implements Comparable{ String s; public SetElement3(String s){ this.s = s; } public String toString(){ return s; } public int compareTo(Object o){ //return s.compareTo(((SetElement3)o).s); return -1; } public boolean equals(Object obj) { return s.equals(((SetElement3)obj).s); } } }
运行结果:
[bb, aa, aa]
看到没有,有两个“aa”!!这是因为compareTo返回值始终是"-1",也就是说“把任何元素都看成不同”。
2、HashSet部分:
以下以HashSet为例进行分析。
从Hashset类的主体部分:
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable { static final long serialVersionUID = -5024744406713321676L; private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map //这是每个键所指的对像 private static final Object PRESENT = new Object(); public HashSet() { map = new HashMap<E,Object>(); } public boolean add(E o) { return map.put(o, PRESENT)==null; } //以下省略.......... } public HashSet() { map = new HashMap<E,Object>(); }
可以看到HashSet使用了HashMap作为其Map保存“键-值”对。
请看示例程序4:
import java.util.*; public class SetTest4 { public static void main(String[] args){ Set set = new HashSet(); set.add(new SetElement4("aa")); set.add(new SetElement4("aa")); set.add(new SetElement4("bb")); System.out.println(set); } static class SetElement4{ String s; public SetElement4(String s){ this.s = s; } public String toString(){ return s; } public boolean equals(Object obj) { return s.equals(((SetElement4)obj).s); } } }
运行结果:
[bb, aa, aa]
没有“示例程序1”中的java.lang.ClassCastException,但是运行结果似乎不对,因为有两个“aa”。
请看示例程序5:
import java.util.*; public class SetTest5 { public static void main(String[] args){ Set set = new HashSet(); set.add(new SetElement5("aa")); set.add(new SetElement5("aa")); set.add(new SetElement5("bb")); System.out.println(set); } static class SetElement5{ String s; public SetElement5(String s){ this.s = s; } public String toString(){ return s; } public boolean equals(Object obj) { return s.equals(((SetElement5)obj).s); } public int hashCode() { //return super.hashCode(); return s.hashCode(); } } }
运行结果:
[bb, aa]
这就对了。“示例程序4”和“示例程序5”有什么区别?是SetElement5重写了hashCode方法。
可见HashSet中是采用了比较元素hashCode的方法来判断元素是否相同(duplicate),而不是采用其他类似equals之类的东东来判断。
3、CopyOnWriteArraySet部分:
类CopyOnWriteArraySet是java.util.concurrent包中的一个类,所以它是线程安全的。
CopyOnWriteArraySet是使用CopyOnWriteArrayList作为其盛放元素的容器。当往CopyOnWriteArrayList添加新元素,它都要遍历整个List,并且用equals来 比较两个元素是否相同。
请看示例程序6:
import java.util.*; import java.util.concurrent.*; public class SetTest6 { public static void main(String[] args){ Set set = new CopyOnWriteArraySet(); set.add(new SetElement6("aa")); set.add(new SetElement6("aa")); set.add(new SetElement6("bb")); System.out.println(set); } static class SetElement6{ String s; public SetElement6(String s){ this.s = s; } public String toString(){ return s; } public boolean equals(Object obj) { return s.equals(((SetElement6)obj).s); } } }
运行结果:
[aa, bb]
好了,一切搞定!!
4、总结:
Set中实现元素互异的各种方法差异很大,大致可以分为三种:使用equals,使用hashCode,使用compareTo。但是我还没有发现
采用“判断地址空间是否相同”来判断元素是否相同的类,当然我们可以用现有的三种方法来实现“判断地址空间是否相同”。
综上所述,我们可以总结出使用Set的三种不同的情形:(以下假设元素类为Element)
A、如果想使用Element的equals方法来判断元素是否相同,那么可以使用CopyOnWriteArraySet来构造类的实体。
B、如果Element实现了Comparable接口,而且想使用compareTo方法来判断元素是否相同,那么可以使用TreeSet来构造类的实体。
C、如果想使用判断hashCode是否相同的方法来判断元素是否相同,那么可以使用HashSet来构造类的实体。
发表评论
-
String点滴
2008-08-01 23:32 863String.subString(int beginIndex ... -
传值还是传引用
2008-07-31 00:36 914Does Java pass by reference or ... -
类初始化顺序
2008-07-25 17:56 666父类->子类 静态变量/静态初始化块--->一 ... -
java面向对象浅析系列2——抽象类、接口与多继承
2008-07-11 13:36 2439转载于 http://blog.csdn.net/hwalan ... -
java面向对象浅析系列1——三个基本特征
2008-07-11 13:30 5488转载于 http://blog.csdn.net/hwala ... -
内部类
2008-07-10 22:19 1026关于JAVA内部类:一个内部类的定义是定义在另一个类内部的类。 ... -
匿名内部类
2008-07-10 22:08 968匿名的内部类是没有名字的内部类。可以继承一个类,但不能ext ... -
List的使用方法讲解及演示
2008-07-10 16:52 3954List接口 List是有 ... -
String VS StringBuffer VS StringBuilder
2008-07-09 21:47 1190首先看一下这三者的区别: String是固定长度的字符串 ... -
java屏幕输出
2008-07-09 18:46 926public class C{ public stat ...
相关推荐
书中还会讲解如何使用STL(Standard Template Library,标准模板库),这是C++库中的一大亮点,包括容器(如vector、list、set)、算法(如排序、查找)和迭代器等。STL极大地提高了C++程序员的生产力,让代码更加...
"C++经典课件详细讲解c++精要"这套资源旨在为初学者提供深入理解和掌握C++的基础。课件内容全面,覆盖了C++语言的核心概念,帮助学习者逐步构建编程思维。 在C++的学习中,首先会接触到基础语法,包括变量、数据...
本文将为您详细讲解 C# get set 函数的使用和应用。 一、为什么需要 get set 函数? 在面向对象编程中,类的成员变量通常是私有的,以保护类的内部状态不被外部修改。但是,为了使类的成员变量能够被外部访问和...
集合框架包括了多种接口和类,如Collection、List、Set、Map等,它们各自有特定的功能和用途。 1. **集合框架概述** - **容器简介**:集合框架就是一组接口和类,它们定义了存储、检索和操作对象的标准方式。这些...
Java集合排序及java集合类详解(Collection、List、Map、Set)讲解 Java集合框架是Java语言中最重要的组件之一,能够正确使用Java集合框架对于Java程序的开发具有无比的好处。本文将详细解释Java集合框架的实现原理、...
本文将详细讲解如何利用`set`容器对类进行排序,并探讨相关的关键知识点。 首先,`set`容器内部基于红黑树(Red-Black Tree)数据结构,保证了插入、删除和查找操作的时间复杂度为O(log n)。这意味着即使在大量元素...
### C#中的Get和Set详解:提升代码安全性与封装性 在C#编程语言中,`get` 和 `set` 是实现属性访问器的核心组成部分,它们不仅增强了代码的安全性,还提高了程序的封装性,是面向对象编程(OOP)的重要实践之一。本文...
本资源包含对STL中多种关键容器的详细讲解,包括Vector、Deque、sort、set、map等,这些都是C++程序员在实际开发中不可或缺的工具。 1. **Vector**:Vector是一个动态数组,它允许在任何位置插入和删除元素。其底层...
group.setName("尚学堂"); User user = new User(); user.setUsername("张三"); user.setAge(18); user.setGroup(group); request.setAttribute("user", user); return mapping.findForward("success"); } ...
get set方法生成注释和字段注释.zip,包括GetterSetterUtil.java、GetterSetterUtil.class、get set方法生成注释和字段注释.docx详细讲解如果用快捷方式生成set、get注释
下面是C语言文件操作函数大全的详细讲解: 1. 文件打开函数:fopen函数 fopen函数是C语言中用于打开文件的函数,格式为:fopen(文件名, 文件使用方式)。文件使用方式可以是“r”、“rb”、“w”、“wb”、“a”、...
C#中的get和set是访问器,用于控制类的私有成员(如字段)的访问。它们是构建属性的关键部分,属性是C#中一种特殊的方法,提供了对类内部数据的封装和保护。属性并不直接表示内存位置,而是提供了一种访问和修改对象...
本“C++编程视频详细讲解”是一套精心设计的教学资源,旨在帮助初学者和有一定基础的学习者深入理解和掌握C++的核心概念与实践技能。 视频教程通常采用直观易懂的方式,由专家亲自讲解,通过实例演示和针对性的指导...
Python 中的 dict 和 set 代码知识点讲解 dict 是 Python 中的一种内置数据结构,orthand for dictionary,用于存储键值对(key-value)。dict 的特点是可以快速查找和插入元素,不会随着元素的增加而变慢。下面是 ...
本篇文章将详细讲解GET和SET方法的原理,以及如何在VB中批量生成和使用它们。 GET方法在VB中用于获取对象的属性值。当你在代码中读取一个对象的属性时,实际上调用了该属性的GET方法。例如,如果你有一个名为`...
然而,在某些场景下,我们可能需要在运行时动态地添加或修改数据属性,这时就需要用到 `this.$set` 方法。`this.$set` 是 Vue 提供的一个全局方法,用于向响应式对象中添加新属性并确保该属性能触发视图更新。 案例...
在"OpenFlashChart实例 + 详细讲解"中,我们将深入探讨如何使用这个库来创建引人入胜的数据可视化效果。 首先,OpenFlashChart的基本使用涉及到在HTML中引入库文件,这通常是一个SWF文件和JavaScript文件。SWF文件...
REUSE_ALV_GRID_DISPLAY超详细讲解 REUSE_ALV_GRID_DISPLAY是一个功能强大的ABAP函数模块,主要用于在ABAP程序中显示ALV网格控件。该函数模块提供了大量的参数和事件,使得开发者可以根据需要自定义ALV网格控件的...
SNMP协议数据单元(PDUs)包括GetRequest、GetNextRequest、SetRequest、Trap和GetResponse。这些PDUs构成了SNMP的基本操作,如查询、修改配置和接收陷阱(Trap,即设备主动发送的报警信息)。 5. 管理信息结构SMI ...