Java基础入门 【第八章 集合】(三)

1.Set集合

    1. Set概述

java.util.Set 接口继承了 Collection 接口,是常用的一种集合类型。相对于之前学习的List集合,Set合特点如下:

除了具有 Collection 集合的特点,还具有自己的一些特点:

Set是一种无序的集合

Set是一种不带下标索引的集合Set是一种不能存放重复数据的集合

重点学习的Set现类:

HashSet 底层借助哈希表实现TreeSet 底层借助二叉树实现

注意,TreeSetSet接口的子接口SortedSet的实现类

基础案例:

实例化一个Set集合,往里面添加元素并输出,注意观察集合特点(无序、不重复)

import java.util.HashSet; import java.util.Iterator; import java.util.Set;

public class Test071_SetBasic {

public static void main(String[] args) {

 

//1.实例化Set集合,指向HashSet实现类对象Set<String> set = new HashSet<>();

set.add("hello1"); set.add("hello2"); set.add("hello3"); set.add("hello4");

set.add("hello5");   //添加失败 重复元素set.add("hello5");   //添加失败 重复元素

//加强for循环遍历

for(String obj : set){ System.out.println(obj);

}

System.out.println("-----------------");

//迭代器遍历

Iterator<String> it = set.iterator(); while(it.hasNext()){

Object obj = it.next(); System.out.println(obj);

}

}

 

}

//输出结果:hello1 hello4 hello5 hello2 hello3

-----------------

通过以上代码和运行结果,可以看出Set类型集合的特点:无序、不可重复

HashSet

java.util.HashSet Set接口的实现类,它使用哈希表(Hash Table)作为其底层数据结构来存储数据。

HashSet特点:

无序性:HashSet中的元素的存储顺序与插入顺序无关

HashSet使用哈希表来存储数据,哈希表根据元素的哈希值来确定元素的存储位置,而哈希值是根据元素的内容计算得到的,与插入顺序无关。

唯一性:HashSet中不允许重复的元素,即每个元素都是唯一的

允许null元素:HashSet允许存储null元素,但只能存储一个null元素,HashSet中不允许重复元素

高效性:HashSet的插入、删除和查找操作的时间复杂度都是O(1)

哈希表通过将元素的哈希值映射到数组的索引来实现快速的插入、删除和查找操作。

基础案例1

实例化HashSet对象,往里面插入多个字符串,验证HashSet特点。

package com.briup.chap08.test;

import java.util.HashSet; import java.util.Set;

public class Test072_Basic {

 

public static void main(String[] args) {

//1.实例化HashSet对象

Set<String> set = new HashSet<>();

//2.往集合中添加元素set.add("hello"); set.add("world"); set.add("nihao"); set.add("hello"); set.add(null); set.add(null);

System.out.println("size: " + set.size());

//3.遍历

for (String str : set) { System.out.println(str);

}

}

}

//运行结果:size: 4 null

world

nihao

hello

根据结果可知,HashSet无序、唯一、null值可存在。

 

元素插入过程:

当向HashSet中插入元素时,先获取元素的hashCode(),再检查HashSet是否存在相同哈希值的元素,如果元素哈希值唯一,则直接插入元素

如果存在相同哈希值的元素,会调用元素的equals()方法来进一步判断元素是否是相同。如果相同,则不会插入重复元素;如果不同,则插入

方法复习:

hashCode() 方法是 Object 中的一个方法,它返回一个 int 类型的哈希码值

通常情况下, hashCode() 方法会根据对象的属性值计算一个哈希码值(重写自定义类中 hashCode方法 

如果两个对象的hashCode值不同,则两个对象的属性值肯定不同

如果两个对象的hashCode值相同,则两个对象的属性值可能相同,也可能不

结论:如果要往HashSet集合存储自定义类对象,那么一定要重写自定义类中的hashCode方法和equals方法。

TreeSet

TreeSetSortedSetSet接口的子接口)的实现类,它基于红黑树(Red- Black Tree)数据结构实现。

TreeSet特点:

有序性:插入的元素会自动排序,每次插入、删除或查询操作后,TreeSet自动调整元素的顺序,以保持有序性。

唯一性:TreeSet中不允许重复的元素,即集合中的元素是唯一的。如果尝试插入一个已经存在的元素,该操作将被忽略。

动态性:TreeSet是一个动态集合,可以根据需要随时添加、删除和修改元素。插入和删除操作的时间复杂度为O(log n),其中n是集合中的元素数量。

高效性:由于TreeSet底层采用红黑树数据结构,它具有快速的查找和插入性能。对于有序集合的操作,TreeSet通常比HashSet更高效。

入门案例1

准备一个TreeSet集合,放入多个Integer元素,观察是否自动进行排序。

public class Test073_Integer {

public static void main(String[] args) {

//1.实例化集合对象

Set<Integer> set = new TreeSet<>();

//2.添加元素set.add(3); set.add(5); set.add(1); set.add(7);

//3.遍历

for(Integer obj : set) { System.out.println(obj);

}

}

}

//输出结果:

1

3

5

7

问题分析:

根据异常提示可知错误原因是: Person 无法转化成 Comparable ,从而导致ClassCastException异常 

为什么会这样呢?

TreeSet是一个有序集合,存储数据时,一定要指定元素的排序规则,有两种指定的方式,具体如下:

TreeSet排序规则:自然排序(元素所属类型要实现 java.lang.Comparable 接口)比较器排序上述2个案例中,Integer存如TreeSet没有报错,是因为Integer类已经实现自然排序,而Person类既没有实现自然排序,也没有额外指定比较器排序规则。

 

1TreeSet:自然排序

如果一个类,实现了 java.lang.Comparable 接口,并重写了 compareTo ,那么这个类的对象就是可以比较大小的。

public interface Comparable<T> { public int compareTo(T o);

}

compareTo方法说明:

int result = this.属性.compareTo(o.属性);

result的值大于0,说明thisoresult的值小于0,说明thisoresult的值等于0,说明thiso相等

元素插入过程:

 

当向TreeSet插入元素时,TreeSet会使用元素的 compareTo() 方法来比较元素之间的大小关系。根据比较结果,TreeSet会将元素插入到合适的位置,以保持有序性。如果两个元素相等( compareTo() 方法返回0),TreeSet会认为这是重复的元素,只会保留一个。

案例展示:

使用自然排序(先按name升序,name相同则按age降序)解决上述案例问题。

基础Person类:

package com.briup.chap08.bean;

//定义Person类,实现自然排序

public class Person implements Comparable<Person> { private String name;

private int age;

public Person() {}

public Person(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) {

 

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]"; }

//重写方法,指定比较规则:先按name升序,name相同则按age降序

@Override

public int compareTo(Person o) {

//注意:字符串比较需要使用compareTo方法

int r = name.compareTo(o.name); if(r == 0) {

r = o.age - this.age; }

return r; } }

测试类:

package com.briup.chap08.test;

import java.util.Set; import java.util.TreeSet;

import com.briup.chap08.bean.Person;

//自然排序测试

public class Test073_Comparable {

public static void main(String[] args) {

//1.实例化TreeSet

Set<Person> set = new TreeSet<>();

//2.添加元素

set.add(new Person("zs",21)); set.add(new Person("ww",20)); set.add(new Person("zs",21)); set.add(new Person("tom",19)); set.add(new Person("tom",23)); set.add(new Person("jack",20));

//3.遍历集合

for (Person person : set) { System.out.println(person);

}

 

}

//输出结果:

Person [name=jack, age=20]

Person [name=tom, age=23]

Person [name=tom, age=19]

Person [name=ww, age=20]

Person [name=zs, age=21]

 

补充内容1Integer类中重写compare源码

可以看出,Integer的俩个对象比较大小,其实就是比较Integer对象对应的int值的大小

注意,compareTo方法返回值代表的含义(三种情况:正数、负数、零)补充内容2整形、浮点型、字符串自然排序规则

 

对于整型、浮点型元素,它们会按照从小到大的顺序进行排序。对于字符串类型的元素,它们会按照字典顺序进行排序。

注意事项:compareTo方法的放回结果,只关心正数、负数、零,不关心具体的值是多少

2TreeSet:比较器排序

思考:如果上述案例中Person类不是自定义类,而是第三方提供好的(不可以修改源码),那么如何实现排序规则的指定?

我们可以可以使用比较器(Comparator)来自定义排序规则。

比较器排序步骤:

创建一个实现了Comparator接口的比较器类,并重写其中的 compare() 

该方法定义了元素之间的比较规则。在 compare() 方法中,我们可以根据元素的属性进行比较,并返回负整数、零或正整数,来表示元素之间的大小关系。

创建TreeSet对象时,将比较器对象作为参数传递给构造函数,这样,TreeSet会根据比较器来进行排序。

TreeSet构造器补充:

//实例化TreeSet类对象时,需要额外传入一个比较器类对象

public TreeSet(Comparator<? super E> comparator) {

this(new TreeMap<>(comparator)); }

 

jcompare法说明:

int result = compare(o1, o2);

result的值大于0表示升序result的值小于0,表示降序

result的值等于0,表示元素相等,不能插入

注意,这里和自然排序的规则是一样的,只关心正数、负数、零,不关心具体的值是多少

案例说明:

使用比较器排序,对上述案例中Person进行排序,要求先按age升序,age相同则按name降序

 

基础类需要注释掉自然排序接口:

//定义Person类,实现自然排序

public class Person /* implements Comparable<Person> */ { private String name;

private int age;

public Person() {}

public Person(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 "Person [name=" + name + ", age=" + age + "]"; }

//重写方法,指定比较规则

//   @Override

//   public int compareTo(Person o) {  } }

//先按name升序,name相同则按age降序

int r = name.compareTo(o.name);

if(r == 0) {

r = o.age - this.age; }

return r;测试类:

 

package com.briup.chap08.test;

import java.util.Comparator; import java.util.Set;

import java.util.TreeSet;

import com.briup.chap08.bean.Person;

//比较器排序测试

public class Test073_Comparator {

public static void main(String[] args) {

//1.准备自定义比较器对象

//   匿名内部类形式

Comparator<Person> comp = new Comparator<Person>() {

//重写比较算法:先按按age升序,age相同则按name降序

@Override

public int compare(Person o1, Person o2) {

int r = o1.getAge() - o2.getAge(); if(r == 0) {

//注意:字符串比较需要使用compareTo方法

= o2.getName().compareTo(o1.getName());

}

return r;

 

};

//2.实例化TreeSet,传入自定义比较器对象

Set<Person> set = new TreeSet<>(comp);

//3.添加元素

set.add(new Person("zs",21)); set.add(new Person("ww",20)); set.add(new Person("zs",21)); set.add(new Person("tom",19)); set.add(new Person("tom",23)); set.add(new Person("jack",20));

//4.遍历集合

for (Person person : set) { System.out.println(person);

} }

//输出结果:

Person [name=tom, age=19]

Person [name=ww, age=20]

Person [name=jack, age=20]

Person [name=zs, age=21]

Person [name=tom, age=23]

注意:如果同时使用自然排序和比较器排序,比较器排序将覆盖自然排序。

 

2.自然排序:

使用元素类实现Comparable接口,并重写其中的 compareTo() 方法元素会按照其自身的比较规则进行排序

自然排序是默认的排序方式,可以直接使用TreeSetCollections.sort()方法进行排序

只能有一种自然排序方式比较器排序:

使用Comparator对象来定义元素之间的比较规则

可以自定义排序规则,不依赖于元素类的实现Comparable接口

需要创建一个实现Comparator接口的比较器类,并重写其中的 compare()方法

可以有多个比较器,根据需要选择不同的比较器进行排序

可以通过传入Comparator对象给TreeSetCollections.sort()方法来进行比较器排序

自然排序和比较器排序都有自己的应用场景。自然排序适用于元素类已经实现了Comparable接口,并且希望按照元素自身的比较规则进行排序的情况。比较器排序适用于需要自定义排序规则,或者元素类没有实现Comparable口的情

况。

LinkedHashSet

LinkedHashSet  HashSet 的一个子类,具有 HashSet 的高效性能和唯一性特性,并且保持了元素的插入顺序,其底层基于哈希表和链表实现。

案例展示:

 

实例化一个LinkedHashSet集合对象,存入多个String字符串,观察是否唯一及顺序存储。

package com.briup.chap08.test;

import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set;

public class Test074_LinkedHashSet {

public static void main(String[] args) {

// 1.实例化LinkedHashSet

Set<String> set = new LinkedHashSet<>();

// 2.添加元素set.add("bbb"); set.add("aaa"); set.add("abc"); set.add("bbc"); set.add("abc");

// 3.迭代器遍历

Iterator<String> it = set.iterator(); while (it.hasNext()) {

System.out.println(it.next()); }

}

}

//运行结果:

bbb

aaa

abc

bbc

    1. Set小结

集合类

特点

示例

HashSet

基于哈希表实现,无序集合,不允许重复元素。

Set set = new HashSet<>();

TreeSet

基于红黑树实现,有序集合,不允许重复元素。

Set set = new TreeSet<>();

LinkedHashSet

基于哈希表和链表实现,按插入顺序排序,不允许重复元素。

Set set = new LinkedHashSet<> ();

3.Map集合

很多时候,我们会遇到成对出现的数据,例如,姓名和电话,身份证和人,IP和域名等等,这种成对出现,并且一一对应的数据关系,叫做映射。java.util.Map<K,  V> 接口,就是专门处理这种映射关系数据的集合类型。

Map集合是一种用于存储键值对(key-value映射关系的集合类。它提供了一种快速查找和访问数据的方式,其中每个键都是唯一的,而值可以重复。

Map概述

Collection接口为单列集合的根接口,Map口为双列集合的根接口。Map集合与Collection集合,存储数据的形式不同:

 

Map集合特点:

存储元素时,必须以key-value(键值对)方式进行

键唯一性:Map

合中的键是唯一的,每个键只能对应一个值

可重复值:Map集合中的值可以重复,不同的键可以关联相同的值

高效的查找和访问:通过给定键key值(唯一),可以快速获取与之对应的value

Map集合内部使用哈希表或红黑树等数据结构来实现高效的查找和访问

Map接口常用方法(注意泛型K代表Key,范型V代表Value):

//key-value存到当前Map集合中

V put(K key, V value)

//把指定map中的所有key-value,存到当前Map集合中

void putAll(Map<? extends K,? extends V> m)

//当前Map集合中是否包含指定的key

boolean containsKey(Object key)

//当前Map集合中是否包含指定的value

boolean containsValue(Object value)

 

//清空当前Map集合中的所有数据

void clear()

//在当前Map集合中,通过指定的key值,获取对应的value

V get(Object key)

//在当前Map集合中,移除指定key及其对应的value

V remove(Object key)

//返回当前Map集合中的元素个数(一对key-value,算一个元素数据)

int size()

//判断当前Map集合是否为空

boolean isEmpty()

//返回Map集合中所有的key

Set<K> keySet()

//返回Map集合中所有的value

Collection<V> values()

//Map集合中的的key-value封装成Entry类型对象,再存放到set集合中,并返回

 

24 Set<Map.Entry<K,V>> entrySet()

Map集合实现类:

Java提供的Map集合实现类,常见的包括HashMapTreeMapLinkedHashMap等。它们在内部实现和性能方面有所不同,可以根据具体需求选择适合的实现类。

HashMap ,底层借助哈希表实现,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键所属类的hashCode()方法、equals()方法

(重要,最常用)

Hashtable :和之前List集合中的 Vector 的功能类似,可以在多线程环境中,保证集合中的数据的操作安全线程安全)

LinkedHashMap :该类是 HashMap 的子类,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致存入顺序就是取出顺序)

TreeMap :该类是 Map 接口的子接口 SortedMap 下面的实现类,和TreeSet 类似,它可以对key值进行排序,同时构造器也可以接收一个比较器对象作为参数。支持key值的自然排序和比较器排序俩种方式(支持key序)

基本方法使用案例:

import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set;

public class Test081_MapBasic {

//双列集合 存放  id-name

public static void main(String[] args) {

//1.创建HashMap集合对象,并添加元素Map<Integer,String> map = new HashMap<>();

//注意,使用put方法添加键值对map.put(1, "zs"); map.put(2, "ls"); map.put(4, "rose"); map.put(3, "jack");

map.put(2, "lucy"); //lucy 会把 ls覆盖掉

//2.输出集合元素个数

//System.out.println(map); System.out.println("size: "+map.size());

//3.判断keyvalue否存在

System.out.println("key 2: " + map.containsKey(2)); System.out.println("value ls: " +

map.containsValue("ls"));

//4.根据key获取value

String name = map.get(3); System.out.println("3: " + name);

//5.根据key删除键值对map.remove(3); System.out.println(map);

 

}

//运行结果:

size: 4

key 2: true value ls: false 3: jack

{1=zs, 2=lucy, 4=rose}

 

​​​​​​​Map遍历

Map集合提供了2种遍历方式。

1)第一种遍历思路

借助Map中的keySet方法,获取一个Set集合对象,内部包含了Map集合中所有key,进而遍历Set集合获取每一个key值,再根据key获取对应的value

keySet遍历案例:

2)第二种遍历思路

 

借助Map中的entrySet方法,获取一个Set对象,内部包含了Map集合中所有的键值对,然后对键值对进行拆分,得到keyvalue进行输出。

Map 接口 entrySet() 方法解析:将 Map 集合中的每一组key-value(键值对)都封装成一个 Entry 类型对象,并且把这些个 Entry 对象存放到Set集合中,并返回。

entrySet遍历案例:对前面案例中的map集合对象进行遍历。import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.Map.Entry;public class Test082_Each {

 

//双列集合 存放  id-name

public static void main(String[] args) {

//1.创建HashMap集合对象,并添加元素

Map<Integer,String> map = new HashMap<>();

map.put(1, "zs"); map.put(2, "ls"); map.put(4, "rose"); map.put(3, "jack");

map.put(2, "lucy"); //lucy 会把 ls覆盖掉

//2.第二种遍历

//   获取所有的key-value键值对,得到一个Set集合

Set<Entry<Integer,String>> entrySet = map.entrySet();

//   遍历Set集合

for (Entry<Integer, String> entry : entrySet) {

//   拆分键值对中的keyvalue Integer key = entry.getKey(); String value = entry.getValue();

System.out.println("id: " + key + " name: " + value);

}

}

}

//运行结果:

 

id: 1 name: zs id: 2 name: lucy id: 3 name: jack id: 4 name: rose

 

​​​​​​​HashMap

HashMap底层借助哈希表实现,元素的存取顺序不能保证一致。

HashMap存储的键值对时,如果键类型为自定义类,那么一般需要重写键所属类hashCode()equals()方法(重要,最常用)

HashMap特点:

键唯一

值可重复

无序性

线程不安全

键和值的允许使用null重点记忆】

/ 4.第一种遍历方法

Set<Student> keySet = map.keySet(); for (Student key : keySet) {

System.out.println(key + ": " + map.get(key)); }

System.out.println("---------------");

// 第二种方式遍历

Set<Entry<Student, String>> entrySet = map.entrySet(); for (Entry<Student, String> entry : entrySet) {

System.out.println(entry.getKey() + ": " + entry.getValue());

}

}

}

//运行结果:

size: 6

Student(ww,67)是否存在: true是否存在 009: false

remove(Student(lucy, 70)): 019

--------------- null: 002

Student [name=rose, age=82]: 005 Student [name=zs, age=78]: 010 Student [name=tom, age=86]: null Student [name=ww, age=67]: 002

---------------

省略...

 

结论:key类型如果为自定义类型,重写其hashCodeequals方法!

HashMap中add(keyvalue)时,需要判断key是否存在(先hashCodeequals

HashMapcontainsKey(key)时,同样要借助hashCodeequals方法HashMapremove(key)时,同样要借助hashCodeequals方法

Hashtable

Hashtable是Java中早期的哈希表实现,它实现了Map接口,并提供了键值对的存储和访问功能。

Hashtable特点:

JDK1.0提供,接口方法较为复杂,后期实现了Map接口

线程安全:Hashtable是线程安全的,相对于HashMap性能稍低

键和值都不能为null:如果尝试使用null作为键或值,将会抛出NullPointerException

 

哈希表实现:和HashMap一样,内部使用哈希表数据结构来存储键值对

案例展示:

实例化Hashtable<Student, String>对象,添加元素并遍历。

package com.briup.chap08.test;

import java.util.Enumeration; import java.util.Hashtable;

import com.briup.chap08.bean.Student;

public class Test084_Hashtable {

public static void main(String[] args) {

// 1.实例化HashMap对象,其中key类型为自定义Student

Hashtable<Student, String> map = new Hashtable<>();

// 2.往集合中添加元素

//  map中插入键值对,调用key所属类的hashCodeequals方法进行判断是否重复

map.put(new Student("zs", 78), "010"); map.put(new Student("rose", 82), "005"); map.put(new Student("lucy", 70), "009");

map.put(new Student("lucy", 70), "019"); // 相同key,只能保留一项,"019"会覆盖"009"

map.put(new Student("ww", 67), "002");

// 注意:Hashtablekeyvalue不能为null,否则抛出

NullPointerException

//map.put(new Student("tom", 86), null);

//map.put(null, "002");

// 3.遍历,Hashtable早期提供的方法较为繁琐Enumeration<Student> keys = map.keys(); while(keys.hasMoreElements()) {

Student key = keys.nextElement(); String value = map.get(key);

System.out.println(key + ": " + value); }

 

}

//运行输出:

Student [name=lucy, age=70]: 019 Student [name=zs, age=78]: 010 Student [name=ww, age=67]: 002 Student [name=rose, age=82]: 005

Hashtable小结:单线程环境下建议使用HashMap,性能更好

 

多线程环境下,建议使用 HashMap + Collections 

​​​​​​​TreeMap

TreeMap是有序映射实现类,它实现了SortedMap接口,基于红黑树数据结构来存储键值对。

TreeMap特点:

键的排序:TreeMap中的键是按照自然顺序或自定义比较器进行排序的

 

红黑树实现:TreeMap内部使用红黑树这种自平衡二叉搜索树数据结构来存储键值对

键唯一,值可重复

线程不安全,如果在多线程环境下使用TreeMap,应该使用Collections工具类处理

初始容量:TreeMap没有初始容量的概念,它会根据插入的键值对动态地调整红黑树的大小

TreeMap小结:

TreeMap底层借助红黑树实现,它提供了高效的有序映射功能,可以用于范围查找、排序和遍历等操作。但红黑树的平衡操作会带来额外的开销,相比于HashMap等实现类,TreeMap在插入和删除操作上可能稍慢。

因此,在选择使用TreeMap时,需要根据具体需求权衡性能和有序性的需求。

​​​​​​​LinkedHashMap

LinkedHashMap是HashMap的一个子类,底层在哈希表的基础上,通过维护一个双向链表来保持键值对的有序性,可以保证存取次序一致。

 基础案例:

创建LinkedHashMap<String, Student>对象,添加元素,观察是否存取次序一致。

import java.util.LinkedHashMap; import java.util.Map;

import com.briup.chap08.bean.Student;

// LinkedHashMap可以保证 存取次序一致

public class Test086_LinkedHashMap {

public static void main(String[] args) {

//1.实例化LinkedHashMap类对象

Map<String, Student> map = new LinkedHashMap<>();

//2.添加元素

map.put("010", new Student("zs", 78)); map.put("005", new Student("rose", 82)); map.put("009", new Student("lucy", 70));

map.put("019", new Student("lucy", 70)); //value可以重复

map.put("002", null);

map.put(null, new Student("ww", 67));

//3.遍历

for (String key : map.keySet()) { System.out.println(key + " " + map.get(key));

}

}

}

//结果输出:

010 Student [name=zs, age=78]

005 Student [name=rose, age=82]

009 Student [name=lucy, age=70]

019 Student [name=lucy, age=70]

002 null

null Student [name=ww, age=67]

 

可以看出,数据存入Map中的顺序,就是存储的顺序,也是取出的顺序!

​​​​​​​Map小结

集合类

特点

示例

HashMap

基于哈希表实现,无序键值对集合,键和值均可为null

Map<String, Integer> map = new HashMap<>();

TreeMap

基于红黑树实现,按键有序排序,键不可为null

Map<String, Integer> map = new TreeMap<>();

LinkedHashMap

基于哈希表和双向链表实现,按插入顺序排序,键和值均可为null

Map<String, Integer> map = new LinkedHashMap<> ();

Hashtable

基于哈希表实现,键值对存储,线程安全,键无序且不允许重复,和值都不能为null

Map<String, Integer> map = new Hashtable<>();

Collections

数组工具类是 java.util.Arrays ,可以专门来操作数组对象,提供静态方法,可直接调用。

集合工具类是 java.util.Collections ,专门来操作集合对象,里面都是静态方法,可以直接调用。

 

注意, Collection 是单列集合根接口, Collections 是集合工具类,两者不同!

1 常用方法:

package java.util;

public class Collections {

// 类外不能实例化对象,工具类主要调用static方法

private Collections() { }

//填充元素值

public static <T> void fill(List<? super T> list, T obj) {

//省略...

}

//获取最大值

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {

Iterator<? extends T> i = coll.iterator(); T candidate = i.next();

while (i.hasNext()) {

T next = i.next();

if (next.compareTo(candidate) > 0) candidate = next;

}

return candidate; }

//排序

@SuppressWarnings("unchecked")

public static <extends Comparable<? super T>> void sort(List<T> list) {

list.sort(null); }

//省略 ... }

 

2)具体方法讲解

fill方法,使用指定元素替换指定列表中的所有元素

List<Integer> list = new ArrayList<>(); list.add(1);

list.add(2); list.add(3);

Collections.fill(list, 20);

for(Integer o : list) { System.out.println(o);

}

max方法,根据元素的自然顺序,返回给定集合的最大元素

List<Integer> list = new ArrayList<>(); list.add(1);

list.add(9); list.add(3);

System.out.println(Collections.max(list));

min方法,根据元素的自然顺序,返回给定集合的最小元素reverse方法,反转集合中的元素

List<Integer> list = new ArrayList<>(); list.add(1);

list.add(9); list.add(3);

Collections.reverse(list);

for(Integer o : list) { System.out.println(o);

}

sort方法,根据元素的自然顺序,对指定列表按升序进行排序

List<Integer> list = new ArrayList<>(); list.add(1);

list.add(9); list.add(3);

//如果需要,也可以在第二个参数位置传一个比较器对象

//Collections.sort(list,c); Collections.sort(list);

for(Integer o : list) { System.out.println(o);

}shuffle方法,使用默认随机源对指定列表进行置换

List<Integer> list = new ArrayList<>(); list.add(1);

list.add(9); list.add(3);

Collections.shuffle(list);

for(Integer o : list) { System.out.println(o);

}

addAll方法,往集合中添加一些元素

 

List<Integer> list = new ArrayList<>();

//注意,addAll的第二个参数,是可变参数Collections.addAll(list,1,3,5,7);

for(Integer o : list) { System.out.println(o);

}synchronized相关方法,将非线程安全的集合转为线程安全了解,后续多线程再学习)

 

synchronizedCollection,把非线程安全的Collection型集合,转为线程安全的集合

synchronizedList,把非线程安全的List类型集合,转为线程安全的集合synchronizedSet,把非线程安全的Set类型集合,转为线程安全的集合synchronizedMap,把非线程安全的Map型集合,转为线程安全的集合

案例展示:

 

准备一个集合,往里面添加元素,然后使用工具类上述方法对其进行操作,观察效果。

package com.briup.chap08.test;

import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List;

public class Test09_Collections {

public static void main(String[] args) {

//1.准备集合并添加元素

//List<Integer> list = Arrays.asList(5,3,4,2,2,7); List<Integer> list = new ArrayList<>();

//addAll 往集合中添加多个元素Collections.addAll(list,5,3,4,2,2,7); System.out.println(list);

//2.max 获取最大值【默认采用自然排序】Integer max = Collections.max(list); System.out.println("max: " + max);

//3.min 获取集合最小值

Integer min = Collections.min(list); System.out.println("min: " + min);

//4.reverse 反转Collections.reverse(list); System.out.println(list);

//4.sort 排序【按照 传入的排序算法 进行排序】Comparator<Integer> comp = new Comparator<Integer>() {

@Override

public int compare(Integer o1, Integer o2) {

 

// 逆序

return o2-o1;

 }

};

//注意:排序不会删除集合中的元素Collections.sort(list,comp); System.out.println("逆序: " + list);

//5.shuffle 随机打乱Collections.shuffle(list); System.out.println("打乱: " + list);

//6.sort 排序【默认自然排序】Collections.sort(list); System.out.println("自然排序: " + list);

//7.fill 填充Collections.fill(list, 20);

System.out.println("after fill: " + list);

//8.将ArrayList【线程不安全】的集合 转换成  线程安全集合

//List<Integer> list2 = Collections.synchronizedList(list);

}

}

注意:Collections.sort排序不会删除集合中的元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时肆 知还

你的鼓励将是我创作的最大动力,

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值