泛型
泛型:<>
作用:统一数据类型,防止数据类型转换
注意:
泛型中的类型必须是引用数据类型
如果不写泛型,默认是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"));
}
}
通配符 ?
应用场景
- 如果我们在定义类、接口、方法的时候,如果类型不确定,我们可以考虑定义含有泛型的类、方法、接口
- 如果类型不确定,但是能知道以后只能传递某个类的继承体系中的子类或者父类,就可以使用泛型通配符
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接口的实现类
特点:
- 元素唯一
- 元素无序
- 无索引
- 线程不安全
数据结构:
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方法)
比较哈希值,如果哈希值不一样,存储
如果哈希值一样,再比较内容
- 内容不一样,存储
- 内容一样,去重
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'}]
}
}
- 如果HashSet存储自定义类型,重写hashCode和equals方法,让HashCode比较属性的哈希值以及属性的内容;
- 如果不重写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
- 概述:
LinkedHashMapextends
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));
}
}
}
}