集合框架
文章目录
JCF: Java Collection Framework
由于操作数组很麻烦: 扩容,缩容
Java搞了一个集合框架来代替数组: 在数组的基础之上封装了一层,更方便开发者使用。
集合框架的基本结构
简化版:
Collection: 父接口->管理列
List: 子接口
**ArrayList: 实现类 , 存放有序的,不唯一的数据**
LinkedList: 实现类
Set: 子接口
**HashSet: 实现类, 存放无序,唯一的数据, 通常用来去重**
TreeSet:实现类
Map: 父接口 -> 管理键值对 key => value
**HashMap: 实现类: 存放键值对**
TreeMap: 实现类
ArraysList***
初始化
// 初始化集合
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList(10);
ArrayList list3 = new ArrayList(list2);
// 多态的方式
List list4 = new ArrayList();
增删改查
增加
// 添加元素- 直接添加到末尾
list4.add(1);
list4.add("2");
list4.add(true);
// 输出
System.out.println(list4);
list4.add(1, "jack");
System.out.println(list4);
// 添加一个集合
list1.add("rose");
list1.add("lucy");
list4.addAll(list1);
System.out.println(list4);
// 指定位置插入集合
list2.add("gxa");
list4.addAll(3, list2);
System.out.println(list4);
删除
// 删除数据-remove
System.out.println(list4.remove(0));
System.out.println(list4);
list4.remove("lucy");
System.out.println(list4);
修改
// 修改数据-set
System.out.println(list4.set(0, "JACK"));
System.out.println(list4);
查
获取数据
// 查询
// 获取对应的元素
System.out.println(list4.get(2));
// 获取对应元素的下标
System.out.println(list4);
list4.add(2, "tom");
list4.add("tom");
System.out.println(list4);
// 没有元素 -1
System.out.println(list4.indexOf("1"));
System.out.println(list4.indexOf("tom"));
System.out.println(list4.lastIndexOf("tom"));
// 是否包含
System.out.println(list4.contains("1"));
System.out.println(list4.contains("tom"));
遍历
iterator()
// 获取迭代器
Iterator iterator = list4.iterator();
// 判断是否有下一个元素
while (iterator.hasNext()){
// 取出对应的元素
System.out.println(iterator.next());
}
for
需要知道范围
size()方法获取集合的长度。
注意: 这个size不是底层数组的长度
for (int i = 0; i < list4.size(); i++) {
System.out.println(list4.get(i));
}
foreach
使用最多的方式
// foreach的方式-使用最多
for (Object o : list4) {
System.out.println(o);
}
泛型的使用
菱形语法
规定集合的数据类型
泛型只能使用: 引用数据类型, 不能使用基本数据类型
泛型的出现: 减少出错的概率。
List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(1);
nums.add(1);
nums.add(1);
for (Integer num : nums) {
System.out.println(num);
}
// 用户列表
List<Member> members = new ArrayList<>();
members.add(new Member("jack1", "123123", 18));
members.add(new Member("jack2", "123123", 19));
members.add(new Member("jack3", "123123", 20));
members.add(new Member("jack4", "123123", 21));
for (Member member : members) {
System.out.println(member);
}
底层
ArrayList的底层是通过数组来存放数据的:
从构造器的底层来看: 是为了初始化底层的elementData
从添加的方法: 当底层的数组长度不够的时候才会去扩容。
从删除的方法:
elementData[--size] = null; // clear to let GC do its work
// 这个地方给了一个提示: 不用的数据尽量赋值为null
// 这样有利于垃圾回收器的执行
从indexOf方法来看:
判断元素是否相等用的是: equals方法
排序
两个元素进行比较:o1 o2
o1>o2 返回 > 0 的值
01=02 返回 0
01<02 返回 < 0 的值
Collections工具类
Arrays工具类
里面的方法很多,重点掌握排序:
List<Integer> nums = new ArrayList<>();
nums.add(22);
nums.add(1);
nums.add(55);
nums.add(6);
nums.add(7);
nums.add(6);
// 利用Collections里面sort进行排序
Collections.sort(nums);
System.out.println(nums);
List<String> names = new ArrayList<>();
names.add("jack");
names.add("lucy");
names.add("jack2");
Collections.sort(names);
System.out.println(names);
对象的排序
固定规则-Comparable接口
将排序规则写死, 实现Comparable接口, 并且重写compareTo方法
针对案例中Members可以按照类似的写法去进行排序:
package com.gxa.day17.entity;
public class Member implements Comparable<Member>{
private String memberName;
private String memberPwd;
private Integer memberAge;
public Member() {
}
public Member(String memberName, String memberPwd, Integer memberAge) {
this.memberName = memberName;
this.memberPwd = memberPwd;
this.memberAge = memberAge;
}
public String getMemberName() {
return memberName;
}
public void setMemberName(String memberName) {
this.memberName = memberName;
}
public String getMemberPwd() {
return memberPwd;
}
public void setMemberPwd(String memberPwd) {
this.memberPwd = memberPwd;
}
public Integer getMemberAge() {
return memberAge;
}
public void setMemberAge(Integer memberAge) {
this.memberAge = memberAge;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Member member = (Member) o;
return this.memberName.equals(member.memberName) && this.memberAge.equals(member.memberAge);
}
@Override
public String toString() {
return "Member{" +
"memberName='" + memberName + '\'' +
", memberPwd='" + memberPwd + '\'' +
", memberAge=" + memberAge +
'}';
}
@Override
public int compareTo(Member o) {
// 按照年龄升序
// return this.memberAge-o.memberAge;
// 按照年龄降序
// return o.memberAge-this.memberAge;
// 按照名字的升序进行排序
return this.memberName.compareTo(o.getMemberName());
}
}
临时规则-Comparator接口
临时规则更灵活, 不需要去修改实体类,随时可以定制比较的规则。
List<Member> members = new ArrayList<>();
members.add(new Member("jack3", "123123", 20));
members.add(new Member("jack1", "123123", 18));
members.add(new Member("jack4", "123123", 21));
members.add(new Member("jack2", "123123", 19));
Collections.sort(members, new Comparator<Member>() {
@Override
public int compare(Member o1, Member o2) {
return o2.getMemberAge()-o1.getMemberAge();
}
});
以后的排序:
redis的排序
排序的场景:
音乐排行榜
阅读量的排行榜
消息列表先后顺序排序
。。。。。
如何判断ArraysList中元素是否相等?
必须要去重写equals方法。
Vector
这个类是Java官方都抛弃了,不再使用。
这个类的使用何ArrayList基本一致。
只是效率更低, 线程安全的 =》 效率低, 基本不使用了
LinkedList
就是所谓的“链表”
查询效率偏底, 正常开发不会选择这个类, 优势在于插入数据和删除数据
ArrayList优势在于查询效率高
正常开发的选型: ArrayList > LinkedList > 数组
用这个类最主要的场景是: 实现队列
先进先出
连接池:
因为Java去**new**实例的时候,比较耗费资源, 所以发明了一个缓冲池
将需要的对象,提前实例化出来, 放入池子中
需要用这个对象的时候, 将这个对象从池子中取出来, 不用的时候再放回去
需要有一个数据结构: 取数据和存储数据, 利用LinkedList来进行存取数据
只需要掌握: LinkedList中, 如何取出第一个数据, 如何将数据添加到list的左边。
左边进去的方法: add()/addLast()
右边出来的方法: pop()
HashMap***
主要是用于管理键值对:
key=>value
名字 =》 真实的人
身份证号 =》 真实的人
在HashMap中: key是唯一的, 不能重复, 值是可以重复的
构造器
// 无参构建
HashMap<String, String> map1 = new HashMap<>();
// 指定初始容量的构建 => 这种方式最常用
HashMap<String, String> map2 = new HashMap<>(16);
// 指定容量 和 加载因子
HashMap<String, String> map3 = new HashMap<>(16, 0.75f);
常用方法
增加
// 增加数据
map1.put("name", "jack");
map1.put("age", "18");
map1.put("gender", "boy");
map1.put("gender", "girl");
System.out.println(map1);
// 直接增加一个map
map2.putAll(map1);
System.out.println(map2);
删除
// 删除数据
map2.remove("age");
System.out.println(map2);
修改
// 只要有对应的key就会去替换
map2.replace("name", "rose");
System.out.println(map2);
// 需要map中存在 key => oldValue这个映射的时候, 才会去替换
map2.replace("name", "jack", "tom");
System.out.println(map2);
查询
// 获取数据
String name = map2.get("name");
String gender = map2.get("gender");
System.out.println(name);
System.out.println(gender);
// 获取数据 如果没有返回默认值
String name2 = map2.getOrDefault("name", "tom");
String age1 = map2.get("age");
System.out.println(age1);
String age2 = map2.getOrDefault("age", "20");
System.out.println(name2);
System.out.println(age2);
// 获取大小
int size = map2.size();
System.out.println(size);
// 获取所有的key
Set<String> keys = map2.keySet();
System.out.println(keys);
// 获取所有的值
Collection<String> values = map2.values();
System.out.println(values);
// 是否包含对应的key
System.out.println(map2.containsKey("name"));
// 是否包含对应的value
System.out.println(map2.containsValue("tom"));
遍历
keySet方式
// 获取所有的key
Set<String> keys = map2.keySet();
System.out.println(keys);
for (String key : keys) {
System.out.println("key:"+key+", value:"+ map2.get(key));
}
Map.entry方式
// 获取 键值对的 entry对象的集合
Set<Map.Entry<String, String>> entries = map2.entrySet();
// 遍历
for (Map.Entry<String, String> entry : entries) {
System.out.print("key:"+entry.getKey());
System.out.println(" value:"+entry.getValue());
}
底层
初始容量: 16
有参构造器:
HashMap存储的基本结构图:
HashTable
HashTable日常开发基本不用, 效率低, 线程安全的。
HashMap是线程非安全的。
确实是并发场景: 建议使用 ConcurrentHashMap
和HashMap的区别:
- HashMap是线程非安全, HashTable线程安全
- HashMap的key可以是null, HashTable的key不能为null
HashMap<String, String> map1 = new HashMap<>(16);
// 不会报空指针
map1.put(null, null);
Hashtable<String, String> map2 = new Hashtable<>(16);
// 会报空指针
map2.put(null, null);
LinkedHashMap
这个基本没用了, 效率也比较低, 也会去维护前后元素的关系。
TreeMap
主要可以用来排序:
TreeMap<Integer, Integer> treeMap = new TreeMap<>();
treeMap.put(20, 11);
treeMap.put(1, 11);
treeMap.put(3, 11);
treeMap.put(10, 11);
System.out.println(treeMap);
TreeMap<String, Integer> treeMap2 = new TreeMap<>();
treeMap2.put("20", 11);
treeMap2.put("1", 11);
treeMap2.put("3", 11);
treeMap2.put("10", 11);
System.out.println(treeMap2);
HashSet***
用来存放无序唯一的数据。
无序说明没有下标
构造器
// 无参构造器
Set<String> set = new HashSet<>();
// 先准备一个List
List<String> names = new ArrayList<>();
names.add("jack");
names.add("rose");
names.add("jack");
System.out.println(names);
// 利用有参构造 -> 去重
Set<String> names2 = new HashSet<>(names);
System.out.println(names2);
常用方法
增加
// 添加数据
// 相同的数据是不会添加进去的
set.add("1");
set.add("1");
set.add("1");
System.out.println(set);
删除
// 删除数据
set.remove("3");
System.out.println(set);
查询
// 获取元素的个数
System.out.println(set.size());
// 判断元素是否存在
System.out.println(set.contains("2"));
// 迭代器
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
// foreach
for (String s : set) {
System.out.println(s);
}
set判断元素是否存在?
需要同时重写两个方法: equals 和 hashCode
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Member member = (Member) o;
return this.memberName.equals(member.memberName) && this.memberAge.equals(member.memberAge);
}
@Override
public int hashCode() {
return Objects.hash(memberName, memberAge);
}
底层
HashSet实际上就是HashMap
HashSet存放的value, 是HashMap中的Key
TreeSet
基本用法和HashSet是一样的。
可以用来排序。
TreeSet<Integer> nums = new TreeSet<>();
nums.add(30);
nums.add(1);
nums.add(3);
nums.add(5);
System.out.println(nums);
``
set判断元素是否存在?
需要同时重写两个方法: equals 和 hashCode
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Member member = (Member) o;
return this.memberName.equals(member.memberName) && this.memberAge.equals(member.memberAge);
}
@Override
public int hashCode() {
return Objects.hash(memberName, memberAge);
}