泛型 - 集合

2/20/2021 Java

集合类

泛型

Generic

泛型接口

interface MyInterface<T> {
    //接口可创建静态常量
    String name = "NorthBoat";

    void build(T t);

    void show();
}

class MyInterfaceImpl1 implements MyInterface<String> {
    private String str;

    @Override
    public void build(String s) {
        str = s;
    }


    @Override
    public void show() {
        System.out.println(str.toString());
    }
}

class MyInterfaceImpl2<T> implements MyInterface<T> {
    T skt;

    @Override
    public void build(T t) {
        skt = t;
    }

    @Override
    public void show() {
        System.out.println(skt);
    }
}
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

泛型类

class MyGeneric<T> {

    T t;

    void setT(T t1) {
        t = t1;
    }

    void show() {
        System.out.println(t.toString());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

Collection

List

有序、有下标

ArrayList

内部维护一个数组(查找快,增删慢)

默认初始容量:10

add方法:当达到数组上限时创建一个1.5倍大小的新数组,用System中arrayCopy方法复制原来元素至新数组

remove方法:定位要删除元素,创建新数组,去掉要删除元素

get方法:获取对应下标的元素

isEmpty()

contains(Object obj)

listIterator:list的迭代器

 ListIterator lt = list.listIterator();
 while(lt.hasNext()){
      System.out.println(lt.next().toString());
 }
1
2
3
4
Vector

内部同样维护一个数组

有独有的枚举器用于遍历:Enumeration en = vector.elements();

LinkedList

内部维护一个双向链表(查找慢,增删快)

Set

无序、无下标、无重复元素

Set常用方法(与List基本相同):

1、add()

2、size()

3、isEmpty()

4、remove()

5、iterator()

6、contains()

HashSet

内部维护一个哈希表(数组+链表+红黑树)

利用hashcode()和equals()实现不重复

TreeSet

1、存储结构:红黑树——>中序遍历 (二叉搜索)

2、基于排序顺序实现元素不重复

3、实现SortedSet接口,对集合元素自动排序

4、排序规则

4.1、用Comparable接口中CompareTo()方法作为排序标准:在类中重写,当 CompareTo() 返回值为0时,判断两者相同

4.2、利用TreeSet含Comparator接口 (比较器) 的构造方法,在Comparator的匿名内部类中重写compare() 方法,实现比较规则的定义

TreeSet<String> tree = new TreeSet<>(new Comparator<String>(){
        @Override
        public int compare(String s1, String s2){

            int n1 = s1.length()-s2.length();
            int n2 = s1.compareTo(s2);

            return n1==0?n2:n1;
        }
    });
1
2
3
4
5
6
7
8
9
10

Map

Interface

Map常用方法:

  • put (k key, v value)

  • remove(k key)

  • keySet() :返回存有key值的set集合

  • entrySet(): 返回存有entry值的set集合(效率高于keySet())

  • size(): 返回键值对个数

  • containsKey(k key): 是否存在key键

  • containsValue(v value): 是否存在value值

Entry: Map中的静态内部类,储存key和value的键值对 <key, value>

Entry常用方法:getKey() / getValue()

HashMap

使用

/**
 * 存储结构:哈希表
 * 默认初始容量:16(1<<4)	加载因子:0.75(扩容比例)
 * 存储结构:哈希表(数组+链表+红黑树)
 * 线程不安全,效率高,允许null作为键和值
 */

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

public class TestHashMap {
    public static void main(String[] args) {

        HashMap<Student, Integer> hashmap = new HashMap<>();

        Student s1 = new Student("Rose", 32);
        Student s2 = new Student("Harden", 33);
        Student s3 = new Student("Wade", 38);

        hashmap.put(s1, 1);
        hashmap.put(s2, 13);
        hashmap.put(s3, 3);
        //覆盖了第一个s1
        hashmap.put(s1, 25);
        //加进了hashmap ——> 改写掉Student的hashcode和equals方法规定重复规则 ——> 又覆盖了s1
        hashmap.put(new Student("Rose", 32), 4);

        System.out.println("元素个数:" + hashmap.size());
        System.out.println(hashmap.toString());

        //删除
        hashmap.remove(s3);
        System.out.println(hashmap.toString());
        System.out.println("-------------");

        //遍历(重点)
        for(Student stu: hashmap.keySet()){
            System.out.println(stu.toString() + ", " + hashmap.get(stu));
        }
        System.out.println("-------------");

        for(Map.Entry<Student, Integer> entry: hashmap.entrySet()){
            System.out.println(entry.getKey() + ", " + entry.getValue());
        }
        System.out.println("-------------");

        //判断
        System.out.println(hashmap.containsKey(s1));
        System.out.println(hashmap.containsValue(1));

    }
}
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

基本属性

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 16

static final int MAXIMUM_CAPACITY = 1 << 30;

static final float DEFAULT_LOAD_FACTOR = 0.75f;

static final int TREEIFY_THRESHOLD = 8;

static final int UNTREEIFY_THRESHOLD = 6;

static final int MIN_TREEIFY_CAPACITY = 64;

Node<K, V> next;//单向指针

transient Node<K,V>[] table;//数组

transient int size;//元素个数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

方法分析

//构造方法
//刚创建好之后table为null,size为0——>节省空间



//put(k key, v value)方法
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}



//resize()方法节选
final Node<K,V>[] resize() {
    Node<K,V>[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    if (oldCap > 0) {
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        //移位运算,当容量达到75%,oldCap容量*2赋给newCap
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr << 1; // double threshold
    }
    else if (oldThr > 0) // initial capacity was placed in threshold
        newCap = oldThr;
    //当oldCap为空,将初始容量(16)赋给newCap
    else {               // zero initial threshold signifies using defaults
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
}
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

源码总结

  • 初始容量:1<<4 (16)

  • 最大容量:1<<30 (2的30次方)

  • 当容量达到75%时开始扩容

  • 当链表(单向)长度大于8并且数组长度大于64时,开始形成红黑树——>提高查找效率

  • 当链表长度小于6时,将红黑树重新展开为链表

  • jdk1.8之前,链表为头插入,1.8之后为尾插入

HashMap和HashSet

  • HashSet内部维护了一个HashMap

Hashtable

存储结构:哈希表

可以用枚举器、keySet、entrySet遍历

Properties

Properties为Hashtable的子类,要求key和value均为String类

与"流"密切相关

TreeMap

存储结构:红黑树

可以对key进行自动排序,与TreeSet类似,同样要求实现Comparable接口中compareTo方法,或使用Comparator的匿名内部类定制比较器

//实现Comparable接口
public class Student implements Comparable<Student>{

    private String name;
    private int age;

@Override
    public int compareTo(Student o) {
        int n1 = this.name.compareTo(o.getName());
        int n2 = this.age-o.getAge();
        return n1==0?n1:n2;
    }
}

//定制比较器
        TreeMap<Teacher, String> treemap = new TreeMap<>(new Comparator<Teacher>(){
            @Override
            public int compare(Teacher o1, Teacher o2) {
                int n1 = o1.getName().compareTo(o2.getName());
                int n2 = o1.getAge()- o2.getAge();
                return n1==0?n1:n2;
            }
        });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

与TreeSet关系:在TreeSet内部维护了一个NavigableMap对象m,即TreeMap,TreeSet的add方法实际上调用了m的put方法......

Collections工具类

实际上由Collection中一系列静态方法组成

sort

对集合升序排列,必须实现Comparable接口

//sort()排序
Collections.sort(list);
System.out.println(list.toString());
1
2
3

binarySearch

二分查找,返回元素位置

//binarySearch()二分查找:返回下标   必须要sort后才能二分查找
int i = Collections.binarySearch(list, 95);
System.out.println(i);
1
2
3

copy

//copy(dest, sec)复制    必须要集合大小一样才能复制
List<Integer> dest = new ArrayList<>();
for(int j = 0; j < list.size(); j++){
    dest.add(j);
}
Collections.copy(dest, list);
System.out.println(dest.toString());
1
2
3
4
5
6
7

reverse

 //reverse(list)反转
Collections.reverse(list);
System.out.println(list.toString());
1
2
3

shuffle

洗牌:打乱元素顺序

//shuffle(list)洗牌:将元素顺序打乱
Collections.shuffle(list);
System.out.println(list.toString());
1
2
3

list.toArray

集合转成数组

//集合转成数组
Integer[] arr = list.toArray(new Integer[0]);
for(int z = 0; z < arr.length; z++){
    System.out.println(arr[z]);
}
1
2
3
4
5

asList

数组转成集合

 //数组转成集合
        String[] str = {"张三", "李四", "王五"};
        List<String> list1 = Arrays.asList(str);
        System.out.println(list1.toString());
1
2
3
4

该集合是一个受限集合,不能进行添加和删除

把基本类型转化成集合时,要把其修改为包装类

Last Updated: 9/13/2024, 1:34:55 AM
妖风过海
刘森