集合
体系结构
-
Collection
-
Collection单列集合,每个元素(数据)只包含一个值
-
-
Map
-
Map双列集合,每个元素包含两个值(键值对)。
-
Collection集合体系
-
Collection也是接口
List(接口)
-
ArrayList(实现类)
-
linkedList(实现类)
-
List系列集合:添加的元素是有序、可重复、有索引。
-
ArrayList、LinekdList :有序、可重复、有索引
-
Set(接口)
-
HashSet------>LinkedHashSet(实现类)
-
TreeSet(实现类)
-
Set系列集合:添加的元素是无序、不重复、无索引
-
HashSet: 无序、不重复、无索引;
-
LinkedHashSet: 有序、不重复、无索引。
-
TreeSet:按照大小升序、不重复、无索引。
-
Collection体系常用API
方法名称 | 示例 | 说明 |
---|---|---|
Collection<String> list=new ArrayList<>(); | 创建 | |
public boolean add(E e) | list.add("java"); | 添加 |
public void clear() | list.clear(); | 清空 |
public boolean remove(E e) | boolean b3=list.remove("java"); | 删除 |
public boolean contains(Object obj | boolean b2=list.contains("wzy"); | 包含 |
public boolean isEmpty() | boolean b1=list.isEmpty(); | 判空 |
public int size() | list.size() | 元素个数 |
public Object[] toArray() | Object[] arrs=list.toArray(); | 转为数组 |
public | list.addAll(list2); | 合并 |
Collection体系使用场景
-
如果希望元素可以重复,又有索引,索引查询要快?
-
用ArrayList集合,基于数组的(用的最多)
-
-
如果希望元素可以重复,又有索引,增删首尾操作快?
-
用LinkedList集合,基于链表的。
-
-
如果希望增删改查都快,但是元素不重复、无序、无索引
-
用HashSet集合,基于哈希表的。
-
-
如果希望增删改查都快,但是元素不重复、有序、无索引。
-
用LinkedHashSet集合,基于哈希表和双链表。
-
-
. 如果要对对象进行排序
-
用TreeSet集合,基于红黑树。后 续也可以用List集合实现排序
-
集合的遍历
-
迭代器
-
集合专用
-
获取一个迭代器
Iterator<String> it= list.iterator();//该迭代器对象默认指向当前集合的0索引
-
常用方法
-
it.hasNext()//判断当前元素是否存在
-
it.next()//获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止取出越界。
-
-
-
foreach/增强for
-
集合//数组都能用
-
示例
-
for(String i:list){ System.out.println(i);//修改第三方变量i的值不会影响集合中的元素 }
-
-
-
Lambda表达式
-
更加简化代码长度
-
示例
-
list.forEach(s -> System.out.println(s));
-
list.forEach(System.out::println);//这也是遍历
-
-
List集合体系
List(接口)
-
ArrayList(实现类)
-
linkedList(实现类)
-
List系列集合:添加的元素是有序、可重复、有索引。
-
ArrayList、LinekdList :有序、可重复、有索引
-
List体系特有方法
-
方法名称 说明 void add(int index,E element) 在此集合中的指定位置插入指定的元素 E remove(int index) 删除指定索引处的元素,返回被删除的元素 E set(int index,E element) 修改指定索引处的元素,返回被修改的元素 E get(int index) 返回指定索引处的元素
ArrayList
-
ArrayList底层是基于数组实现的,查询元素快,增删相对慢。
-
因为:根据索引定位元素快,增删需要做元素的移位操作
-
Arraylist常用API,与上文Collection基本一致
API关键字 | 作用 |
---|---|
list.add("java") | 增加元素 |
list.add(1,"这是插入的内容") | 在指定位置加入元素 |
String s = list.get(1) | 获取集合中元素 |
list.size() | 获取集合中元素个数 |
String s2 = list.remove(2) | 根据索引删除某元素,把被删除的元素返回给s2 |
list.remove("C++") | 直接删除指定元素 |
list.set(0,"wzy"); | 根据索引修改某个位置的元素 |
ArrayList<Movie> movies=new ArrayList<>() | 存自定义类型:Movie |
movies.add(new Movie("第二部电影",9.6,"李四")) | 直接创建一个对象并把他加入到集合中 |
LinkedList
-
LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素非常快,所以多了很多首尾操作的特有API
-
LinkedList特有API:使用他们可以模拟出队列和栈
-
-
做一个队列:先进先出
-
//1做一个队列 LinkedList<String> queue=new LinkedList<>(); //2入队:排队就是后进来的排到后面 queue.addLast("1号"); queue.addLast("2号"); queue.addLast("3号"); System.out.println(queue); //3出队 queue.removeFirst();//先出 System.out.println(queue);
-
做一个栈:先进后出
LinkedList<String> stack=new LinkedList<>(); stack.addFirst("第一颗子弹");//子弹每次都装在弹夹的最上面 stack.addFirst("第二颗子弹"); stack.addFirst("第三颗子弹"); stack.push("第四颗子弹");//和addFrist一样,压栈 stack.removeLast();//先进后出 stack.pop();//和removeLast效果一样,弹栈 System.out.println(stack);
-
说明
-
把左边当作是first右边是last
-
或者把上边当作first下面当作last
-
集合的并发修改异常问题
-
并发:边遍历边修改元素
-
使用迭代器遍历可以解决并发修改异常问题
-
Iterator<String > it=list.iterator(); while(it.hasNext()){ String ele=it.next(); if ("java".equals(ele)){ //list.remove(ele);//用集合删除会出问题 it.remove();//用迭代器删除没问题 } }
-
-
foreach和Landa表达式 遍历都无法解决
-
普通for循环倒着遍历也可以解决该问题
Set集合体系
Set集合的功能上基本上与Collection的API一致
-
Set系列集合:添加的元素是无序、不重复、无索引
-
HashSet: 无序、不重复、无索引;
-
LinkedHashSet: 有序、不重复、无索引。
-
TreeSet:按照大小升序、不重复、无索引。
-
HashSet
-
底层原理:哈希表
-
哈希表是一种对于增删改查数据性能都较好的结构
-
哈希表组成:
-
lJDK8之前的,底层使用数组+链表组成
-
lJDK8开始后,底层采用数组+链表+红黑树组成。
-
-
哈希值
-
是JDK根据对象的地址,按照某种规则算出来的int类型的数值
-
name.hashCode()
-
同一个对象多次调用hashCode()方法返回的哈希值是相同的,不同对象哈希值不同
-
-
LinkedHashSet
-
有序,不重复,无索引
-
底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序
TreeSet
-
l不重复、无索引、可排序
-
排序规则
-
对于数值类型:Integer , Double,官方默认按照大小进行升序排序。
-
对于字符串类型:默认按照首字符的编号(ASCLL)升序排序。
-
对于自定义类型如Student对象,TreeSet无法直接排序
-
-
自定义排序
-
法一:让自定义的类(如学生类)实现Comparable接口重写里面的compareTo方法来定制比较规则
-
public class Student implements Comparable<Student>{ public int compareTo(Student o) { return this.age-o.age;//当年龄相等时会被默认去重 //return this.age-o.age>=0?1:-1;//不会被去重 } }
-
-
法二:TreeSet集合有参数构造器,可以设置Comparator接口对应的比较器对象,来定制比较规则
-
Set<Student> sets3=new TreeSet<>((o1, o2)-> o2.getAge()>o1.getAge()?1:-1);
-
-
泛型深入
-
泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
-
好处
-
l统一数据类型。
-
把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常
-
-
使用领域
-
类后面------------>泛型类
方法申明上----->泛型方法
接口后面--------->泛型接口
-
泛型类
-
l定义类时同时定义了泛型的类就是泛型类。
-
l泛型类的格式:修饰符 class 类名<泛型变量>{ }
-
public class MyArrayList<T> { }
-
-
作用:编译阶段可以指定数据类型,类似于集合的作用。
-
核心思想:把出现泛型变量的地方全部替换成传输的真实数据类型
泛型方法
-
作用:方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性。
泛型接口
-
泛型接口可以让实现类选择当前功能需要操作的数据类型
-
实现接口的类肯定会不相同 添加元素的时候就不能写死 这时就应该使用泛型接口
-
作用:泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据类型这样重写的方法都将是针对于该类型的操作。
-
定义
-
public interface Data <E>{ void add(E e); }
-
-
实现
-
class Teacher implements Data<Teacher> //泛型接口实现时要声明类型,E要传Teacher //此时接口中的E就是Teacher了
-
通配符:?
-
? 可以在“使用泛型”的时候代表一切类型。
-
E T K V 是在定义泛型的时候使用的
-
通配符的上下限
-
泛型上限:? extends Car: ?必须是Car或者其子类
-
泛型下限:? super Car : ?必须是Car或者其父类
-
可变参数
-
可变参数用在形参中可以接收多个数据。
-
可变参数的格式:数据类型...参数名称
-
作用
-
l接收参数非常灵活,方便。可以不接收参数,可以接收1个或者多个参数,也可以接收一个数组
-
本质上就是一个数组
-
-
注意事项
-
1.一个形参列表中可变参数只能有一个
2.可变参数必须放在形参列表的最后面
-
Collections工具类
Collections并不属于集合,是用来操作集合的工具类
相关API | 说明 |
---|---|
Collections.addAll(names,"wzy","yjh","gwq","zch"); | 批量添加 |
Collections.shuffle(names); | 打乱List集合元素存储顺序 |
Collections.sort(list); | 排序 |
-
排自定义类型数据也有两种方法与TreeSet排自定义类型一致
-
Collections排序的API只适用于List
Map集合体系
Map也是接口
HashMap(实现类)
-
LinkedHashMap(实现类)
-
HashMap:元素按照键是无序,不重复,无索引,值不做要求。(与Map体系一致)
-
LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求。
-
HashTable(实现类)
-
Properties(实现类)
-
后续讲解
-
其他(接口)
-
TreeMap
-
TreeMap:元素按照建是排序,不重复,无索引的,值不做要求
-
体系特点
-
Map也是接口:是一种双列集合,每个元素包含两个数据。key=value(键值对元素)
-
Map集合
-
键:无序,不重复的,无索引的,如果重复后面覆盖前面
-
值:不做要求(可以重复)
-
Map体系常用API
-
Map是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的
方法名称 | 示例 | 说明 |
---|---|---|
Map<String,Integer> maps=new HashMap<>(); | 创建 | |
V put(K key,V value) | maps2.put("张三",4); | 添加 |
V remove(Object key) | Integer hw = maps.remove("huawei"); | 由键删除键值对元素 |
void clear() | 清空 | |
boolean containsKey(Object key) | boolean iphonex = maps.containsKey("iphoneX"); | 包含键/值 |
boolean isEmpty() | boolean empty = maps.isEmpty(); | 判空 |
maps.putAll(maps2); | 合并 | |
Set<String> sets = maps.keySet(); | 拿所有的键 | |
Collection<Integer> values = maps.values(); | 拿所有的值 |
Map集合的遍历
-
键找值
-
先获取全部键的Set集合。遍历键的Set集合,然后通过键提取对应值。
-
示例
-
Set<String> keys = maps.keySet();//拿键 for (String key : keys) { Integer value=maps.get(key);//找值 System.out.println(key + "->" + value);
-
-
键值对
-
先把Map集合转换成Set集合,Set集合中每个元素都是键值对实体类型了。遍历Set集合,然后提取键以及提取值。
-
示例
-
Set<Map.Entry<String, Integer>> entries = maps.entrySet();//Map转Set for(Map.Entry<String,Integer>entry:entries){ String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + "->" + value); }
-
-
lambda表达式
-
示例
-
maps.forEach(( key, value)-> System.out.println(key+"->"+value));
HashMap
体系特点
-
HashMap:元素按照键是无序,不重复,无索引,值不做要求。(与Map体系一致)
-
HashMap跟HashSet底层原理是一模一样的,都是哈希表结构,只是HashMap的每个元素包含两个值而已。
-
Set系列集合的底层就是Map实现的,只是Set集合中的元素只要键数据,不要值数据而已
LinkdHashMap
体系特点
-
LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求。
-
底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序
TreeMap
体系特点
-
TreeMap:元素按照建是排序,不重复,无索引的,值不做要求。
-
注意:TreeMap集合是一定要排序的,可以默认排序,也可以将键按照指定的规则进行排序
排序
与TreeSet排序方法一致
-
方式一
Map<Student,String> maps=new TreeMap<>((o1, o2) -> o1.getAge()< o2.getAge()?1:-1);
不可变集合
-
集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变。否则报错
-
在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合。
-
List<Double> lists= List.of(12.2 , 23.4 , 45.6 , 6.4);//不能做任何修改,包括添加或者删除元素
Stream流
想象成一根流水线或者传送带,用于简化集合和数组操作的API
获取流
-
Collection集合体系
-
List<String> list=new ArrayList<>(); Stream<String> s = list.stream();
-
-
Map集合体系
-
Map<String,Integer> maps= new HashMap<>(); Stream<String> keyStream=maps.keySet().stream();//键流 Stream<Integer> valueStream=maps.values().stream();//值流 Stream<Map.Entry<String,Integer> > mapEntryStream=maps.entrySet().stream();//键值对流
-
-
数组
-
//a法一 Stream<String> s1 = Arrays.stream(names); //b法二 Stream<String> s2 = Stream.of(names);
-
常用API
//1链式编程 list.stream() .filter(s->s.startsWith("w")) .filter((s->s.length()==3)) .forEach(s-> System.out.println(s));//支持链式编程 //2满足条件的个数 long s6 = list.stream() .filter(s -> s.length() == 3) .count(); System.out.println(s6); //3过滤后只要前两个 list.stream() .filter(s->s.length()==3) .limit(2) .forEach(System.out::println);//方法引用 //4跳过前两个 list.stream() .filter(s->s.length()==3) .skip(2) .forEach(System.out::println);//方法引用 //5Map加工:第一个参数是原材料,第二个参数是加工后的结果 list.stream() .map(s->"加工前缀:"+s) .forEach(System.out::println); //把集合内的元素全部封装成对象 list.stream() .map(Student::new) .forEach(System.out::println);//简化后的代码格式 //6合并流 Stream<String> w = list.stream().filter(s -> s.startsWith("w"));//先获得两个流 Stream<String> y = list.stream().filter(s -> s.startsWith("y")); Stream<String> wy = Stream.concat(w, y); wy.forEach(System.out::println);
收集Stream流
-
收集到集合内
-
Stream<String> w = lists.stream().filter(s -> s.startsWith("w")); List<String> collects = w.collect(Collectors.toList()); System.out.println(collects);
-
-
收集到数组里
-
Stream<String> w1 = lists.stream().filter(s -> s.startsWith("w"));//流只能使用一次,使用完就挂了,所以创建一个新的流h Object[] arrays = w1.toArray(); String[] s = w1.toArray(String[]::new); System.out.println(Arrays.toString(arrays));
-