3.常用集合——Set集合、哈希表
i.AbstractSet<E>(1.2)类和AbstractMap<K,V>(1.2)相关:
Set和Map部分需要进行比较方式讲解可能更能够理解里面每一种集合的用法
1)HashSet<E>(1.2)、HashMap<K,V>(1.2)和HashTable<K,V>(1.0)
HashSet<E>(1.2)类:
public classHashSet<E>extendsAbstractSet<E>implementsSet<E>,Cloneable,Serializable
该类实现了接口Set,由哈希表支持[实际是一个HashMap实例],它不保证集合的迭代顺序,特别是不保证顺序恒久不变,但是允许null元素。对该集合迭代使用的时间和HashSet实例的大小(元素的数量)和底层的HashMap实例(桶的数量)的“容量”的和成比例,如果迭代性在程序设计的时候很重要,不要将初始化容量设置得太高。该实现不是同步的,而且其遍历方法等同于数组,都是快速失败的,若需要对该集合进行同步方法就需要调用下边的方法:
Set s = Collections.synchronizedSet(newHashSet(...));
HashMap<K,V>(1.2)类:
public classHashMap<K,V>extendsAbstractMap<K,V>implementsMap<K,V>,Cloneable,Serializable
该类是基于哈希表的Map接口实现,此实现提供了所有可选的映射操作,并且允许使用null值和null键。(除了非同步和允许使用null之外,HashMap类和Hashtable类大致相同。),同样的该类不保证映射的顺序,特别是它不保证该顺序恒久不变。HashMap的实例有两个影响性能的参数:初始容量和加载因子
容量是哈希表中的桶的数量,初始容量就是哈希表在创建的时候的容量。
加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。
当哈希表中的条目数超出了加载因子和当前容量的乘积的时候,需要针对哈希表结构进行重建操作,而哈希表内部具有大约两倍的桶数目。
Hashtable<K,V>(1.0)类:
public classHashtable<K,V>extendsDictionary<K,V>implementsMap<K,V>,Cloneable,Serializable
该类是HashMap的前身,主要特点和HashMap<K,V>差不多,但是有一点点区别就是:键和值都不允许使用null,而且该类的实现是线程同步的。
先看几个简单的例子,再来考虑它们相互之间的一些区别和联系
——[1]HashSet<E>的基本例子——
packageorg.susan.java.collection;
importjava.util.Arrays;
importjava.util.HashSet;
importjava.util.Iterator;
importjava.util.Set;
/**
*一个使用HashSet的简单例子
**/
public classHashSetDemo {
public static voidmain(Stringargs[]){
HashSet<String> set =newHashSet<String>();
set.add("A");
set.add("B");
set.add("C");
set.add("B");
set.add("D");
printSet(set);
System.out.println();
String[] strArray = {"E","F","G"};
set.addAll(Arrays.asList(strArray));
printSet(set);
}
private static voidprintSet(Set<String> set){
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
System.out.print("["+ iterator.next() +"],");
}
}
}
根据上边这段代码可以得到下边的输出:【*:因为集合本身是无序的,而且迭代不保证顺序,有可能输出的顺序不一样,但是集合元素的内容应该是相同的。】
[D],[A],[B],[C],
[D],[E],[F],[G],[A],[B],[C],
——[2]从HashSet<E>里面删除某个元素——
packageorg.susan.java.collection;
importjava.util.HashSet;
importjava.util.Iterator;
importjava.util.Set;
/**
*HashSet的删除方法remove(Object obj)
**/
public classHashSetDemo {
public static voidmain(Stringargs[]){
HashSet<Integer> set =newHashSet<Integer>();
set.add(newInteger(12));
set.add(newInteger(33));
set.add(55);
set.remove("B");
set.remove(12);
printSet(set);
}
private static voidprintSet(Set<Integer> set){
Iterator<Integer> iterator = set.iterator();
while(iterator.hasNext()){
System.out.print("["+ iterator.next() +"],");
}
}
}
先看上边这段代码的结果:
[33],[55],
【*:与ArrayList的结果有区别的是,该remove方法只有一个参数Object,而且没有重载形式,因为HashSet本身是无序的,所以和ArrayList不一样的是,不支持索引,所以在删除的时候,进行了一次自动拆解箱的操作。注意代码set.remove(12),这个代码传入的是12的原始类型,但是在这个过程里面转换成为了Integer的类型。如果这一段是ArrayList类型而不是HashSet类型,就会抛出异常,因为ArrayList有一个带int类型的重载方法,是删除某个索引位置的元素,而且HashSet的remove方法如果删除失败的话不会抛出异常,因为是返回的一个特殊值false,这一点可以直接在代码中修改set.remove("B")为System.out.println(set.remove("B"))来验证】
——[3]HashMap<K,V>的不同遍历——
packageorg.susan.java.collection;
importjava.util.Collection;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Set;
importjava.util.Map.Entry;
/**
*使用HashMap的基本例子
**/
public classHashMapDemo {
public static voidmain(Stringargs[]){
HashMap<Integer,String> map =newHashMap<Integer,String>();
map.put(1,"One");
map.put(2,"Two");
map.put(3,"Three");
map.put(4,"Four");
//键遍历
System.out.println("------Key Iterator------");
Set<Integer> keys = map.keySet();
Iterator<Integer> iterator = keys.iterator();
while(iterator.hasNext()){
Integer key = iterator.next();
System.out.print("[Key:"+ key +"--");
System.out.println("Value:"+ map.get(key) +"]");
}
// 值遍历
System.out.println("------Value Iterator------");
Collection<String> values = map.values();
Iterator<String> vIterator = values.iterator();
while(vIterator.hasNext()){
Stringvalue = vIterator.next();
System.out.println("[Value:"+ value +"]");
}
//映射关系遍历
System.out.println("------Entry Iterator------");
Set<Entry<Integer,String>> set = map.entrySet();
Iterator<Entry<Integer,String>> sIterator = set.iterator();
while(sIterator.hasNext()){
Entry<Integer,String> entry = sIterator.next();
System.out.print("[Key:"+ entry.getKey() +"--");
System.out.println("Value:"+ entry.getValue() +"]");
}
}
}
这里提供了三种不同的方式遍历,有几点需要说明:
- 通过键遍历的时候,键使用的返回是Set<E>,因为键是一个不重复的,所以为了保证键的不重复性,设计的时候使用的Set<E>
- 通过值遍历的时候,值使用的时候返回是Collection<E>,因为该集合是可以重复的,而且不需要保证值的不重复性
- 通过关系遍历的时候,使用的格式需要注意Entry是Map的内部类Map.Entry,而且每一个项的类型需要注意
- 只能通过Map的键去获取值,不能通过Map的值去获取键
下边是这段程序的输出:
------Key Iterator------
[Key:1--Value:One]
[Key:2--Value:Two]
[Key:3--Value:Three]
[Key:4--Value:Four]
------Value Iterator------
[Value:One]
[Value:Two]
[Value:Three]
[Value:Four]
------Entry Iterator------
[Key:1--Value:One]
[Key:2--Value:Two]
[Key:3--Value:Three]
[Key:4--Value:Four]
——[4]Hashtable<K,V>的简单用法——
packageorg.susan.java.collection;
importjava.util.Enumeration;
importjava.util.Hashtable;
public classHashtableDemo {
public static voidmain(Stringargs[]){
Hashtable<Integer,String> tables =newHashtable<Integer,String>();
tables.put(1,"One");
tables.put(2,"Two");
tables.put(3,"Three");
Enumeration<Integer> iterator =null;
for(iterator = tables.keys();iterator.hasMoreElements();){
Integer key = iterator.nextElement();
System.out.print("[Key:"+ key +"--");
System.out.println("Value:"+ tables.get(key) +"]");
}
}
}
上边代码的程序输出:
[Key:3--Value:Three]
[Key:2--Value:Two]
[Key:1--Value:One]
【*:从上边的代码段可以看出,HashMap和Hashtable没有太多的区别,所以这段代码仅仅提供Hashtable的键遍历方式就可以了,至于遍历是使用for还是使用while,这个可以根据本身的情况自行选择。而且需要注意一点是HashMap在遍历的时候返回的迭代器是Iterator,而Hashtable返回的迭代器是Enumeration。】
上边的代码段都是1.5过后带泛型的代码段,下边提供一段老版本(1.4或者1.4以下的版本)的写法:
packageorg.susan.java.collection;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Map.Entry;
public classOleMap {
public static voidmain(Stringargs[]){
HashMap map =newHashMap();
map.put(1,"One");
map.put(2,"Two");
Iterator iterator = map.entrySet().iterator();
while(iterator.hasNext())
{
Entry entry = (Entry)iterator.next();
System.out.print("[Key:"+ entry.getKey() +"--");
System.out.println("Value:"+ entry.getValue()+"]");
}
}
}
这段代码的输出这里不列出来了,老版本的写法没有泛型概念,就会出现一个类型的强制转换过程,在理解的时候可能简单很多,不过这种写法用1.5编译的时候会存在很多类型检查的警告。
上边已经基本接触了Hashtable和HashMap,总结一下这两个的特点和相互之间的区别,因为HashSet本身不是一个映射表的概念,就可以当作一个普通的Set集合的实现来使用,所以HashSet加入比较是没有太大的实际意义:
- 返回的迭代器不一样:Hashtable返回的迭代器是Enumeration,而HashMap返回的迭代器是Iterator
- HashMap不是同步的,而Hashtable是线程同步的,意思就是说前者是线程不安全的,系统开销比较小;后者是线程安全的,开销相对大点点
- HashTable不允许null键和null值,而HashMap是允许null键和null值的
- HashTable有一个contains(Object value)方法和containsValue(Object value)的功能是一模一样的
最后再介绍一下上边代码没有涉及到的常用方法:
HashMap<K,V>类:
booleancontainsKey(Object key):如果该映射里面包含了指定的一个键的映射关系返回为true,反之返回为false
booleancontainsValue(Object value):如果该映射里面包含了指定的一个或者多个值的映射关系,返回为true,反之返回为false
voidputAll(Map<?extendsK,?extendsV> m):不单独复制某个映射关系,而是直接把一个映射关系复制到某个映射里面,类似集合中的addAll方法
Hashtable<K,V>类:
booleancontains(Object value):如果该映射里面包含了指定的一个或者多个值的映射关系,返回为true,反之返回为false
booleancontainsKey(Object key):如果该映射里面包含了指定的一个键的映射关系返回为true,反之返回为false
booleancontainsValue(Object value):如果该映射里面包含了指定的一个或者多个值的映射关系,返回为true,反之返回为false
Enumeration<V>elements():返回哈希表中的值的枚举
Collection<V>values():返回哈希表中的值的集合
Enumeration<K>keys():返回哈希表中的键的枚举
Set<K>keySet():返回哈希表中的键的集合
protected voidrehash():重组该hash表。
这里注意区分返回为键枚举以及键集合的方法和返回为值枚举和值集合的方法【elements() && values();keys() && keySet()】
2)TreeSet<E>(1.2)类TreeMap(K,V>(1.2)类:
上边介绍的HashSet和HashMap都是无序的,接下来介绍两个有序的映射:
TreeSet<E>(1.2)类:
public classTreeSet<E>extendsAbstractSet<E>implementsNavigableSet<E>,Cloneable,Serializable
基于TreeMap的NavigableSet实现,使用元素的自然顺序对元素进行排序,或者根据创建的Comparator进行排序。
——[$]TreeSet简单例子——
packageorg.susan.java.collection;
importjava.util.Iterator;
importjava.util.TreeSet;
/**
*TreeSet集合的一个例子
**/
public classTreeSetDemo {
public static voidmain(Stringargs[]){
TreeSet<Integer> tree = new TreeSet<Integer>();
tree.add(22);
tree.add(11);
tree.add(33);
tree.add(44);
System.out.println(tree);
Iterator<Integer> iterator = tree.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() +",");
}
System.out.println();
iterator = tree.descendingIterator();
while(iterator.hasNext()){
System.out.print(iterator.next() +",");
}
}
}
上边这段代码演示了TreeSet的基本用法,其实TreeSet有一个很大的特点,不论用什么样子的方式将元素添加到这个集合里面,这个集合里面的元素总是通过某个比较器进行了排序操作的,可以看下边的输出:
[11, 22, 33, 44]
11,22,33,44,
44,33,22,11,
从上边的结果可以知道,TreeSet本身就是已经排好序的集合,所以正序遍历结果和本身内部的结果一样的顺序,虽然添加的时候是22,11,33,44。至于TreeSet的方法,大部分和Set差不多,这里不做详细介绍,有兴趣的可以去查阅以下API。
——[$]TreeMap简单例子——
介于红黑树(Red-Block tree)的NavigableMap实现,该映射根据键的自然排序进行排序,或者根据键的Comparator进行排序
packageorg.susan.java.collection;
importjava.util.Iterator;
margin-top: 0px; margin-bottom:
分享到:
Global site tag (gtag.js) - Google Analytics
相关推荐
Java集合框架是Java编程语言中一个至关重要的组成部分,它为数据存储和操作提供了丰富的类库。泛型是Java 5引入的一项创新特性,极大地增强了集合框架的安全性和效率。本讲解将深入探讨这两个主题,以及与之相关的...
Java集合框架是Java编程语言中不可或缺的一部分,它提供了...总的来说,Java集合、泛型和枚举是构建复杂数据结构和实现业务逻辑的关键工具。熟练掌握这些概念和它们的使用方法,将极大地提升Java编程的效率和代码质量。
1. **泛型**:泛型是Java 5引入的最重要的特性之一,它允许在类、接口和方法中使用类型参数,从而实现了类型安全的集合操作。泛型的主要优点是避免了类型转换的麻烦,消除了运行时的类型异常。例如,ArrayList可以...
Java集合框架中的泛型使用包括: - **限定类型参数**:通过 `<T extends SomeClass>` 定义类型参数的上限,保证添加到集合的元素是SomeClass或其子类。 - **通配符**:如 `?` 和 `? extends SomeClass`,用于限制...
在Java编程语言中,枚举和泛型是两种非常重要的特性,它们分别提供了对特定数据类型和类型安全的集合操作的支持。下面我们将详细探讨这两个主题。 **枚举(Enum)** 枚举类型是Java 5.0引入的新特性,它允许开发者...
枚举(Enum)和泛型(Generic)是Java编程语言中的两种强大特性,它们极大地提升了代码的可读性、安全性和复用性。本篇文章将深入探讨这两种概念及其在实际应用中的示例。 首先,我们来看枚举。枚举是一种预定义的...
### Java语言基础入门教程知识点详解 ...枚举和泛型是Java语言中非常重要的两个概念。枚举提供了一种定义固定集合的有效方式,而泛型则提高了代码的灵活性和安全性。掌握这两种特性能够帮助开发者写出更高质量的代码。
【网络程序设计】和【Java】的领域中,泛型和枚举是两个重要的概念,它们极大地提高了代码的复用性和安全性。 **泛型** 泛型是Java中引入的一种强大的类型系统特性,允许我们在编程时定义类型参数化的类、接口和...
泛型可以应用于集合框架、自定义类、接口和方法等场景,是Java编程中的高级特性。本部分内容将详细介绍泛型的基本概念、定义、用法和规则限制等。 首先,泛型的基本概念是“参数化类型”,它允许程序员在不明确指定...
FileList.java 自己实现的一个文件名称枚举类 MyDataIO.java 数据输入输出示例 MyFileOutput.java 将键盘读入的文字保存到文件 MyPipedIO.java 管道流示例 MySequenceIn.java 顺序输入流示例 ObjectFileTest....
Java 5 泛型是Java编程语言中一个重要的里程碑,它引入了类型安全的集合,大大增强了代码的可读性和可维护性。泛型在Java 5中首次亮相,为开发者提供了一种方式来限制集合(如List、Set、Map等)中可以存储的数据...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入,极大地增强了代码的类型安全性和重用性。本压缩包包含了一些关于Java泛型的实例,旨在帮助学习者深入理解和应用这一特性。 泛型的...
9. 泛型与枚举:泛型也可以应用于枚举类型,允许枚举实例持有或操作特定类型的数据,增强了枚举的表达能力。 10. 泛型与异常:在抛出或捕获异常时,也可以使用泛型,例如`throw new IllegalArgumentException...
泛型枚举是Java中的一种枚举类型,它允许在枚举类型中定义泛型参数。泛型枚举可以使枚举类型更加灵活和通用。 在Java中,枚举类型可以使用泛型参数,例如: ```java public enum Color<T> { RED, GREEN, BLUE; ...
这使得枚举成为定义常量集合的最佳选择。 示例1展示了如何定义枚举类`Action`,并且在`doAction`方法中使用枚举值作为参数。这样,编译器会自动检查传入的参数是否是枚举中的有效值,避免了无效输入导致的错误。...
如同C++中的模板,Java的泛型允许开发者定义泛型类、泛型接口以及泛型方法,使得在不指定具体类型的情况下,代码依然能处理任意类型的对象。例如,Java的ArrayList、HashMap等集合类就是泛型的应用实例,它们允许...
枚举在Java中不仅是一个类,还是一种特殊的类型,允许我们定义自己的常量集合。接下来,我们将深入探讨Java枚举类型的使用方法及其相关知识点。 1. **枚举的声明与初始化** 枚举类型的声明方式类似于类,但以`enum...
在Java中,集合框架的泛型操作包括添加、删除、查找和遍历元素。这些操作在运行时会进行类型检查,确保插入的元素与集合的泛型类型匹配。在"Demo"中,可能演示了如何通过泛型安全地操作Set等集合类。 7. **通配符*...
Java集合与数据结构是编程中不可或缺的基础知识,尤其在Java编程中扮演着核心角色。这个压缩包文件包含了一系列关于这主题的PDF文档,涵盖了广泛的知识点。以下是对这些主题的详细解析: 1. **栈和队列**: 栈是一...