Core Java Tutorial -,corejavatutorial
Core Java Tutorial -,corejavatutorial
Java HashSet 是 Set 接口最流行的实现。 java.util.HashSet
由一个HashMap
支持。HashSet
继承 AbstractSet
类并实现Set
、Cloneable
和 Serializable
接口。
1. Java HashSet
Java 中有关 HashSet 的一些重点有:
Java HashSet Constructors
Java HashSet 提供四个构造器:
1. public HashSet()
:创建一个新的空的 HashSet,由默认初始容量为 16,加载因子为 0.75 的 HashMap 支持。
2. public HashSet(int initialCapacity)
:创建一个新的空的 HashSet,由指定初始容量,加载因子为 0.75 的 HashMap 支持。
3. public HashSet(int initialCapacity, float loadFactor)
创建一个新的空的 HashSet,由指定初始容量,指定加载因子的 HashMap 支持。
4. public HashSet(Collection<? extends E> c)
:创建一个包含指定集合中元素的新 Set。 支持 HashMap 是使用默认加载因子(0.75)创建的,并且初始容量足以包含指定集合中的所有元素。
下面的代码片段显示了所有这些 HashSet 构造函数的示例用法。
package HashSet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class HashSetTest {
public static void main(String[] args) {
Set<String> set;
//initial capacity should be power of 2
set = new HashSet<>(32);
//setting backing HashMap initial capacity and load factor
set = new HashSet<>(32, 0.80f);
//creating HashSet from another Collection
Set<String> set1 = new HashSet<>(set);
Set<String> set2 = new HashSet<>(new ArrayList<>());
}
}
Java HashSet Methods
一些有用的 HashSet 方法:
1. public boolean add(E e)
:将给定的元素添加到 Set 中(如果该元素在 Set 不存在的话)。此方法内部使用 equals()
方法来检查重复项,因此请确保你的对象正确定义 equals()
方法。
2. public void clear()
:删除 Set 中的所有元素。
3. public Object clone()
:返回 Set 示栗的浅拷贝。
4. public boolean contains(Object o)
:如果 Set 包含给定元素返回 true,否则返回 false。
5. public boolean isEmpty()
:如果 Set 不包含任何元素,则返回 true,否则返回 false。
6. public Iterator<E> iterator()
:返回此 Set 中元素的迭代器。元素以特定顺序返回。
7. public boolean remove(Object o)
:从此 Set 中移除给定元素,如果存在则返回 true。如果元素不在集合中,则返回 false。
8. public int size()
:返回 Set 中元素的数量。
9. public Spliterator<E> spliterator()
:在此集合中的元素上创建一个后期绑定和快速失败的 Spliterator。这是在 Java 8 中引入的,但直到现在我都没用过他。
10. public boolean removeAll(Collection<?> c)
:HashSet 从 AbstractSet 继承此方法。此方法将删除属于指定集合一部分的集合中的所有元素。
Java HashSet Example
Java HashSet 示栗程序展示了 HashSet 的通常用法。
package HashSet;
import java.util.*;
public class HashSetExample {
public static void main(String[] args) {
Set<String> fruits = new HashSet<>();
// add example
fruits.add("Apple");
fruits.add("Banana");
// isEmpty example
System.out.println("fruits set is empty = " + fruits.isEmpty());
// contains example
System.out.println("fruits contains Apple = " + fruits.contains("Apple"));
System.out.println("fruits contains Mango = " + fruits.contains("Mango"));
// remove example
System.out.println("Apple removed from fruits set = " + fruits.remove("Apple"));
System.out.println("Mango removed from fruits set = " + fruits.remove("Mango"));
// size example
System.out.println("fruits set size = " + fruits.size());
// addAll example
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Apple");
list.add("Banana");
list.add("Mango");
System.out.println("fruits set before addAll = " + fruits);
System.out.println("list = " + list);
fruits.addAll(list);
System.out.println("fruits set after addAll = " + fruits);
// iterator example
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
System.out.println("Consuming fruit " + iterator.next());
}
// removeAll example
fruits.add("Orange");
System.out.println("fruits set before removeAll = " + fruits);
System.out.println("list = " + list);
fruits.removeAll(list);
System.out.println("fruits set after removeAll = " + fruits);
// clear example
fruits.clear();
System.out.println("fruits set is empty = " + fruits.isEmpty());
}
}
上面的 HashSet 示例程序的输出如下
fruits set is empty = false
fruits contains Apple = true
fruits contains Mango = false
Apple removed from fruits set = true
Mango removed from fruits set = false
fruits set size = 1
fruits set before addAll = [Banana]
list = [Apple, Apple, Banana, Mango]
fruits set after addAll = [Apple, Mango, Banana]
Consuming fruit Apple
Consuming fruit Mango
Consuming fruit Banana
fruits set before removeAll = [Apple, Mango, Orange, Banana]
list = [Apple, Apple, Banana, Mango]
fruits set after removeAll = [Orange]
fruits set is empty = true
Java HashSet ConcurrentModificationException Example
Java HashSet 迭代器是快速失败的,所以如果 Set 在结构上被修改,则方法将抛出 java.util.ConcurrentModificationException
。下面是一个简单的例子来说明这一点。
package HashSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class HashSetConcurrentModificationExceptionExample {
public static void main(String[] args) {
Set<String> fruits = new HashSet<>();
// add example
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
fruits.add("Mango");
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println("Processing " + fruit);
// wrong way of removing from Set, can throw java.util.ConcurrentModificationException
if ("Orange".equals(fruit)) fruits.remove("Orange");
}
}
}
上面程序运行后将得到以下输出和异常
Processing Apple
Processing Mango
Processing Orange
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442)
at java.util.HashMap$KeyIterator.next(HashMap.java:1466)
at HashSet.HashSetConcurrentModificationExceptionExample.main(HashSetConcurrentModificationExceptionExample.java:20)
注意!HashSet 元素不保证是有序的,调用 iterator.next()
将抛出 ConcurrentModificationException
异常。所以如果”Orange”是迭代器中的最后一个,则不会得到异常,因为 iterator.hasNext()
将返回 false,且不会调用 iterator.hasNext()
我们应该总是使用 Iterator 方法进行结构修改,如下所示:
package HashSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class HashSetConcurrentModificationExceptionExample2 {
public static void main(String[] args) {
Set<String> fruits = new HashSet<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
fruits.add("Mango");
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println("Processing " + fruit);
// correct way of structural modification of Set
if ("Orange".equals(fruit)) {
iterator.remove();
}
}
System.out.println("fruits set after iteration = " + fruits);
}
}
上面 HashSet 迭代器栗子不会抛出异常,你会得到下面的输出:
Processing Apple
Processing Mango
Processing Orange
Processing Banana
fruits set after iteration = [Apple, Mango, Banana]
Java HashSet to Array Example
有时我们必须将 HashSet 转换为数组,反之亦然。下面是一个简单的程序,显示将 HashSet 转换为数组,然后将 Array 转换为 HashSet 的正确方法。
package HashSet;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class HashSetToArrayExample {
public static void main(String[] args) {
Set<Integer> ints = new HashSet<>();
for (int i = 0; i < 10; i++) {
ints.add(i);
}
System.out.println("ints set = " + ints);
// set to array example
Integer[] intArray = new Integer[ints.size()];
intArray = ints.toArray(intArray);
System.out.println("intArray = " + Arrays.toString(intArray));
ints.remove(0);
ints.remove(1);
System.out.println("intArray = " + Arrays.toString(intArray));
// array to set example
ints = new HashSet<>(Arrays.asList(intArray));
System.out.println("ints from array = " + ints);
ints.remove(0);
ints.remove(1);
System.out.println("ints from array after remove = " + ints);
System.out.println("intArray = " + Arrays.toString(intArray));
}
}
上面 HashSet 转数组的栗子输出如下:
ints set = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
intArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
intArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ints from array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ints from array after remove = [2, 3, 4, 5, 6, 7, 8, 9]
intArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Java HashSet to List Example
Set 和 List 之间没有太大的区别,但有时候我们必须将 Set 转换为 Set 或 List 转换为 Set。面是一个简单的例子,显示了将 Set 转换为为 List,将List 设置为 Set 的正确方法。
package HashSet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class HashSetToListExample {
public static void main(String[] args) {
Set<String> vowels = new HashSet<>();
vowels.add("a");
vowels.add("e");
vowels.add("i");
//set to list example
List<String> vowelsList = new ArrayList<>(vowels);
System.out.println("vowels set = " + vowels);
System.out.println("vowelsList = " + vowelsList);
vowels.add("o");
vowelsList.add("a");
vowelsList.add("u");
System.out.println("vowels set = " + vowels);
System.out.println("vowelsList = " + vowelsList);
//list to set example
vowels = new HashSet<>(vowelsList);
System.out.println("vowels set = " + vowels);
}
}
Java HashSet equals() and hashCode() methods
HashSet 利用 HashMap 来存储它的元素。当i尝试添加元素时,HashSet 用 equals()
和 hashCode()
方法检查重复元素。让我们看看,如果你的 Set 对象没有提供 equals()
方法实现会发生什么。
package HashSet;
import java.util.HashSet;
import java.util.Set;
public class HashSetEqualsMethodImportance {
public static void main(String[] args) {
Set<Emp> emps = new HashSet<>();
emps.add(new Emp(1, "Pankaj"));
emps.add(new Emp(2, "David"));
emps.add(new Emp(1, "Pankaj"));
System.out.println(emps);
}
}
class Emp {
private String name;
private int id;
public Emp(int i, String n) {
this.id = i;
this.name = n;
}
@Override
public String toString() {
return "{" + id + "," + name + "}";
}
}
当我们运行上面程序,我们将得到以下输出:
[{2,David}, {1,Pankaj}, {1,Pankaj}]
所以看起来我们能够在 Set 中存储重复元素。其实不是,这是因为 Emp 类没有定义 equals()
方法,因此使用了 Object 类的 equals()
方法实现。Object 类的 equals
方法定义如下:
public boolean equals(Object obj) {
return (this == obj);
}
所以当添加一个新元素时,对象引用被检查而不是内容。因此,我们拥有重复内容的对象,但它们具有不同的引用。让我们看看当我们在 Emp 类中定义 equals()
和 hashCode()
方法后会发生什么。
package HashSet;
import java.util.HashSet;
import java.util.Set;
public class HashSetEqualsMethodImportance2 {
public static void main(String[] args) {
Set<Emp> emps = new HashSet<>();
emps.add(new Emp(1, "Pankaj"));
emps.add(new Emp(2, "David"));
emps.add(new Emp(1, "Pankaj"));
System.out.println(emps);
Emp e = new Emp(3, "Lisa");
emps.add(e);
System.out.println(emps);
//set values to make it duplicate
e.setId(1);
System.out.println(emps);
e.setName("Pankaj");
System.out.println(emps);
}
}
class Emp {
private String name;
private int id;
public Emp(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof Emp)) return false;
Emp emp = (Emp) o;
if (emp.getId() == this.getId() && this.getName().equals(emp.getName())) return true;
return false;
}
@Override
public int hashCode() {
return getId();
}
@Override
public String toString() {
return "{" + getId() + "," + getName() + "}";
}
}
输出如下:
[{1,Pankaj}, {2,David}]
[{1,Pankaj}, {2,David}, {3,Lisa}]
[{1,Pankaj}, {2,David}, {1,Lisa}]
[{1,Pankaj}, {2,David}, {1,Pankaj}]
注意,当我们尝试添加一个元素时,HashSet 能够检查重复。但是我们可以使用 setter 方法更改对象值并使其重复。它的工作原理是因为 Set 上没有完成任何操作。这就是为什么不可变对象更适合于 Set 和 Map。
相关文章
- 暂无相关文章
用户点评