Java(集合)

泛型

泛型:<>
作用:统一数据类型,防止数据类型转换
注意:
泛型中的类型必须是引用数据类型
如果不写泛型,默认是Object

  • 含有泛型的类
package alive.g_genericity;

import java.util.Arrays;

/**
 * @Author zyj
 * @Date 2024/09/14 17:54
 * @Description
 */
public class GenericityEntity<E> {
    Object[] arr = new Object[10];
    int size = 0;

    public boolean add(E e) {
        arr[size] = e;
        size++;
        return true;
    }

    public E getElement(int index) {

        return (E) arr[index];
    }

    @Override
    public String toString() {
        return "GenericityEntity{" +
                "arr=" + Arrays.toString(arr) +
                '}';
    }
}

package alive.g_genericity;

/**
 * @Author zyj
 * @Date 2024/09/14 18:12
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        GenericityEntity<String> ge = new GenericityEntity<>();
        ge.add("alex");
        ge.add("Tom");
        System.out.println("ge = " + ge);
        GenericityEntity<Integer> gy = new GenericityEntity<>();
        gy.add(1);
        gy.add(2);
        gy.add(3);
        gy.add(4);
        System.out.println("gy = " + gy);

    }
}

  • 含有泛型的方法

格式:
修饰符

  public static <E> void print(ArrayList<E> list, E... e) {
        for (E el : e) {
            list.add(el);
        }
}
  • 含有泛型的接口

格式:
public Interface 接口名< E >{
}

在实现接口的时候,如果没有确定类型,,只能在new的时候确定

package alive.h_genericity;

/**
 * @Author zyj
 * @Date 2024/09/14 19:01
 * @Description
 */
public class GeneInterfaceImpl<E> implements GeneInterface<E> {

    @Override
    public E get(E e) {
        return e;
    }
}

package alive.h_genericity;

/**
 * @Author zyj
 * @Date 2024/09/14 19:00
 * @Description
 */
public interface GeneInterface<E> {
    public E get(E e);
}

package alive.h_genericity;


/**
 * @Author zyj
 * @Date 2024/09/14 19:06
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        GeneInterfaceImpl<String> gi = new GeneInterfaceImpl<>();
        System.out.println(" gi=》 " + gi.get("alex"));
    }
}

在实现接口的时候确定类型

package alive.h_genericity;

/**
 * @Author zyj
 * @Date 2024/09/14 19:00
 * @Description
 */
public interface GeneInterface<E> {
    public E get(E e);
}

package alive.h_genericity;

/**
 * @Author zyj
 * @Date 2024/09/14 19:01
 * @Description
 */
public class GeneInterfaceImpl implements GeneInterface<String> {

    @Override
    public String get(String s) {
        return s;
    }
}

package alive.h_genericity;


/**
 * @Author zyj
 * @Date 2024/09/14 19:06
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        GeneInterfaceImpl gf = new GeneInterfaceImpl();
        System.out.println(gf.get("Tom"));
    }
}

通配符 ?

应用场景

  1. 如果我们在定义类、接口、方法的时候,如果类型不确定,我们可以考虑定义含有泛型的类、方法、接口
  2. 如果类型不确定,但是能知道以后只能传递某个类的继承体系中的子类或者父类,就可以使用泛型通配符
package alive.i_genericity;

import java.util.ArrayList;

/**
 * @Author zyj
 * @Date 2024/09/14 19:18
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        ArrayList<String> arr1 = new ArrayList<>();
        arr1.add("a");
        arr1.add("b");
        arr1.add("c");
        ArrayList<Integer> arr2 = new ArrayList<>();
        arr2.add(1);
        arr2.add(2);
        arr2.add(3);
        print(arr1);
        print(arr2);
    }

    public static void print(ArrayList<?> list) {
        for (Object el : list) {
            System.out.println("el = " + el);
        }
    }
}

泛型的上限下限

可以规定泛型的范围
上限:
格式:< ? extends 类型>,? 只能接收extends 后面的本类类型以及子类类型
下限:
格式:<? super 类型>,? 只能接收super后面的本类类型以及父类类型

package alive.j_genericity;

import java.util.ArrayList;
import java.util.Collection;

/**
 * @Author zyj
 * @Date 2024/09/14 19:34
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        /**
         * Integer -> Number -> Object
         * String -> Object
         */
        ArrayList<String> str = new ArrayList<>();
        ArrayList<Integer> inte = new ArrayList<>();
        ArrayList<Number> num = new ArrayList<>();
        ArrayList<Object> obj = new ArrayList<>();
        get1(str); // 错误
        get1(inte);
        get1(num);
        get1(obj); // 错误
        get2(str); // 错误
        get2(inte); // 错误
        get2(num);
        get2(obj);
    }

    public static void get1(Collection<? extends Number> collection) {

    }

    public static void get2(Collection<? super Number> collection) {

    }
}

案例

package alive.k_example;

import java.util.ArrayList;
import java.util.Collections;

/**
 * @Author zyj
 * @Date 2024/09/15 13:50
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        String kind = "♥-♠-♦-♣";
        String[] kindArr = "♥-♠-♦-♣".split("-");
        String[] arrItem = "A-2-3-4-5-6-7-8-9-10-J-Q-K".split("-");
        ArrayList<String> poker = new ArrayList<>();
        for (int j = 0; j < arrItem.length; j++) {
            for (int i = 0; i < kindArr.length; i++) {

                poker.add(kindArr[i] + arrItem[j]);
            }
        }
        poker.add("BJ");
        poker.add("SJ");
        ArrayList<String> p1 = new ArrayList<>();
        ArrayList<String> p2 = new ArrayList<>();
        ArrayList<String> p3 = new ArrayList<>();
        ArrayList<String> sub = new ArrayList<>();
        Collections.shuffle(poker);
        for (int i = 0; i < poker.size(); i++) {
            String p = poker.get(i);
            if (i >= 51) {
                sub.add(p);
            } else if (i % 3 == 0) {
                p1.add(p);
            } else if (i % 3 == 1) {
                p2.add(p);
            } else if (i % 3 == 2) {
                p3.add(p);
            }
        }
        System.out.println("p1 = " + p1);
        System.out.println("p2 = " + p2);
        System.out.println("p3 = " + p3);
        System.out.println("sub = " + sub);
    }
}

Set集合

Set和Map密切相关
Map的遍历需要先变成单列集合,只能变成Set集合

HashSet集合

HashSet是Set接口的实现类

特点:

  1. 元素唯一
  2. 元素无序
  3. 无索引
  4. 线程不安全

数据结构:
JDK8之前:哈希表 = 数组 + 链表
JDK8之后:哈希表 = 数组 + 链表 + 红黑树(增加查询速度)

package alive.l_set;

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

/**
 * @Author zyj
 * @Date 2024/09/15 15:08
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        HashSet<String> setArr = new HashSet<>();
        setArr.add("A");
        setArr.add("B");
        setArr.add("C");
        setArr.add("D");
        setArr.add("E");
        System.out.println("setArr = " + setArr);
        // 迭代器遍历
        Iterator<String> it = setArr.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
        // 增强for
        for (String s : setArr) {
            System.out.println(s);
        }
    }
}

LinkedHashSet集合

LinkedHashSet extends HashSet

特点:
元素唯一
元素有序
无索引
线程不安全

数据结构
哈希表 + 双向链表

package alive.l_set;

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

/**
 * @Author zyj
 * @Date 2024/09/15 15:08
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        LinkedHashSet<String> setArr = new LinkedHashSet<>();
        setArr.add("A");
        setArr.add("B");
        setArr.add("C");
        setArr.add("D");
        setArr.add("E");
        System.out.println("setArr = " + setArr);
        // 迭代器遍历
        Iterator<String> it = setArr.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
        // 增强for
        for (String s : setArr) {
            System.out.println(s);
        }
    }
}

哈希值

哈希值是有计算机算出来的十进制数,可以看做对象的地址值
获取对象的哈希值,使用的是Object中的方法
public native int hashCode()

package alive.m_hash;

/**
 * @Author zyj
 * @Date 2024/09/17 14:31
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        Person jack = new Person(10, "Jack");
        Person tom = new Person(20, "Tom");
        System.out.println("jack = " + jack);
        System.out.println("tom = " + tom);
        System.out.println("jack.hashCode() = " + jack.hashCode());
        System.out.println("tom.hashCode() = " + tom.hashCode());
        System.out.println("jack=>" + Integer.toHexString(jack.hashCode()));
        System.out.println("Tom=>" + Integer.toHexString(tom.hashCode()));
        /**
         * jack = alive.m_hash.Person@682a0b20
         * tom = alive.m_hash.Person@3d075dc0
         * jack.hashCode() = 1747585824
         * tom.hashCode() = 1023892928
         * jack=>682a0b20
         * Tom=>3d075dc0
         */
    }
}

package alive.m_hash;

/**
 * @Author zyj
 * @Date 2024/09/17 14:31
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = new String("abc");
        System.out.println("s1=>" + s1.hashCode());
        System.out.println("s2=>" + s2.hashCode());
        /**
         * s1=>96354
         * s2=>96354
         */
        String s3 = "通话";
        String s4 = "重地";
        System.out.println("s3=>" + s3.hashCode());
        System.out.println("s4=>" + s4.hashCode());
        /**
         * s3=>1179395
         * s4=>1179395
         */
    }
}

注意:
如果重写了hashCode方法,那计算的就是对象内容的哈希值
如果不重写hashCode方法,默认就是计算对象的哈希值

总结:
内容一样哈希值可能不一样
哈希值一样内容可能不一样

哈希值的计算

 String s1 = new String("Tom");

 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;
    }
public static int hashCode(byte[] value) {
        int h = 0;
        // [84,111,109]
        for (byte v : value) {
            h = 31 * h + (v & 0xff);
        }
        return h;
}

(v & 0xff):v和0xff做与运算,得到的还是本身
ASCII:
T->84
o->111
m->109
h = 31*(31*(31 * 0 + 84 )+111)+109 = 84274

31是什么?
31是个质数,31这个数通过大量的计算统计,得到31可以降低内容不一样,但是哈希值一样的情况内容不一样,哈希值一样(哈希冲突、哈希碰撞)

package alive.m_hash;

/**
 * @Author zyj
 * @Date 2024/09/17 14:31
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        Person p1 = new Person(12, "Tom");
        Person p2 = new Person(16, "Tom");
        Person p3 = new Person(12, "Tom");
        String s1 = new String("Tom");
        String s2 = "Jack";
        System.out.println("s1.hashCode=>" + s1.hashCode());
        System.out.println("s2.hashCode=>" + s2.hashCode());
        System.out.println("p1.hashCode=>" + p1.hashCode());
        System.out.println("p2.hashCode=>" + p2.hashCode());
        System.out.println("p3.hashCode=>" + p3.hashCode());
        
    }
}

s1.hashCode=>84274
s2.hashCode=>2300927
p1.hashCode=>85607
p2.hashCode=>85731
p3.hashCode=>85607
p1和p3 的哈希值是一样的,因为我们重写了hashCode方法,比较的是内容

 public int hashCode() {
        return Objects.hash(age, name);
 }

HashSet 去重

先计算元素的哈希值(重写hasCode方法)再比较内容(重写equals方法)
比较哈希值,如果哈希值不一样,存储
如果哈希值一样,再比较内容

  1. 内容不一样,存储
  2. 内容一样,去重
package alive.n_hash;

import java.util.HashSet;

/**
 * @Author zyj
 * @Date 2024/09/18 10:21
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("abc");
        set.add("abc");
        set.add("通话");
        set.add("重地");
        System.out.println("set = " + set);
        // set = [通话, 重地, abc]
    }
}

存储自定义对象

package alive.o_hashSet;

import alive.m_hash.Person;

import java.util.HashSet;

/**
 * @Author zyj
 * @Date 2024/09/18 10:26
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        Person p1 = new Person(10, "Tom");
        Person p2 = new Person(11, "Tom");
        Person p3 = new Person(10, "Tom");
        HashSet<Person> set = new HashSet<>();
        set.add(p1);
        set.add(p2);
        set.add(p3);
        System.out.println("set = " + set);
        //set = [Person{age=10, name='Tom'}, Person{age=11, name='Tom'}]
    }
}
  1. 如果HashSet存储自定义类型,重写hashCode和equals方法,让HashCode比较属性的哈希值以及属性的内容;
  2. 如果不重写hashCode和equals方法,默认值调用的是Object中没有重写的方法,不同的对象哈希值是不一样的,equals比较的地址值夜不一样所以此时对象的属性值一样,也不能去重复

双列集合

在这里插入图片描述

Map

  • 是双列集合的顶级接口
  • 元素特点:
    都是由Key和value组成,键值对

HashMap

  • HashMap是Map的实现类
  • 特点
    key唯一,value可重复;
    如果key重复,则会发生value覆盖;
    无序
    无索引
    线程不安全
    可以存null键和null值
  • 数据结构
    哈希表
  • 方法:
    V put(K key,V value):添加元素,返回值是被覆盖的value
    V remove(Object key):根据Key删除键值对,返回的被删除的value
    V get(Object key):根据key获取value
    boolean containsKey(Object key):判断集合中是否包含指定的key
    Collection< V > values():获取集合中所有的value,转存到Collection集合中
package alive.p_map;

import java.util.HashMap;

/**
 * @Author zyj
 * @Date 2024/09/18 11:50
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        HashMap<Integer, String> map = new HashMap<>();
        // null
        System.out.println(map.put(1, "韩立"));
        // Jack
        System.out.println(map.put(1, "南宫婉"));
        map.put(2, "紫灵");
        map.put(3, "元瑶");
        System.out.println("map = " + map);
        System.out.println(map.remove(3));// 元瑶
        System.out.println(map.remove(4));// null
        System.out.println(map.get(1));//南宫婉
        System.out.println(map.get(3)); // null
        System.out.println(map.containsKey(2));// true
        System.out.println(map.containsKey(3));//false
        System.out.println(map.values());// [南宫婉, 紫灵]
        map.put(null, null);
        System.out.println(map);
    }
}

LinkedHashMap

  • 概述:
    LinkedHashMap extends HashMap
  • 方法: 和HashMap一样
package alive.q_map;

import java.util.LinkedHashMap;

/**
 * @Author zyj
 * @Date 2024/09/18 12:05
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
        map.put(1, "韩立");
        map.put(2, "南宫婉");
        map.put(3, "紫灵");
        map.put(4, "元瑶");
        System.out.println(map);
    }
}

遍历

package alive.p_map;

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

/**
 * @Author zyj
 * @Date 2024/09/18 11:50
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1, "韩立");
        map.put(2, "南宫婉");
        map.put(3, "紫灵");
        map.put(4, "元瑶");
        Set<Integer> keys = map.keySet();
        for (Integer key : keys) {
            String value = map.get(key);
            System.out.println("value = " + value);
        }
        Set<Map.Entry<Integer, String>> entries = map.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
            Integer key = entry.getKey();
            String value = entry.getValue();
            System.out.println("key = " + key);
            System.out.println("value = " + value);
        }


    }
}

map去重

package alive.r_map;

import java.util.HashMap;

/**
 * @Author zyj
 * @Date 2024/09/18 13:37
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        HashMap<Person, Integer> map = new HashMap<>();
        map.put(new Person(10, "Tom"), 1);
        map.put(new Person(12, "Tom"), 2);
        map.put(new Person(10, "Tom"), 3);
        System.out.println("map = " + map);
        //map = {Person{age=12, name='Tom'}=2, Person{age=10, name='Tom'}=3}
    }
}

package alive.r_map;

import java.util.Objects;

/**
 * @Author zyj
 * @Date 2024/09/18 13:36
 * @Description
 */
public class Person {
    private int age;
    private String name;

    public Person() {
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    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;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

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

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

如果key是自定义类型,去重复需要重写hasCode和equals方法,去重过程和set一样,因为set集合的元素底层都是保存到map的key位置上

案例

  • 使用map集合统计字符出现的次数
package alive.s_map;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;

/**
 * @Author zyj
 * @Date 2024/09/18 13:43
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = scanner.next();
        String[] arr = str.split("");
        System.out.println(Arrays.toString(arr));
        HashMap<String, Integer> map = new HashMap<>();
        for (String s : arr) {
            if (map.get(s) == null) {
                map.put(s, 1);
            } else {
                map.put(s, map.get(s) + 1);
            }
        }
        System.out.println(map);
    }
}

  • map 实现斗地主案例
package alive.s_map;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

/**
 * @Author zyj
 * @Date 2024/09/18 13:43
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        // ① 创建一个数组存储花色
        String[] colors = "♥♠♣♦".split("");
        String[] number = "2-3-4-5-6-7-8-9-10-J-Q-K-A".split("-");
        HashMap<Integer, String> pokerMap = new HashMap<>();
        ArrayList<Integer> porkers = new ArrayList<>();
        porkers.add(0);
        porkers.add(1);
        int key = 2;
        for (String num : number) {
            for (String color : colors) {
                pokerMap.put(key, color + num);
                porkers.add(key);
                key++;
            }
        }
        pokerMap.put(0, "BJ");
        pokerMap.put(1, "SJ");
        System.out.println("porkers = " + porkers);
        System.out.println("pokerMap = " + pokerMap);
        Collections.shuffle(porkers);
        System.out.println("porkers = " + porkers);
        ArrayList<Integer> pl1 = new ArrayList<>();
        ArrayList<Integer> pl2 = new ArrayList<>();
        ArrayList<Integer> pl3 = new ArrayList<>();
        ArrayList<Integer> last = new ArrayList<>();
        for (int i = 0; i < porkers.size(); i++) {
            Integer value = porkers.get(i);
            if (i >= 51) {
                last.add(value);
            } else if (i % 3 == 0) {
                pl1.add(value);
            } else if (i % 3 == 1) {
                pl2.add(value);
            } else if (i % 3 == 2) {
                pl3.add(value);
            }
        }
        Collections.sort(pl1);
        Collections.sort(pl2);
        Collections.sort(pl3);
        System.out.println("pl1 = " + pl1);
        System.out.println("pl2 = " + pl2);
        System.out.println("pl3 = " + pl3);
        System.out.println("last = " + last);
        showPoker("pl1", pl1, pokerMap);
        showPoker("pl2", pl2, pokerMap);
        showPoker("pl3", pl3, pokerMap);
        showPoker("底牌", last, pokerMap);

    }

    private static void showPoker(String name, ArrayList<Integer> arr, HashMap<Integer, String> map) {
        String str = "";
        for (Integer key : arr) {
            str += map.get(key);
        }
        System.out.println(name + "===>" + str);
    }
}

哈希表存储

哈希表存储数据去重过程
① 先比较元素的哈希值(重写hashCode)再比较内容(重写equals)
② 如果哈希值不一样,表示内容不一致,存入
③ 如果哈希值一样,内容不一样(哈希碰撞,哈希冲突)存入
④ 如果哈希值一样,内容一样,去重复

组成部分:数组、链表、红黑树

在这里插入图片描述

注意点:
① 哈希表中的数组长度默认为 16,第一次put的时候数组才会被初始化为长度为16的数组
② 哈希表中有一个加载因子,0.75F:数组存储达到75%的时候扩容2
③ 如果链表长度达到8并且数组容量>=64时,链表会自动转为红黑树
④ 如果删除元素,元素个数<=6,红黑树会转回链表

1.HashMap底层数据数据结构:哈希表
2.jdk7:哈希表 = 数组+链表
jdk8:哈希表 = 数组+链表+红黑树
3.
先算哈希值,此哈希值在HashMap底层经过了特殊的计算得出
如果哈希值不一样,直接存
如果哈希值一样,再去比较内容,如果内容不一样,也存
如果哈希值一样,内容也一样,直接去重复(后面的value将前面的value覆盖)

哈希值一样,内容不一样->哈希冲突(哈希碰撞)
4.要知道的点:
a.在不指定长度时,哈希表中的数组默认长度为16,HashMap创建出来,一开始没有创建长度为16的数组
b.什么时候创建的长度为16的数组呢?在第一次put的时候,底层会创建长度为16的数组
c.哈希表中有一个数据加[加载因子]->默认为0.75(加载因子)->代表当元素存储到百分之75的时候要扩容了->2倍
d.如果对个元素出现了哈希值一样,内容不一样时,就会在同一个索引上以链表的形式存储,当链表长度达到8并且当前数组长度>=64时,链表就会改成使用红黑树存储
如果后续删除元素,那么在同一个索引位置上的元素个数小于6,红黑树会变回链表
e.加入红黑树目的:查询快

  • 特殊的变量
    ① default_initial_capacity:HashMap默认容量 16
    ② default_load_factor:HashMap默认加载因子 0.75f
    ③ threshold:扩容的临界值 等于 容量*0.75 = 12 第一次扩容
    ④ treeify_threshold:链表长度默认值,转为红黑树:8
    ⑤ min_treeify_capacity:链表被树化时最小的数组容量:64
  • 注意点
  • 哈希表中有数组,但是为什么是无索引?
    哈希表虽然有索引,但是set和map没有索引,因为存储数据的时候可能会在同一索引下形成链表结构,如果在一个索引下获取了一个链表,就会有多个元素,不知道是哪个元素,所以就取消了索引操作;
    比如说,存入的时候 ① ->-> ③,但是取出的时候 ① ->->
  • 为什么HashMap是无序的,LinkedHashMap是有序的?
    在这里插入图片描述
    HashMap:是单向链表;
    在这里插入图片描述
    遍历到第一个节点,每个节点就串起来了,存入的① ->->->

HashMap无参构造

//HashMap中的静态成员变量
static final float DEFAULT_LOAD_FACTOR = 0.75f;
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

使用无参数构造方法创建HashMap对象,将加载因子设置为默认的加载因子,loadFactor=0.75F。

HashMap有参构造

HashMap(int initialCapacity, float loadFactor) ->创建Map集合的时候指定底层数组长度以及加载因子
    
public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
    	throw new IllegalArgumentException("Illegal initial capacity: " +
    initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
    	initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
    	throw new IllegalArgumentException("Illegal load factor: " +
    loadFactor);
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);//10
}

带有参数构造方法,传递哈希表的初始化容量和加载因子

  • 如果initialCapacity(初始化容量)小于0,直接抛出异常。
  • 如果initialCapacity大于最大容器,initialCapacity直接等于最大容器
    MAXIMUM_CAPACITY = 1 << 30 是最大容量 (1073741824)
  • 如果loadFactor(加载因子)小于等于0,直接抛出异常
  • tableSizeFor(initialCapacity)方法计算哈希表的初始化容量。
    注意:哈希表是进行计算得出的容量,而初始化容量不直接等于我们传递的参数。

红黑树集合

TreeSet

① TreeSet是Set的实现类
② 特点:
对元素进行排序
无索引
不能存null
线程不安全
元素唯一
③ 数据结构:红黑树

构造方法:
TreeSet():构造一个新的空set,可根据其元素的自然顺序进行排序->ASCII
TreeSet(Comparator<? super E>compoarator):构造一个新的空TreeSet,它根据指定比较器进行排序

package alive.u_treeset;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @Author zyj
 * @Date 2024/09/18 16:37
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        TreeSet<String> treeSet1 = new TreeSet<>();
        treeSet1.add("a");
        treeSet1.add("c");
        treeSet1.add("d");
        treeSet1.add("b");
        treeSet1.add("e");
        System.out.println("treeSet = " + treeSet1);
        //treeSet = [a, b, c, d, e]
        TreeSet<Person> treeSet2 = new TreeSet<>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        });

        treeSet2.add(new Person(10, "Tom"));
        treeSet2.add(new Person(8, "Tom"));
        treeSet2.add(new Person(7, "Tom"));
        treeSet2.add(new Person(16, "Tom"));
        System.out.println("treeSet2 = " + treeSet2);
    }
}

TreeMap

package alive.v_treemap;

import java.util.Comparator;
import java.util.TreeMap;

/**
 * @Author zyj
 * @Date 2024/09/18 16:52
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        TreeMap<Integer, String> treeMap1 = new TreeMap<>();
        treeMap1.put(1, "韩立");
        treeMap1.put(3, "南宫婉");
        treeMap1.put(2, "紫灵");
        treeMap1.put(4, "元瑶");
        System.out.println("treeMap1 = " + treeMap1);
        //treeMap1 = {1=韩立, 2=紫灵, 3=南宫婉, 4=元瑶}
        TreeMap<Person, Integer> treeMap2 = new TreeMap<>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        treeMap2.put(new Person(1, "韩立"), 1);
        treeMap2.put(new Person(3, "南宫婉"), 1);
        treeMap2.put(new Person(2, "紫灵"), 1);
        treeMap2.put(new Person(4, "元瑶"), 1);
        System.out.println("treeMap2 = " + treeMap2);

    }
}

Hashtable和Vector

Hashtable

① Hashtable是Map的实现类
② 特点:
key唯一,value可重复
无序
无索引
线程不安全
不能存储null键和null值
③数据结构:哈希表

package alive.w_hashtable;

import java.util.Hashtable;

/**
 * @Author zyj
 * @Date 2024/09/18 17:15
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        Hashtable<Integer, String> t1 = new Hashtable<>();
        t1.put(1, "韩立");
        t1.put(2, "南宫婉");
        t1.put(1, "历飞羽");
        t1.put(5, "紫灵");
        t1.put(4, "元瑶");
        System.out.println("t1 = " + t1);
        // t1 = {5=紫灵, 4=元瑶, 2=南宫婉, 1=历飞羽}
    }
}

  • HashMap与Hashtable的区别

相同点:元素无序,无索引,key唯一
不同点:
HashMap:线程不安全,可以存储null键,null值
Hashtable:线程安全,不可以存储null键,null值

Vector

① Vector 是List的实现类
② 特点:
元素有序
有索引
元素可重复
线程安全
③ 数据结构:数组
④ 如果用无参构造创建对象,数组的初始容量为10,自动扩容2
⑤ 如果用有参构造创建对象,数组出事容量为传入的长度,自动扩容,扩的是老数组长度 + 指定的容量增量

package alive.x_vector;

import java.util.Vector;

/**
 * @Author zyj
 * @Date 2024/09/18 17:24
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        Vector<String> v = new Vector<>();
        v.add("b");
        v.add("a");
        v.add("d");
        v.add("c");
        System.out.println("v = " + v);
        for (String s : v) {
            System.out.println("s = " + s);
        }
    }
}

Vector源码

Vector():构造一个空间向量,使其内部数据数组的大小为10,其标准容量增量为0
Vector(int initialcapacity,int capacityIncrement):使用指定的初始容量和容量增量构造一个空的向量

 public Vector() {
        this(10);
 }
 public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
}   

Properties集合(属性集)

① Properties 继承自 Hashtable
② 特点:
key唯一,value可重复
无序
无索引
线程安全
不能存null键,null值
Properties的key和value类型默认为String
③ 数据结构:哈希表
④ 特有方法:
Object setProperty(String key,String value):存储键值对
String getProperty(String key):根据key获取value
Set< String > stringPropertyNames:获取所有的key,保存到set集合中
void load(InputStream instream):将流中的数据加载到Propertites集合中

package alive.y_properties;

import java.util.Properties;
import java.util.Set;

/**
 * @Author zyj
 * @Date 2024/09/18 17:49
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        Properties pt = new Properties();
        pt.put("user", "root");
        pt.put("password", "root@123");
        pt.setProperty("ip", "192.168.1.12");
        pt.setProperty("port", "8733");
        System.out.println("pt = " + pt);
        String port = pt.getProperty("port");
        System.out.println("port = " + port);
        Set<String> str = pt.stringPropertyNames();
        for (String s : str) {
            System.out.println("s = " + s);
        }
    }
}

集合嵌套

  • list in list
package alive.z_list_in_list;

import java.util.ArrayList;

/**
 * @Author zyj
 * @Date 2024/09/18 17:56
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        ArrayList<String> list2 = new ArrayList<>();
        list1.add("韩立");
        list1.add("张铁");
        list1.add("乌丑");
        list2.add("紫灵");
        list2.add("南宫婉");
        list2.add("元瑶");
        System.out.println("list1 = " + list1);
        System.out.println("list2 = " + list2);
        ArrayList<ArrayList<String>> arrayLists = new ArrayList<>();
        arrayLists.add(list1);
        arrayLists.add(list2);
        for (ArrayList<String> arrayList : arrayLists) {
            for (String s : arrayList) {
                System.out.println("s = " + s);
            }
        }
        /**
         * list1 = [韩立, 张铁, 乌丑]
         * list2 = [紫灵, 南宫婉, 元瑶]
         * s = 韩立
         * s = 张铁
         * s = 乌丑
         * s = 紫灵
         * s = 南宫婉
         * s = 元瑶
         */
    }
}

  • list in map
package alive.z_list_in_list;

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

/**
 * @Author zyj
 * @Date 2024/09/18 17:56
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        HashMap<Integer, String> c_1 = new HashMap<>();
        HashMap<Integer, String> c_2 = new HashMap<>();
        c_1.put(101, "韩立");
        c_1.put(102, "张铁");
        c_1.put(103, "萧诧");
        c_2.put(104, "元瑶");
        c_2.put(105, "紫灵");
        c_2.put(106, "南宫婉");
        System.out.println("c_1 = " + c_1);
        System.out.println("c_2 = " + c_2);
        ArrayList<HashMap<Integer, String>> scl = new ArrayList<>();
        scl.add(c_1);
        scl.add(c_2);
        for (HashMap<Integer, String> sc : scl) {
            Set<Map.Entry<Integer, String>> entries = sc.entrySet();
            for (Map.Entry<Integer, String> entry : entries) {
                System.out.println("key = " + entry.getKey());
                System.out.println("value = " + entry.getValue());
            }
        }
        /**
         * c_1 = {101=韩立, 102=张铁, 103=萧诧}
         * c_2 = {104=元瑶, 105=紫灵, 106=南宫婉}
         * key = 101
         * value = 韩立
         * key = 102
         * value = 张铁
         * key = 103
         * value = 萧诧
         * key = 104
         * value = 元瑶
         * key = 105
         * value = 紫灵
         * key = 106
         * value = 南宫婉
         */
    }
}

  • map in map
package alive.z_list_in_list;

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

/**
 * @Author zyj
 * @Date 2024/09/18 17:56
 * @Description
 */
public class Test {
    public static void main(String[] args) {
        HashMap<Integer, String> c_1 = new HashMap<>();
        HashMap<Integer, String> c_2 = new HashMap<>();
        c_1.put(101, "韩立");
        c_1.put(102, "张铁");
        c_1.put(103, "萧诧");
        c_2.put(104, "元瑶");
        c_2.put(105, "紫灵");
        c_2.put(106, "南宫婉");
        System.out.println("c_1 = " + c_1);
        System.out.println("c_2 = " + c_2);
        HashMap<String, HashMap<Integer, String>> map = new HashMap<>();
        map.put("C_1", c_1);
        map.put("C_2", c_2);
        Set<Map.Entry<String, HashMap<Integer, String>>> entries = map.entrySet();
        for (Map.Entry<String, HashMap<Integer, String>> entry : entries) {

            HashMap<Integer, String> mapValue = entry.getValue();
            Set<Integer> keys = mapValue.keySet();
            for (Integer key : keys) {
                System.out.println(entry.getKey() + "==>" + key + "==>" + mapValue.get(key));
            }
        }
    }
}

IO流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值