
Collection 概述和使用Collection 的元素;Set 和 List)实现类(如上图)。Collection 类型;ArrayList 创建。| 方法名 | 说明 |
|---|---|
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
boolean removeIf(Object o) | 根据条件进行移除 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定的元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
需要注意的是,下面代码主要为了演示在接口 Collection 的各实现类中都有上述表格中的方法,且在个实现类中这些方法在使用上基本一致,因此使用多态的方式(即父类引用指向子类对象)进行了代码演示,在实际的使用中,一般都是本类型的引用指向本类型的对象。
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Predicate;
public class Test {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<>();
collection.add("William");
collection.add("Shakespeare");
collection.add("the");
collection.add("greatest");
collection.add("playwright.");
System.out.println(collection); // [William, Shakespeare, the, greatest, playwright.]
boolean william = collection.remove("William");
System.out.println(william); // true
boolean kant = collection.remove("Kant");
System.out.println(kant); // false
// Lambda
collection.removeIf(
(String string) -> {
return string.length() == 3;
}
);
System.out.println(collection); // [Shakespeare, greatest, playwright.]
// Anonymous
collection.removeIf(new Predicate<String>() {
@Override
public boolean test(String string) {
return string.length() == 8;
}
});
System.out.println(collection); // [Shakespeare, playwright.]
boolean shakespeare = collection.contains("Shakespeare");
System.out.println(shakespeare); // true
boolean empty = collection.isEmpty();
System.out.println(empty); // false
int size = collection.size();
System.out.println(collection); // [Shakespeare, playwright.]
System.out.println(size); // 2
collection.clear();
System.out.println(collection); // []
}
}
关于上述
removeIf()方法中 Lambda 表达式格式的理解,可以结合如下的源码:
ArrayList中的removeIf()方法继承自Collection接口;removeIf()方法接收一个Predicate类型的形式参数;Predicate的源码显示这是一个接口,且只有一个抽象方法test(),因此该接口满足使用 Lambda 表达式的前提条件;test()抽象方法的形式参数为泛型,Lambda 表达式中的形式参数和集合中保存的元素一致即可,即为String,返回值需要和抽象方法test()的一致,即为boolean;removeIf()方法会使用一个迭代器对象遍历集合中的所有元素,针对每次遍历得到的元素,都会使用test()方法判断该元素是否满足删除条件,如果满足则将该元素删除。
public interface Collection<E> extends Iterable<E> {
......
/**
* Removes all of the elements of this collection that satisfy the given
* predicate. Errors or runtime exceptions thrown during iteration or by
* the predicate are relayed to the caller.
*
* @implSpec
* The default implementation traverses all elements of the collection using
* its {@link #iterator}. Each matching element is removed using
* {@link Iterator#remove()}. If the collection's iterator does not
* support removal then an {@code UnsupportedOperationException} will be
* thrown on the first matching element.
*
* @param filter a predicate which returns {@code true} for elements to be
* removed
* @return {@code true} if any elements were removed
* @throws NullPointerException if the specified filter is null
* @throws UnsupportedOperationException if elements cannot be removed
* from this collection. Implementations may throw this exception if a
* matching element cannot be removed or if, in general, removal is not
* supported.
* @since 1.8
*/
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
......
}
/**
* Represents a predicate (boolean-valued function) of one argument.
*
* This is a functional interface
* whose functional method is {@link #test(Object)}.
*
* @param the type of the input to the predicate
*
* @since 1.8
*/
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
......
// All other methods are either default or static
}
Iterator iterator() 方法可得到此集合元素的迭代器对象,该对象默认指向当前集合索引为 0 的元素位置。boolean hasNext():判断当前位置是否有元素可以被取出;E next():首先获取当前位置的元素,然后将迭代器对象移向下一个索引位置;void remove():删除迭代器对象当前指向的元素。import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<>();
collection.add("William");
collection.add("Shakespeare");
collection.add("the");
collection.add("greatest");
collection.add("playwright.");
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if ("playwright.".equals(next)) {
iterator.remove();
}
System.out.println(next);
}
System.out.println(collection); // [William, Shakespeare, the, greatest]
}
}
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
......
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
......
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
......
/**
* Returns an iterator over the elements in this list in proper sequence.
*
* The returned iterator is fail-fast.
*
* @return an iterator over the elements in this list in proper sequence
*/
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
// prevent creating a synthetic constructor
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
......
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
......
}
List 概述和使用List 是接口,不能直接使用,该接口两个主要的实现类为 ArrayList 和 LinkedList ;List 接口的实现类所创建的对象都是有序集合,这里的有序指的是存取顺序;Set 接口的实现类不同,List 接口的实现类所创建的集合中允许存在重复的元素;List 接口的实现类所创建的对象不仅支持通过整数索引的方式直接访问任意元素,还支持根据索引位置插入元素。上述介绍的 Collection 接口中的常用方法适用于集合体系中 Collection 继承条线的所有实现类,以下的方法仅仅适用于继承自 Collection 接口的 List 接口的实现类,如:ArrayList 和 LinkedList :
| 方法名 | 描述 |
|---|---|
void add(int index, E element) | 在此集合中的指定位置插入指定的元素,原来位置索引的元素会后移 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index, E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
ArrayList 源码分析下面以首先创建一个空的
ArrayList后,再往其中添加一个元素的过程为例,分析ArrayList典型方法的底层源码,在这个过程中主要主要介绍一下几点事实:
ArrayList动态数组底层是通过数组的方式来实现的;- 通过
ArrayList空参构造方法ArrayList()创建的动态数组对象,其底层存储数据的容器是一个长度为零的数组;- 在第一次尝试调用
add(E e)方法向使用空参构造方法创建的ArrayList对象中添加元素时,ArrayList底层会先将存储数据的数组容器扩容至长度为 10 ,然后再将元素添加至扩容后数组的第一个索引位置;- 此后,当
ArrayList对象底层的数组容器已满时,如果还希望调用add(E e)方法向其中添加元素,那么ArrayList对象底层的数组容器会先扩容原先的 1.5 倍,然后再向其中添加新的元素。
elementData 成员变量,这是一个元素类型为 Object 的数组;ArrayList() 时,elementData 指向 DEFAULTCAPACITY_EMPTY_ELEMENTDATA ,后者是一个空数组。public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
......
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
......
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
......
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
......
}
通过空参构造 ArrayList() 创建空的动态数组之后,在第一次尝试调用 add(E e) 方法添加元素时:
add(E e) 方法内部会调用 add(E e, Object[] elementData, int s) 方法;elementData 会通过 grow() 方法扩容;grow() 方法内部会调用 grow(int minCapacity) 方法实现具体的扩容操作(依赖于 Arrays 中的静态方法 copyOf(T[] original, int newLength));grow(int minCapacity) 方法前需要知道 copyOf(T[] original, int newLength) 方法所需的 newLength 参数,即扩容后底层数组的长度;newCapacity(int minCapacity) 方法:
oldCapacity = 0 ,因此 newCapacity 扩容 1.5 倍之后还是 0 ;if 条件成立,进入内层第一个 if 条件,该条件也成立,因此返回 DEFAULT_CAPACITY (为 10)和 minCapacity (为 1)中的较大值。newCapacity(int minCapacity) 方法得到 copyOf(T[] original, int newLength) 方法所需的 newLength 参数为 10 ,至此,elementData 扩容为容量为 10 的数组;grow(int minCapacity) 和 grow() 依次返回,最终在方法 add(E e, Object[] elementData, int s) 中完成元素添加,同时记录动态数组的长度的成员变量 size 递增。public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
......
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
......
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
......
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private Object[] grow() {
return grow(size + 1);
}
/**
* Returns a capacity at least as large as the given minimum capacity.
* Returns the current capacity increased by 50% if that suffices.
* Will not return a capacity greater than MAX_ARRAY_SIZE unless
* the given minimum capacity is greater than MAX_ARRAY_SIZE.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
*/
public int size() {
return size;
}
......
/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
......
}
LinkedList 基本使用LinkedList 集合的底层实现的数据结构是链表,其主要特点是查询慢,增删快。
LinkedList 作为 List 接口的典型实现类,而 List 接口又继承自 Collection 接口,因此 LinkedList 支持 Collection 接口以及 List 接口中声明的所有方法。
除此之外,LinkedList 本身还拥有一系列特有的操作方法,这些方法也是 ArrayList 类所不具备的:
| 方法名 | 说明 |
|---|---|
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.addFirst("Shakespeare");
linkedList.addFirst("William");
System.out.println(linkedList); // [William, Shakespeare]
linkedList.addLast("is");
linkedList.addLast("The Bard");
System.out.println(linkedList); // [William, Shakespeare, is, The Bard]
String first = linkedList.getFirst();
String last = linkedList.getLast();
System.out.println(first); // William
System.out.println(last); // The Bard
String removeFirst = linkedList.removeFirst();
String removeLast = linkedList.removeLast();
System.out.println(removeFirst); // William
System.out.println(removeLast); // The Bard
System.out.println(linkedList); // [Shakespeare, is]
}
}
Set 概述和使用List 一样,都是接口,不能直接创建实例对象使用;HashSet 和 TreeSet ,实现了 Collection 接口中所有抽象方法;HashSet 和 TreeSet 两个实现类中,都不可以存储重复元素,且二者都不保证数据的存取顺序;for 循环遍历,可以使用迭代器和增强 for 循环的方式进行遍历;TreeSetTreeSet():根据其元素的自然顺序进行排序;TreeSet(Comparator comparator) :根据指定的比较器进行排序。TreeSet 集合存储学生对象并通过 TreeSet 集合支持的方式进行遍历;TreeSet 集合:
TreeSet 集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的。Student 类实现 Comparable 接口:
Comparable 接口,重写 compareTo(T o) 方法。compareTo() 方法:
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/**
* @param o the object to be compared.
* @return a negative integer, zero, or a positive integer as this object
* s less than, equal to, or greater than the specified object.
*/
@Override
public int compareTo(Student o) {
int result = this.age - o.age;
result = result == 0 ? this.name.compareTo(o.getName()) : result;
return result;
}
}
以下为测试代码:
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(new Student("William", 30));
treeSet.add(new Student("Shakespeare", 400));
treeSet.add(new Student("Socrates", 2000));
treeSet.add(new Student("Confucius", 2000));
treeSet.add(new Student("Confucius", 2000));
System.out.println(treeSet);
}
}
上述代码的输出结果为:
[Student{name='William', age=30}, Student{name='Shakespeare', age=400}, Student{name='Confucius', age=2000}, Student{name='Socrates', age=2000}]
TreeSet 集合存储老师对象并通过 TreeSet 集合支持的方式进行遍历;TreeSet 的有参构造方法创建集合对象用以存储自定义对象,构造方法形参接收的是比较器对象;Comparator 接口的一个实现类对象,该实现类需重写 compare(T o1, T o2) 方法;public class Teacher {
private String name;
private int age;
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
以下为使用匿名内部类的测试代码:
import java.util.Comparator;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
TreeSet<Teacher> treeSet = new TreeSet<>(new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
int result = o1.getAge() - o2.getAge();
result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
return result;
}
});
treeSet.add(new Teacher("William", 30));
treeSet.add(new Teacher("Shakespeare", 400));
treeSet.add(new Teacher("Socrates", 2000));
treeSet.add(new Teacher("Confucius", 2000));
treeSet.add(new Teacher("Confucius", 2000));
System.out.println(treeSet);
}
}
以下为使用 Lambda 表达式的测试代码:
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
TreeSet<Teacher> treeSet = new TreeSet<>((Teacher o1, Teacher o2) -> {
int result = o1.getAge() - o2.getAge();
result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
return result;
});
treeSet.add(new Teacher("William", 30));
treeSet.add(new Teacher("Shakespeare", 400));
treeSet.add(new Teacher("Socrates", 2000));
treeSet.add(new Teacher("Confucius", 2000));
treeSet.add(new Teacher("Confucius", 2000));
System.out.println(treeSet);
}
}
TreeSet 集合的对象所述类实现 Comparable 接口,重写 compareTo() 方法,根据 compareTo() 方法返回值进行对象排序和存储;TreeSet 对象的时候传递 Comparator 接口的实现类对象,重写 compare() 方法,根据其返回值进行对象排序和存储;String 类默认实现了 Comparable 接口,所以多个 String 对象存入 TreeSet 默认按照自然排序进行,如果希望实现先按照字符串长度,再按照字典序排列,则必须使用比较器排序。import java.util.Comparator;
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
// Anonymous class
TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int result = o1.length() - o2.length();
result = result == 0 ? o1.compareTo(o2) : result;
return result;
}
});
treeSet.add("Dostoevsky");
treeSet.add("Shakespeare");
treeSet.add("Socrates");
treeSet.add("Confucius");
treeSet.add("Confucius");
System.out.println(treeSet);
}
}
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
TreeSet<String> treeSet = new TreeSet<>((String o1, String o2) -> {
int result = o1.length() - o2.length();
result = result == 0 ? o1.compareTo(o2) : result;
return result;
});
treeSet.add("Dostoevsky");
treeSet.add("Shakespeare");
treeSet.add("Socrates");
treeSet.add("Confucius");
treeSet.add("Confucius");
System.out.println(treeSet);
}
}
HashSetSet 接口的实现类,不可以存储重复元素;for 循环遍历。int 类型的数值。Object 类中的 public int hashCode()方法返回对象的哈希码值。hashCode() 方法返回的哈希值是相同的;hashCode() 方法,可以实现让不同对象的哈希值相同,例如使得两个具有不同地址但是具有相同属性的对象具有相同的哈希值。import java.util.Objects;
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return Objects.equals(name, student.name);
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
HashSet 原理HashSet 中添加元素的步骤大致如下:
equals() 方法进行比较,如果前者和后者的任意一个的比较结果相同,那么不添加该元素,否则将其添加至链表中。HashSet 原理HashSet 中添加元素的步骤大致如下:
equals() 方法进行比较,如果前者和后者的任意一个的比较结果相同,那么不添加该元素,否则将其添加至链表中;equals() 方法进行比较,如果前者和后者的任意一个的比较结果相同,那么不添加该元素,否则将其添加至红黑树中。HashSet 集合使用案例HashSet 支持的方式实现在控制台遍历该集合。import java.util.Objects;
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return Objects.equals(name, student.name);
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
以下为测试代码:
import java.util.HashSet;
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
HashSet<Student> hashSet = new HashSet<>();
hashSet.add(new Student("Dostoevsky", 100));
hashSet.add(new Student("Shakespeare", 400));
hashSet.add(new Student("Socrates", 2000));
hashSet.add(new Student("Socrates", 2000));
hashSet.add(new Student("Confucius", 2500));
for (Student student : hashSet) {
System.out.println(student);
}
Iterator<Student> iterator = hashSet.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
HashSet 集合存储自定义对象时,必须重写 hashCode() 和 equals() 方法,以实现自定义对象的去重。Map 概述和使用| 方法名称 | 方法说明 |
|---|---|
V put(K key, V value) | 添加元素或覆盖值 |
V remove(Object key) | 根据键删除键值对 |
void clear() | 移除所有的键值对 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
V get(Object key) | 根据键获取值 |
Set keySet() | 获取所有键的集合 |
Collection values() | 获取所有值的集合 |
Set | 获取所有键值对对象的集合 |
下面对 HashMap 进行遍历的四种方式:
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class Main {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("Russia", "Dostoevsky");
hashMap.put("England", "Shakespeare");
hashMap.put("Greek", "Socrates");
hashMap.put("China", "Confucius");
System.out.println(hashMap);
Set<String> keySet = hashMap.keySet();
for (String key : keySet) {
String value = hashMap.get(key);
System.out.println(key + "=" + value);
}
Set<Map.Entry<String, String>> entries = hashMap.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
hashMap.forEach(
(String key, String value) -> System.out.println(key + "=" + value)
);
hashMap.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
System.out.println(key + "=" + value);
}
});
}
}
HashMapHashMap 底层是哈希表结构的;hashCode() 方法和 equals() 方法保证键的唯一;hashCode() 和 equals() 方法;HashSet ,根据 JDK 版本不同,集合中元素存储使用数组 + 链表或数组 + 链表 + 红黑树。下面对 HashMap 进行遍历的四种方式:
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class Main {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("Russia", "Dostoevsky");
hashMap.put("England", "Shakespeare");
hashMap.put("Greek", "Socrates");
hashMap.put("China", "Confucius");
System.out.println(hashMap);
Set<String> keySet = hashMap.keySet();
for (String key : keySet) {
String value = hashMap.get(key);
System.out.println(key + "=" + value);
}
Set<Map.Entry<String, String>> entries = hashMap.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
hashMap.forEach(
(String key, String value) -> System.out.println(key + "=" + value)
);
hashMap.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
System.out.println(key + "=" + value);
}
});
}
}
TreeMapTreeMap 底层是红黑树结构;Comparable 接口并重写该接口的 compareTo() 方法,或者在创建 TreeMap 对象时候传入比较器对象。TreeMap 集合,要求在集合中保存键值对对象;Teacher 类型,值是籍贯, Teacher 成员属性是姓名和年龄;public class Teacher implements Comparable<Teacher> {
private String name;
private int age;
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
/**
* @param o the object to be compared.
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the specified object.
*/
@Override
public int compareTo(Teacher o) {
int result = this.getAge() - o.getAge();
result = result == 0 ? this.name.compareTo(o.getName()) : result;
return result;
}
}
以下是测试代码:
import java.util.TreeMap;
import java.util.function.BiConsumer;
public class Main {
public static void main(String[] args) {
TreeMap<Teacher, String> treeMap = new TreeMap<>();
treeMap.put(new Teacher("Dostoevsky", 100), "Russia");
treeMap.put(new Teacher("Shakespeare", 400), "England");
treeMap.put(new Teacher("Socrates", 2000), "Greek");
treeMap.put(new Teacher("Confucius", 2000), "China");
treeMap.forEach(new BiConsumer<Teacher, String>() {
@Override
public void accept(Teacher teacher, String s) {
System.out.println(teacher + " was from " + s);
}
});
treeMap.forEach((teacher, s) -> System.out.println(teacher + " was from " + s));
}
}
import java.util.Comparator;
import java.util.TreeMap;
import java.util.function.BiConsumer;
public class Main {
public static void main(String[] args) {
TreeMap<Teacher, String> treeMap = new TreeMap<>(new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
int result = o2.getAge() - o1.getAge();
result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
return result;
}
});
treeMap.put(new Teacher("Dostoevsky", 100), "Russia");
treeMap.put(new Teacher("Shakespeare", 400), "England");
treeMap.put(new Teacher("Socrates", 2000), "Greek");
treeMap.put(new Teacher("Confucius", 2000), "China");
treeMap.forEach(new BiConsumer<Teacher, String>() {
@Override
public void accept(Teacher teacher, String s) {
System.out.println(teacher + " was from " + s);
}
});
treeMap.forEach((teacher, s) -> System.out.println(teacher + " was from " + s));
}
}
不管是用自然排序还是使用比较器排序,在实现接口时都需要指定泛型 Teacher 。