认识Java Collections (三)

本文介绍了Java中Set接口的基本概念及其三种实现:HashSet、TreeSet和LinkedHashSet。探讨了如何利用这些集合去除重复项,并提供了基本操作和批量操作的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[size=medium][b]Set Interface[/b][/size]

除了不能添加重复元素外,set也添加了一些强约束,在执行equals和hashCode方法,这使得集合可以进行有意义的比较操作,即使他们的实现类型不同。
一个Set接口的声明如下:

public interface Set<E> extends Collection<E> {
// Basic operations
int size();
boolean isEmpty();
boolean contains(Object element);
boolean add(E element); //optional
boolean remove(Object element); //optional
Iterator<E> iterator();

// Bulk operations
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c); //optional
boolean removeAll(Collection<?> c); //optional
boolean retainAll(Collection<?> c); //optional
void clear(); //optional

// Array Operations
Object[] toArray();
<T> T[] toArray(T[] a);
}



Java平台包含3个通用的set实现:HashSet,TreeSet和LinkedHashSet。HashSet将元素存储在一张hash表中,一般来说,这是set的最优实现。但是它并不关心数据的存储顺序。
TreeSet将元素存储在一棵红黑树中,数据的顺序按照元素的值排列。总体上说,它的性能略低于HashSet。LinkedHashSet使用一个linked list贯穿整个set,并且按照插入顺序排列,由于要处理HashSet的无序性,所以要花费稍微高一些的代价。

以下是一些简单但是很实用的有关set的习惯用法。
假设你有一个结合c,你想创建另一个集合,包含c中的全部元素,并移除所有重复元素,下面的一行代码可以展示这个技巧:

Collection<Type> noDups = new HashSet<Type>(c);

以下是一个小小的变种,它将保留原集合的元素顺序:

Collection<Type> noDups = new LinkedHashSet<Type>(c);

下面是一个泛型方法,它包装了上一行代码:

public static <E> Set<E> removeDups(Collection<E> c) {
return new LinkedHashSet<E>(c);
}



2.Set 的基本操作
size()方法返回set的元素数量(也称作set的基)。isEmpty的功能正如其名字描述的那样。而add方法则会在添加时检查待添加元素是否已经存在于集合中。
下面的程序示例将演示Set的基本用法,该程序将统计程序参数字符串中的重复单词,并生成一个包含非重复单词的集合
import java.util.*;

public class FindDups {
public static void main(String[] args) {
Set<String> s = new HashSet<String>();
for (String a : args)
if (!s.add(a))
System.out.println("Duplicate detected: " + a);

System.out.println(s.size() + " distinct words: " + s);
}
}

现在运行程序:
java FindDups i came i saw i left
得到输出结果:
Duplicate detected: i
Duplicate detected: i
4 distinct words: [i, left, saw, came]
[color=red]
注意:[/color] 在上面的代码中,我们使用接口类型(Set)而不是实现类型(HashSet)来引用我们的HashSet实例。这是一种[b]强烈[/b]推荐的编程习惯,这样做可以给予程序更多的柔韧性,因为你可以通过仅仅更改构造器来将程序的实现更改。(比如你可以很容易的做出一个ArrayList版本的例子,仅仅需要改变以下构造器即可)。
此外,程序是否可以成功运行也得不到保证。因为程序使用了一个在早期版本中编写的非标准操作方法,而在新的版本中此方法并没有被实现,那么程序就会失败。使用接口来引用实例,可以使你不会使用非标准方法。

3. Bulk Operations
这里,假设有两个set s1与s2
s1.containsAll(s2) s2是否为s1子集
s1.addAll(s2) s1与s2的并集
s1.removeAll(s2) 将s1中也属于s2的元素去掉
s1.retainAll(s2) s1与s2的交集

如果希望在不破坏原有集合的基础上进行以上操作,需要对目标集合进行以此copy,下面是常用的代码:
Set<Type> union = new HashSet<Type>(s1);
union.addAll(s2);

Set<Type> intersection = new HashSet<Type>(s1);
intersection.retainAll(s2);

Set<Type> difference = new HashSet<Type>(s1);
difference.removeAll(s2);


4.数组操作
与Collection的数组操作一致

(to be continued...)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值