集合学习总结
集合是一个容器,存放多个元素(元素的数据类型是引用类型(object)),容量没有限制
Collection集合
Collection接口:单列集合,存储一个一个的对象
List接口
List接口:可重复,有顺序 ----动态数组 替换原有数组
-
ArrayList:最常用的实现类 底层: Object[] elementData 线程不安全,但是效率高
-
linkedList:针对数据的插入和删除 底层:双向链表存储 数据的插入和删除效率高
-
Vector:古老的实现类 底层: Object[] elementData 线程安全,但是效率低
-
相同点:都是List接口的实现类,存储数据特点相同
相关方法
package com.lcj.集合;
import jdk.swing.interop.SwingInterOpUtils;
import java.lang.reflect.Array;
import java.util.*;
public class list {
public static void main(String[] args) {
/*
集合的创建,基本方法,增强for循环:内部使用了迭代器
*/
/*List lt = new ArrayList();
student s = new student("邓憨憨",41);
student s1 = new student("邓憨憨1",40);
student s2 = new student("邓憨憨2",42);
student s3 = new student("邓憨憨3",43);
lt.add(s);//添加元素
lt.add(s1);
lt.add(s2);
lt.add(s3);
lt.add(10);//10是Object类型
Integer i1 = (Integer)lt.get(4);
if(i1 == 10){
lt.add(5);
}
List lt1 = new ArrayList<>();
lt1.add(8);
lt1.add("lcj");
lt.addAll(lt1);
lt.remove(5);//移除obj元素
//lt.retainAll(lt1);//交集
//lt.removeAll(lt1);//移除集合lt1中的的所有元素---去除交集
//contains(object o) 判断集合中是否包含o这个对象 底层:equals();
boolean b = lt.containsAll(lt1);//判断集合是否包含了 传入集合的所有元素
boolean contains = lt.contains(10);
boolean contains1 = lt.contains(s1);
System.out.println(b);
System.out.println(contains);
System.out.println(contains1);
System.out.println(lt.isEmpty());
//lt.clear();//清空集合
for(int i = 0;i < lt.size();i++){//获取长度
System.out.println(lt.get(i));//获取元素
}
for(Object obj:lt){
System.out.println(obj);
}*/
/*
迭代器:
执行原理:指针下移
*/
/*List lt = new ArrayList();
lt.add("a");
lt.add("b");
lt.add("c");
Iterator ie = lt.iterator();//普通迭代器只能用来遍历
while (ie.hasNext()){//判断是否有元素
System.out.println(ie.next());
}
ListIterator ir =lt.listIterator();//列表迭代器可以遍历,也可以修改集合中的元素
while (ir.hasNext()){//进行迭代,3个元素
String s = (String)ir.next();
if("b".equals(s)){
ir.add("java");
}
System.out.println(s);
}*/
//迭代完我增加了一个元素
/*
泛型
*/
/*List<String> l = new ArrayList<String>();
l.add("aaa");
l.add("bbbb");
l.add("sss");
for (String s : l) {
System.out.println(s);
}*/
/*
Collection类对集合进行操作
*/
List<String> l = new ArrayList<String>();
l.add("aaa");
l.add("bbbb");
l.add("sss");
for (String s : l) {
System.out.println(s);
}
String s1 = Collections.max(l);//最大值
System.out.println(s1);
//Collections.sort(l);//排序:升序
//Collections.reverse(l);//反转
Collections.shuffle(l);//随机排序
for (String s : l) {
System.out.println(s);
}
}
public static void list1(){
LinkedList ll = new LinkedList<>();
}
/**
* 传入一个类型的数组,对数组进行处理:复制,返回一个相同类型的集合
*/
public <E> List<E> copyArray(E[] arr){
ArrayList<E> es = new ArrayList<>();
for (E e : arr) {
es.add(e);
}
return es;
}
}
Set接口
Set接口:数据无序:存放数据不是随机的,也不是在底层数组中根据数组的索引进行添加,而是按照数据的Hashcode值进行排序
数据不可重复:根据equals进行判断,不能返回TRUE,保证相同元素只能添加一个
HashSet底层实现
HashSet:无参构造 public HashSet() {
map = new HashMap<>();
}
LinkedHashSet
LinkedHashSet:按照添加的顺序的遍历,使用了双向链表来记录添加顺序 使用场景:频繁遍历
TreeSet
TreeSet:按照对象的指定属性进行排序 添加的元素:相同类的对象
排序方式:比较器
自然排序中比较两个对象是否相同:compareTo()
定制排序
Map集合
Map接口:双列存储,存储key-value对(Entry对象)的数据
HashMap
HashMap:主要的实现类,线程不安全 效率高,不能存储null的KEY和value LinkedHashMap:按照添加的顺序的遍历
原因:在原有HashMap的底层基础上,添加了一对指针,指向后一个元素和前一个元素 使用场景:频繁遍历
TreeMap
TreeMap:按照KEY进行排序
底层实现原理
向map集合添加key-value对对象p:
首次调用put方法才在底层去创建长度为16的数组,获取p的key的Hash值,根据哈希值判断他在数组中的位置
如果该位置上没有其他元素,则将该对象放在数组的这个位置
如果改位置上有元素(通过链表进行存储,红黑树),则比较p的Key的哈希值与各个元素的哈希值
如果不同则说明不是相同元素,添加p
如果相同则调用p的key的equals方法与各个元素的key进行比较,
true:说明是相同元素,不进行添加
false:不同元素,添加
注意
jdk8:1.new HasMap():底层没有创建长度为16的数组
2.底层数组为Node[]
3.首次调用put方法才在底层去创建长度为16的数组
4.红黑树:折半查找
使用的前提条件:底层数组长度>64 数组中某一索引位置上使用链表存储的数据>8
源码关键量
源码关键量:
DEFAULT_INITIAL_CAPACITY 16 HashMap的默认容量
DEFAULT_LOAD_FACTOR 0.75 加载因子 得出数组的临界值,达到临界值进行扩容(既不浪费空间,控制链表结构较少)
TREEIFY_THRESHOLD:链表长度大于8转换成红黑树
MIN_TREEIFY_CAPACITY:桶中得NODE被树化时最小的hash表容量:64
threshold:扩容得临界值 DEFAULT_INITIAL_CAPACITY*DEFAULT_LOAD_FACTOR 12
常用方法
package com.lcj.集合;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class map {
public static void main(String[] args) {
Map<Integer,student> m = new HashMap<>();
student s4 = new student("邓憨憨",41);
student s1 = new student("邓憨憨1",40);
student s2 = new student("邓憨憨2",42);
student s3 = new student("邓憨憨3",43);
student s5 = new student("邓憨憨3",43);
m.put(1,s1);
m.put(2,s2);
m.put(3,s3);
m.put(4,s4);
m.put(5,s5);
m.remove(5);//移除
//m.clear();//清楚集合
Set<Integer> keys = m.keySet();
boolean b = m.containsKey(4);
boolean b1 = m.containsValue(s2);
System.out.println(b1);
System.out.println(b);
Collection<student> values = m.values();
for (student value : values) {
System.out.println(value);
}
Set<Map.Entry<Integer, student>> entries = m.entrySet();
for (Map.Entry<Integer, student> entry : entries) {
System.out.println(entry);
}
for (Integer key : keys) {
student s = m.get(key);//根据键获取值
System.out.println("键:"+key+" "+"值:"+s);
}
}
}
泛型
泛型的理解机注意事项
- 集合中使用:集合接口和类都是带泛型的结构
- 实例化集合类,可以指明具体的泛型类型
- 指明完后,集合类和接口中的泛型变为指明的数据类型
add(E e) add(String e) - 泛型的类型必须是类,不能是基本数据类型,如若是基本数据类型则使用他们的包装类
没有指明泛型类型,默认是Objectl类型
泛型类
public class DAO<T> {
private Map<String,T> map = new HashMap<>();
泛型方法
使用泛型不等与泛型方法
public <E> List<E> copyArray(E[] arr){
ArrayList<E> es = new ArrayList<>();
for (E e : arr) {
es.add(e);
}
return es;
}
泛型实例
访问数据库(表=对象 申明一个类)
- 创建一个泛型类DAO,创建一个MAP集合,key为String value为T对象,创建相关方法
package com.lcj.集合.text;
import java.util.*;
public class DAO<T> {
private Map<String,T> map = new HashMap<>();
//保存T类型的对象到Map集合中
public void save(String id,T entity){
map.put(id,entity);
System.out.println("id:"+id+"\t\t保存成功");
}
//从map集合中获取id对应的对象
public T get(String id){
T t = map.get(id);
return t;
}
//替换map集合中key为id的内容,改为entity对象
public void update(String id,T entity){
if(map.containsKey(id)){
map.put(id,entity);
}
}
//返回map集合中存放的所有T对象
public List<T> list(){
ArrayList<T> ts = new ArrayList<>();
Collection<T> values = map.values();
for (T value : values) {
ts.add(value);
}
return ts;
}
//删除指定对象
public void delete(String id){
map.remove(id);
}
}
- 创建一个User类
package com.lcj.集合.text;
public class User {
private int id;
private int age;
private String name;
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
- 创建测试类
package com.lcj.集合.text;
import java.util.List;
public class DaoText {
public static void main(String[] args) {
DAO<User> userDAO = new DAO<>();
userDAO.save("1001",new User(1001,23,"朱俊良"));
userDAO.save("1002",new User(1002,24,"张俊"));
userDAO.save("1003",new User(1003,25,"刘成军"));
userDAO.save("1004",new User(1004,26,"吕豪"));
userDAO.save("1005",new User(1005,27,"胡明雄"));
userDAO.save("1006",new User(1006,28,"王飞翔"));
User user = userDAO.get("1003");
System.out.println(user);
userDAO.update("1004",new User(1004,18,"邓婷婷"));
userDAO.delete("1006");
List<User> list = userDAO.list();
for (User user1 : list) {
System.out.println(user1);
}
}
}
遍历集合的两种方式
增强for循环:简化遍历 快捷键:集合.for
迭代器:过程的重复,应用于对集合的遍历
可认为指针的移动
List lt = new ArrayList();
lt.add("a");
lt.add("b");
lt.add("c");
Iterator ie = lt.iterator();//普通迭代器只能用来遍历
while (ie.hasNext()){//判断是否有元素
System.out.println(ie.next());
}
补充:listIterator()迭代器