【501-560】集合
2022-01-26 16:40:00 # JavaSE

概述

  1. 集合不能存储基本数据类型,也不能直接存储java对象,存储的都是java对象的内存地址。(或者说是引用)(这儿应该有个图…)

    1
    List.add(100) // 自动装箱 Integer
  2. 不同集合对应不同数据结构

  3. 集合分为两大类:单个方式存储元素(超级父接口:java.util.Collection),键值对方式存储元素(超级父接口: java.util.Map)

  4. Collection 集合的继承结构图(这儿因该有两张图)

  5. Map 集合的继承结构图(这儿因该有一张图)

  6. 各个类总结:

  7. 1 LinkedList:底层是双向链表。

  8. 2 Vector:底层是数组,线程安全的,效率较低,使用较少。

  9. 3 HashSet:底层是HashMap,放到 HashSet集合中的元素等同于放到HashMap集合key部分了。

  10. 4 TreeSet:底层是TreeMap,放到TreeSet,集合中的元素等同于放到TreeMap集合 key部分了。

  11. 5 HashMap:底层是哈希表。

  12. 6 Hashtable:底层也是哈希表,只不过线程安全的,效率较低,使用较少。

  13. 7 properties:是线程安全的,并且key和value只能存储字符串String。

  14. 8 TreeMap:底层是二叉树。TreeMap集合的key可以自动按照大小顺序排序。

  15. 存储元素的特点:

  16. 1 List集合存储元素的特点: 有序可重复
    有序:存进去的顺序和取出的顺序相同,每一个元素都有下标。可重复:存进去1,可以再存储一个1.

  17. 2 Set集合存储元素的特点: 无序不可重复
    无序:存进去的顺序和取出的顺序不一定相同。另外 set集合中元素没有下标。不可重复:存进去1,不能再存储1了。

  18. 3 SortedSet集合存储元素特点:首先是无序不可重复的,但是SortedSet集合中的元素是可排序的。
    无序:存进去的顺序和取出的顺序不一定相同。另外set集合中元素没有下标。
    不可重复:存进去1,不能再存储1了。
    可排序:可以按照大小顺序排列

  19. 4 Map集合的 key,就是一个set集合,往set集合中放数据,实际上放到了Map集合的key部分。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    import java.util.*;

    public class _513_迭代器是通用的 {
    public static void main(String[] args) {
    Collection c1 = new ArrayList();
    Collection c2 = new HashSet();
    Collection c3 = new TreeSet();

    c1.add(1);
    c1.add(2);
    c1.add(3);
    c1.add(1);
    for (Iterator it = c1.iterator(); it.hasNext(); ){
    System.out.println(it.next());
    }
    /*
    1
    2
    3
    1
    */

    System.out.println("==================");
    c2.add(1);
    c2.add(2);
    c2.add(3);
    c2.add(1); // 这个无效 因为HashSet无序不可重复
    for (Iterator it = c2.iterator(); it.hasNext(); ){
    System.out.println(it.next());
    }
    /*
    1
    2
    3
    */

    System.out.println(" ============ ");
    c3.add(1);
    c3.add(3);
    c3.add(2);
    c3.add(1);
    for (Iterator it = c3.iterator(); it.hasNext(); ){
    System.out.println(it.next());
    }
    /*
    1
    2
    3
    */
    }
    }

  20. 集合只要发生改变,比如add或remove了某些引用,迭代器必须重新获取,以用来遍历集合

Collection接口中常用方法

  1. Collection中能存放什么元素?
    没有使用“泛型之前,collection中可以存储object的所有子类型。使用了“泛型之后,collection中只能存储某个具体的类型。只要是object的子类型就行。(集合中不能直接存储基本数据类型,也不能存java对象,只是存储java对象的内存地址。)

boolean add(E e);

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.ArrayList;
import java.util.Collection;

public class _508_Collection接口中常用方法 {
public static void main(String[] args) {
// 多态
Collection c = new ArrayList();
// 自动装箱
c.add(100);
c.add(true);
}
}

int size();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.ArrayList;
import java.util.Collection;

public class _509_Collection接口中常用方法 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(100);
c.add(3.14);
c.add(true);
c.add(new Object());

System.out.println(c.size()); // 4
}
}

void clear();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.ArrayList;
import java.util.Collection;

public class _509_Collection接口中常用方法 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(100);
c.add(3.14);
c.add(true);
c.add(new Object());

System.out.println(c.size()); // 4

c.clear();
System.out.println(c.size()); // 0
}
}

boolean contains(Object o);

contains使用

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.ArrayList;
import java.util.Collection;

public class _509_Collection接口中常用方法 {
public static void main(String[] args) {
Collection c = new ArrayList();
System.out.println(c.contains(100)); // false
c.add(100);
System.out.println(c.contains(100)); // true
}
}

contains解析

这儿应该有张图…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.util.ArrayList;
import java.util.Collection;

public class _514_Collection方法解析 {
public static void main(String[] args) {
Collection c = new ArrayList();
String s1 = new String("abc");
String s2 = new String("def");
c.add(s1);
c.add(s2);

String s3 = new String("abc");
// 底层调用了equals()
System.out.println(c.contains(s3)); // true

/*
public boolean contains(Object o) {
return indexOf(o) >= 0;
}

public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
*/
}
}

boolean remove(Object o);

remove方法使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.ArrayList;
import java.util.Collection;

public class _509_Collection接口中常用方法 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(100);
System.out.println(c.contains(100)); // true

c.remove(100);
System.out.println(c.contains(100)); // false
}
}

remove方法解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.ArrayList;
import java.util.Collection;

public class _516_remove方法源码分析 {
public static void main(String[] args) {
Collection c = new ArrayList();
String s1 = new String("hello");
String s2 = new String("hello");
c.add(s1);
System.out.println(c.size()); // 1

// 底层调用equals()
c.remove(s2);
System.out.println(c.size()); // 0

/*
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}


*/
}
}

boolean isEmpty();

1
2
3
4
5
6
7
8
9
10
11
import java.util.ArrayList;
import java.util.Collection;

public class _510_Collection接口中常用方法 {
public static void main(String[] args) {
Collection c = new ArrayList();
System.out.println(c.isEmpty()); // true

}
}

Object[] toArray();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.ArrayList;
import java.util.Collection;

public class _510_Collection接口中常用方法 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(100);
c.add("hello");
Object[] o = c.toArray();
for (int i = 0; i < o.length; i++) {
System.out.println(o[i]);
}
/*
100
hello
*/
}
}

public interface Iterator{}

执行原理(这儿应该有一张图…)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.ObjectInput;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class _511_Collection集合迭代 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(100);
c.add("hello");
c.add(3.14444);
for (Iterator it = c.iterator(); it.hasNext(); ){
Object o = it.next();
System.out.println(o);
}
/*
100
hello
3.14444
*/
}
}

List接口特有方法

void add(int index, E element);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class _519_List接口特有方法 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("A");
list.add("B");
list.add("D");

Iterator it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
/*
A
B
D
*/

System.out.println("========");
list.add(2,"C");
it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
/*
A
B
C
D
*/

}
}

E get(int index);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.ArrayList;
import java.util.List;

public class _520_List接口特有方法 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("A");
list.add("B");

Object o = list.get(0);
System.out.println(o);

System.out.println("=======");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
/*
A
=======
A
B
*/
}
}

int indexOf(Object o);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.ArrayList;
import java.util.List;

public class _520_List接口特有方法 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("A");
list.add("B");
list.add("A");

System.out.println(" ======== ");
int i = list.indexOf("A");
System.out.println(i); // 0

}
}

int lastIndexOf(Object o);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.ArrayList;
import java.util.List;

public class _520_List接口特有方法 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("A");
list.add("B");
list.add("A");

i = list.lastIndexOf("A");
System.out.println(i); // 2
}
}

E set(int index, E element);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class _520_List接口特有方法 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("A");
list.add("B");
list.add("A");

list.set(0,"C");
for (int j = 0; j < list.size(); j++) {
System.out.println(list.get(j));
}
/*
C
B
A
*/
}
}

ArrayList

  1. 初始化容量为10,底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量10
  2. size() 是元素个数,不是容量大小
  3. 容量满了之后,增长容量grow()变为1.5倍
  4. 线程不安全的

另一个构造方法 public ArrayList(Collection<? extends E> c) {}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.ArrayList;
import java.util.HashSet;

public class _523_ArrayList另一个构造方法 {
public static void main(String[] args) {

HashSet hashSet = new HashSet();
hashSet.add("A");
hashSet.add("B");

ArrayList list = new ArrayList(hashSet);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}

}
}

如何转化为线程安全的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;

public class _523_ArrayList另一个构造方法 {
public static void main(String[] args) {

HashSet hashSet = new HashSet();
hashSet.add("A");
hashSet.add("B");

ArrayList list = new ArrayList(hashSet);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}

// 非线程安全的
ArrayList lst = new ArrayList();
// 变为线程安全的
Collections.synchronizedList(lst);

lst.add("123");
lst.add("234");

}
}

LinkedList

  1. 底部是双向链表
  2. 检索效率低,增删效率高
  3. 存储内存地址不连续
  4. 线程不安全的

public E get(int index)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.LinkedList;

public class _526_链表优点和缺点 {
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add("a");
list.add("b");

// LinkedList的get(),是遍历链表来的...
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}

/*
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}

Node<E> node(int index) {
// assert isElementIndex(index);

if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
*/
}
}

public boolean add(E e)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.LinkedList;

public class _527_LinkedList源码分析 {
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add("a");
list.add("b");
list.add("c");

/*
public boolean add(E e) {
linkLast(e);
return true;
}

void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}

*/
}
}

Vector

  1. 底层是个数组
  2. 初始化容量为10
  3. 当容量满了后,调用grow(),扩容为原来的2倍
  4. 线程安全的,效率较低,使用较少

public synchronized boolean add(E e)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.Vector;

public class _529_Vecotr集合源码分析 {
public static void main(String[] args) {
Vector vector = new Vector();
vector.add(10);
// 当容量满了后,调用grow()
// 扩容为原来的2倍

/*
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}

private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
*/
}
}

泛型机制

  1. JDK5.0推出的新特性
  2. 泛型这种语法机制,只在程序编译阶段起作用,只是给编译器参考的。(运行阶段泛型没用!)
  3. JDK8之后引入了:自动类型推断机制。(又称为钻石表达式)

指定存储Animal类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class _530_泛型机制 {
public static void main(String[] args) {
// 使用泛型 指定存储Animal类
List<Animal> list = new ArrayList<Animal>();
list.add(new Cat());
list.add(new Bird());

// 遍历
Iterator<Animal> it = list.iterator();
while(it.hasNext()){
Animal a = it.next();
a.move();
}
}
}

class Animal {
public void move(){
System.out.println("Animal move~");
}
}

class Cat extends Animal {
public void catchMouse(){
System.out.println("Cat catch mouse~");
}
}

class Bird extends Animal {
public void fly(){
System.out.println("bird fly~");
}
}

自动类型推断机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.ArrayList;

public class _531_类型自动判断 {
public static void main(String[] args) {
// 自动类型判断,钻石表达式
ArrayList<Animal2> list = new ArrayList<>();


}
}

class Animal2 {

}

自定义泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class _532_自定义泛型 {
public static void main(String[] args) {
Test<String> t = new Test<>();
t.doSome("ABC");

Test<Integer> i = new Test<>();
i.doSome(100);
}
}

class Test<FanXing> {
public void doSome(FanXing o){
System.out.println(o);
}
}

foreach

  1. JDK5.0推出新特性 foreach
1
2
3
4
5
6
7
8
9
public class _533_foreach {
public static void main(String[] args) {
int[] p = {1,2,3,6,1,3,5};
for (int i:p) {
System.out.println(i);
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.ArrayList;

public class _534_foreach {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
list.add(200);
list.add(300);

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

Set

HashSet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.HashSet;
import java.util.Set;

public class _535_演示HashSet集合特点 {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Hello0");
set.add("Hello2");
set.add("Hello1");
set.add("Hello0");

for (String i : set){
System.out.println(i);
}
/*
Hello0
Hello1
Hello2
*/
}
}


TreeSet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.Set;
import java.util.TreeSet;

public class _536_演示TreeSet集合特点 {
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("ABC");
set.add("AB");
set.add("BB");
set.add("AAA");

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

/*
AAA
AB
ABC
BB
*/
}
}

Map接口常用方法

V put(K key, V value);

1
2
3
4
5
6
7
8
9
10
import java.util.HashMap;
import java.util.Map;

public class _537_Map接口常用方法 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");
}
}

V get(Object key);

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.HashMap;
import java.util.Map;

public class _537_Map接口常用方法 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");

Object o = mp.get(100);
System.out.println(o);
}
}

void clear();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.HashMap;
import java.util.Map;

public class _537_Map接口常用方法 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");

Object o = mp.get(100);
System.out.println(o); // 100元

mp.clear();
Object o1 = mp.get(100);
System.out.println(o1); // null
}
}

int size();

1
2
3
4
5
6
7
8
9
10
11
import java.util.HashMap;
import java.util.Map;

public class _537_Map接口常用方法 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");
System.out.println(mp.size()); // 1
}
}

boolean containsKey(Object key);

1
2
3
4
5
6
7
8
9
10
11
import java.util.HashMap;
import java.util.Map;

public class _537_Map接口常用方法 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");
System.out.println(mp.containsKey(100)); // true
}
}

boolean containsValue(Object value);

1
2
3
4
5
6
7
8
9
10
11
import java.util.HashMap;
import java.util.Map;

public class _537_Map接口常用方法 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");
System.out.println(mp.containsValue("100元")); // true
}
}

boolean isEmpty();

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.HashMap;
import java.util.Map;

public class _537_Map接口常用方法 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");
mp.clear();
System.out.println(mp.isEmpty()); // true
}
}

Collection values();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class _538_Map接口常用方法 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");
mp.put(200, "200元");
mp.put(300, "300元");

Collection<Object> values = mp.values();
for (Object i : values){
System.out.println(i);
}
/*
100元
200元
300元
*/
}
}

Set keySet();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class _539_遍历Map集合 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");
mp.put(200, "200元");
mp.put(300, "300元");

Set<Object> keys = mp.keySet();
for (Object i : keys){
System.out.println(i);
}
/*
100
200
300
*/

for (Object i : keys){
System.out.println(mp.get(i));
}
/*
100元
200元
300元
*/
}
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class _540_遍历Map集合的另一种方式 {
public static void main(String[] args) {
Map<Object, Object> mp = new HashMap<>();
mp.put(100, "100元");
mp.put(200, "200元");
mp.put(300, "300元");

Set<Map.Entry<Object, Object>> entries = mp.entrySet();
for (Map.Entry<Object, Object> i : entries){
System.out.println(i.getKey() + " = " + i.getValue());
}

/*
100 = 100元
200 = 200元
300 = 300元
*/
}
}

HashMap

  1. HashMap集合底层是哈希表/散列表的数据结构。
  2. 哈希表是一个怎样的数据结构呢?
    哈希表是一个数组和单向链表的结合体。
    数组∶在查询方面效率很高,随机增删方面效率很低。
    单向链表:在随机增删方面效率较高,在查询方面效率很低。
    哈希表将以上的两种数据结构融合在―起,充分发挥它们各自的优点。
  3. HashMap集合底层的源代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class HashMap {
    // HashMap底层实际上就是一个数组。(一维数组)
    node<K, V>[] table;

    //静态的内部类HashNap.Node
    static class Node<K, V> {
    final int hash; //哈希值是key 的hashCode()方法的执行结果。
    final K key; //存储到Map集合中的那个key
    V value; //存储到Map集合中的那个value
    Node<K, V> next; //下一个节点的内存地址。
    }
    }
  4. 哈希表数据结构:
    (这儿应该有张图…)
  5. HashMap集合的默认初始化容量是16,默认加载因子是0.75
    这个默认加载因子是当HashMap集合底层数组的容量达到75%的时候,数组开始扩容。
    重点: 记住: HashMap集合初始化容量必须是2的幂次,这也是官方推荐的,这是因为达到散列均匀,为了提高HashMap集合的存取效率,所必须的。
  6. 重写hashCode()和equals()通过IDEA要两者同时重写,IDEA自动生成
  7. 放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同时重写hashCode方法和equals方法。
  8. HashMap在JDK8之后
    如果哈希表单向链表中元素超过8个,单向链表这种数据结构会变成红黑树数据结构
    当红黑树上的节点数里小于6时,会重新把红黑树变成单向链表数据结构

同时重写hashCode和equals

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import java.util.HashSet;
import java.util.Objects;

public class _544_同时重写hashCodeequals {
public static void main(String[] args) {
// HashSet底层是HashMap
HashSet<Object> set = new HashSet<>();

Student s1 = new Student("name");
Student s2 = new Student("name");
System.out.println(s1.equals(s2)); // true

System.out.println("s1 hashCode = " + s1.hashCode());
System.out.println("s2 hashCode = " + s2.hashCode());
set.add(s1);
set.add(s2);
// 如果Student类不重写hashCode(),则set.size() = 2
// 重写后为 1
System.out.println(set.size());

}
}

class Student{
private String name;

public Student(String name) {
this.name = name;
}

public Student() {
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name);
}

@Override
public int hashCode() {
return Objects.hash(name);
}
}

HashMap和Hashtable的区别

  1. HashMap和Hashtable一样底层都是哈希表
  2. Hashtable初始化容量11,默认加载因子是0.75
  3. Hashtable 的 key 和 value 都不能为 null
  4. Hashtable 扩容是原容量 * 2 + 1

Hashtable 的 key 和 value 都不能为 null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.HashMap;
import java.util.Hashtable;

public class _548_HashMapHashtable的区别 {
public static void main(String[] args) {
HashMap<Object, Object> mp = new HashMap<>();
mp.put(null, null);
System.out.println(mp.size());

Hashtable<Object, Object> mpt = new Hashtable<>();
// Hashtable 的 key 和 value 都不能为 null
// mpt.put(null, null);
/*
Exception in thread "main" java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:460)
at _548_HashMap和Hashtable的区别.main(_548_HashMap和Hashtable的区别.java:11)
*/


}
}

Properties

  1. key 和 value 用于存 String

getProperty() 和 setProperty()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.Properties;

public class _549_属性类Properties{
public static void main(String[] args) {
Properties ppt = new Properties();
ppt.setProperty("123", "123");
ppt.setProperty("234", "234");

System.out.println(ppt.getProperty("123"));
System.out.println(ppt.get("234"));


}
}

TreeSet

  1. TreeSet集合底层实际上是一个TreeMap
  2. TreeMap集合底层是一个二叉树。
  3. 放到TreeSet集合中的元素,等同于放到TreeMap集合key部分了。
  4. TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小顺序自动排序。称为:可排序集合。

TreeSet对String是可排序的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.TreeSet;

public class _550_演示TreeSetString是可排序的 {
public static void main(String[] args) {
TreeSet<Object> set = new TreeSet<>();
set.add("123");
set.add("1233");
set.add("022");
set.add("0");
// 字典序升序排序
for (Object i : set){
System.out.println(i);
}
/*
0
022
123
1233
*/
}
}

自定义类型实现Comparable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.util.TreeSet;

public class _552_自定义类型实现Comparable接口 {
public static void main(String[] args) {
TreeSet<User> users = new TreeSet<>();
users.add(new User(10));
users.add(new User(30));
users.add(new User(20));

for (User i : users){
System.out.println(i);
}
/*
User{age=10}
User{age=20}
User{age=30}
*/

}
}

class User implements Comparable<User>{
int age;

public User(int age) {
this.age = age;
}

// 比较逻辑
@Override
public int compareTo(User o) { // c1.compareTo(c2);
return age - o.age;
}

@Override
public String toString() {
return "User{" +
"age=" + age +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.TreeSet;

public class _553_比较规则该怎么写 {
public static void main(String[] args) {
TreeSet<Vip> vips = new TreeSet<>();
vips.add(new Vip("ycc",20));
vips.add(new Vip("lsh",19));
vips.add(new Vip("lj",20));

for (Vip i : vips){
System.out.println(i);
}

}
}

class Vip implements Comparable<Vip>{
String name;
int age;

public Vip(String name, int age) {
this.name = name;
this.age = age;
}

/*
compareTo方法的返回值很重要:
返回0表示相同,value会覆盖。
返回>0,会继续在右子树上找。【10 - 9 = 1 ,1 > 0的说明左边这个数字比较大。所以在右子树上找。】
返回<0,会继续在左子树上找。
*/
@Override
public int compareTo(Vip o) {
if(age == o.age){
return name.compareTo(o.name);
}
return age - o.age;
}

@Override
public String toString() {
return "Vip{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

实现比较器接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.util.Comparator;
import java.util.TreeSet;

public class _555_实现比较器接口 {
public static void main(String[] args) {
TreeSet<Integer> set = new TreeSet<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});

set.add(1);
set.add(3);
set.add(2);

for (Integer i : set){
System.out.println(i);
}
/*
3
2
1
*/
}
}

Collections工具类

  1. java.util.collection 集合接口
  2. java.util.collections 集合工具类,方便集合的操作。

Collections.synchronizedList()

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.ArrayList;
import java.util.Collections;

public class _556_Collections工具类 {
public static void main(String[] args) {
// ArrayList 不是线程安全的
ArrayList<Integer> list = new ArrayList<>();
// 变成线程安全的
Collections.synchronizedList(list);
}
}

Collections.sort()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.ArrayList;
import java.util.Collections;

public class _556_Collections工具类 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
// 排序
list.add(200);
list.add(100);
list.add(300);
Collections.sort(list);
for (Integer i : list){
System.out.println(i);
} // 100 200 300
}
}

Prev
2022-01-26 16:40:00 # JavaSE
Next