在深入探讨模块20之前,让我们回顾一下day19中的关键内容:
add、addAll、clear、size、isEmpty、remove、toArray、contains等方法。iterator方法获取,提供了hasNext()和next()方法。在迭代集合时,不能随意修改集合长度,否则会抛出并发修改异常。add、add(index, element)、remove、size、get、set等方法。自动扩容机制,扩容1.5倍。for(元素类型 变量名:集合名或者数组名),遍历集合时使用迭代器,遍历数组时使用普通for循环。本模块将深入探讨集合的高级应用,包括:
Collections集合工具类的常用方法。HashSet和LinkedHashSet的特点及使用。HashSet将元素去重的过程。Collections是一个集合工具类,提供了多种静态方法来操作集合。
static <T> boolean addAll(Collection<? super T> c, T... elements):批量添加元素。static void shuffle(List<?> list):将集合中的元素顺序打乱。static <T> void sort(List<T> list):将集合中的元素按照默认规则排序。static <T> void sort(List<T> list, Comparator<? super T> c):将集合中的元素按照指定规则排序。public class Demo01Collections {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三", "李四", "王五", "赵六", "田七", "朱八");
System.out.println(list);
Collections.shuffle(list);
System.out.println(list);
ArrayList<String> list1 = new ArrayList<>();
list1.add("c.举头望明月");
list1.add("a.床前明月光");
list1.add("d.低头思故乡");
list1.add("b.疑是地上霜");
Collections.sort(list1);
System.out.println(list1);
}
}泛型是Java中用于统一数据类型、防止数据类型转换异常的一种机制。
public class Demo01Genericity {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("1");
list.add(1);
list.add("abc");
list.add(2.5);
list.add(true);
for (Object o : list) {
String s = (String) o;
System.out.println(s.length());
}
}
}public class MyArrayList<E> {
Object[] obj = new Object[10];
int size;
public boolean add(E e) {
obj[size] = e;
size++;
return true;
}
public E get(int index) {
return (E) obj[index];
}
@Override
public String toString() {
return Arrays.toString(obj);
}
}public class ListUtils {
public static <E> void addAll(ArrayList<E> list, E... e) {
for (E element : e) {
list.add(element);
}
}
}public interface MyList<E> {
boolean add(E e);
}public class Demo01Genericity {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("张三");
list1.add("李四");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
method(list1);
method(list2);
}
public static void method(ArrayList<?> list) {
for (Object o : list) {
System.out.println(o);
}
}
}public class Demo02Genericity {
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
ArrayList<Number> list3 = new ArrayList<>();
ArrayList<Object> list4 = new ArrayList<>();
get1(list1);
//get1(list2);错误
get1(list3);
//get1(list4);错误
System.out.println("=================");
//get2(list1);错误
//get2(list2);错误
get2(list3);
get2(list4);
}
public static void get1(Collection<? extends Number> collection) {
}
public static void get2(Collection<? super Number> collection) {
}
}按照斗地主的规则,完成洗牌发牌的动作。具体规则:使用54张牌打乱顺序,三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
ArrayList<String>,每张牌由花色数字两部分组成,使用Collections类的shuffle方法进行随机排序。ArrayList<String>,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。
public class Poker {
public static void main(String[] args) {
ArrayList<String> color = new ArrayList<>();
ArrayList<String> number = new ArrayList<>();
ArrayList<String> poker = new ArrayList<>();
color.add("♠");
color.add("♥");
color.add("♣");
color.add("♦");
for (int i = 2; i <= 10; i++) {
number.add(i + "");
}
number.add("J");
number.add("Q");
number.add("K");
number.add("A");
for (String num : number) {
for (String huaSe : color) {
String pokerNumber = huaSe + num;
poker.add(pokerNumber);
}
}
poker.add("😊");
poker.add("☺");
Collections.shuffle(poker);
ArrayList<String> p1 = new ArrayList<>();
ArrayList<String> p2 = new ArrayList<>();
ArrayList<String> p3 = new ArrayList<>();
ArrayList<String> dipai = new ArrayList<>();
for (int i = 0; i < poker.size(); i++) {
String s = poker.get(i);
if (i >= 51) {
dipai.add(s);
} else if (i % 3 == 0) {
p1.add(s);
} else if (i % 3 == 1) {
p2.add(s);
} else if (i % 3 == 2) {
p3.add(s);
}
}
System.out.println("涛哥:" + p1);
System.out.println("三上:" + p2);
System.out.println("金莲:" + p3);
System.out.println("底牌:" + dipai);
}
}集合加入红黑树的目的:提高查询效率。HashSet集合的数据结构包括哈希表,其中JDK8之前为数组+链表,JDK8之后为数组+链表+红黑树,以提高查询效率。


https://www.cs.usfca.edu/~galles/visualization/RedBlack
Set接口并没有对Collection接口进行功能上的扩充,而且所有的Set集合底层都是依靠Map实现

Set和Map密切相关,Map的遍历需要先变成单列集合,只能变成Set集合。
HashSet是Set接口的实现类,具有元素唯一、无序、无索引、线程不安全等特点。底层数据结构为哈希表。
public class Demo01HashSet {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("张三");
set.add("李四");
set.add("王五");
set.add("赵六");
set.add("田七");
set.add("张三");
System.out.println(set);
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
for (String s : set) {
System.out.println(s);
}
}
}LinkedHashSet继承自HashSet,具有元素唯一、有序、无索引、线程不安全等特点。底层数据结构为哈希表+双向链表。
public class Demo02LinkedHashSet {
public static void main(String[] args) {
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("张三");
set.add("李四");
set.add("王五");
set.add("赵六");
set.add("田七");
set.add("张三");
System.out.println(set);
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
for (String s : set) {
System.out.println(s);
}
}
}哈希值是由计算机算出来的一个十进制数,可以看做是对象的地址值。获取对象的哈希值使用的是Object中的方法public native int hashCode()。
注意: a. 哈希值不一样,内容肯定不一样 b. 哈希值一样,内容也有可能不一样
public class Person {
private String name;
private Integer age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name) && Objects.equals(age, person.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}public class Demo01Hash {
public static void main(String[] args) {
Person p1 = new Person("涛哥", 18);
Person p2 = new Person("涛哥", 18);
System.out.println(p1);
System.out.println(p2);
System.out.println(p1.hashCode());
System.out.println(p2.hashCode());
}
}字符串的哈希值是通过特定的算法计算出来的,例如String类的哈希算法。
public int hashCode() {
int h = hash;
if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
if (h == 0) {
hashIsZero = true;
} else {
hash = h;
}
}
return h;
}HashSet通过计算元素的哈希值和比较内容来去重。
public class Test02 {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("abc");
set.add("通话");
set.add("重地");
set.add("abc");
System.out.println(set);
}
}自定义类型需要重写hashCode和equals方法来实现去重。
public class Person {
private String name;
private Integer age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name) && Objects.equals(age, person.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test03 {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
set.add(new Person("涛哥", 16));
set.add(new Person("金莲", 24));
set.add(new Person("涛哥", 16));
System.out.println(set);
}
}通过本文的学习,希望能够帮助您深入理解集合的高级应用,包括Collections集合工具类的常用方法、泛型的使用、HashSet和LinkedHashSet的特点及使用,以及HashSet将元素去重的过程。这些都是Java集合框架中非常重要的知识点。