14.1 集合框架
什么是集合框架?
Java中的集合框架其实就是对**【数据结构】**的封装,这个封装中提供了一些常用方法,可方便操作数据,无需程序猿自定定义操作,只需要调用封装方法就可以完成对存在集合中数据【增删改查】
集合其实就是对数据结构一种封装,所以之前sun公司就把集合放置到一个统一包中进行管理【java.util】包
什么是数据结构?
数据结构其实就是计算机,组织和存储数据形式
数据结构是指相互之间存在一种或多种特定关系的数据集合
通常情况下,精心选择数据结构可以带来更加高效运行和存储效率, 数据结构往往高效的原因在于**【检索算法】和【索引计数】**
常见数据结构:【数组、栈、链表(单向和双向)、哈希表、队列(单向和双向)、堆、树、图】
Java的集合框架其实就是对【数据结构实现】,我们需要掌握就是如何操作这个数据结构(即操作集合中方法),高效存储与处理数据
PS:根据不同数据结构,操作数据性能是不同(有地查询块、有的插入快、有地允许重复、有的不允许重复等等),在开发中只要选择合理数据结构即集合对数据存储与操作即可
Java中常见的集合框架
习惯性说Java中集合有三大框架【List、Set和Map】
如果详细说明的话应该2个框架3个实现
2个框架: Collection 和 Map
3个实现 :Collection这个集合下两个主要实现 List 和 set 所以称为三大集合List、set 和Map
集合和数组最大区别在于:
集合中只能储存引用类型即对象
集合是一个变长容量,根据集合储存元素个数动态进行删减【扩容和减容】
数组是一个定长容器,创建大小数固定,无论存储多少数据长度都是唯一
常见三大集合框架:
List【列表】:集合中存储对象是按照索引位置进行存储,允许存储重复数据
Set【集】: 集合中存储对象不是按照特定方式进行存储,不允许出现重复数据
Map【映射】:集合中每一个存储元素都是以一种【键值对key- value】方式进行存储的,以一种key和value的形式存储的,key 这个对象是不允许重复【唯一性】,value是允许重复
14.1.1 概念
- 集合是一种对象容器,用于存放对象
- 数组的缺点:
- 1、数组定长,一旦定义不能改变
- 2、数组中没有方法
- 3、数组中只能存放相同的数据类型的数据
- 集合特点:
- 1、长度可以改变
- 2、集合中丰富的操作元素的方法
- 3、集合中只能存储引用数据类型的数据
- 集合的分类
- 1、单列集合 (集合中一个元素保存一个数据) Collection
- 2、双列集合 (集合中一个元素保存两个数据) Map
14.1.2 集合架构
集合架构 |
|
14.2 Collection接口
单列集合的顶层接口
14.2.1 常用方法
- add方法向集合集合中添加元素
- clear方法,清空集合中所有元素
- contains方法 判断集合是否包含某个元素
- isEmpty判断集合是否为空
- remove方法 移除集合中元素,返回boolean类型。如果集合中不包含次元素,则删除失败
- size()返回集合中元素的个数
- toArray将集合转换成数组。
- addAll 向一个集合中添加另一个集合
- containsAll 判断一个集合中是否包含另一个集合
- removeAll 从一个集合中移除另一个集合
public class CollectionDemo { public static void main(String[] args) { //创建Collection对象 Collection coll = new ArrayList(); //Collection接口下常用的方法 //add 向集合中添加元素 coll.add("jack"); coll.add(10); coll.add("rose"); System.out.println(coll); //contains 判断集合中是否包含指定元素 System.out.println(coll.contains("赵四")); //isEmpty 判断集合的元素个数是否为0 System.out.println(coll.isEmpty()); //remove 移除集合中指定的元素,如果存在返回true、否则返回false coll.remove("jack1"); System.out.println(coll); //size 获取集合中元素个数 System.out.println(coll.size()); //toArray 将集合变成数组 Object[] arr = coll.toArray(); //Arrays.toString 将数组变成字符串形式 System.out.println(Arrays.toString(arr)); int[] nums = {1,2,3,4}; //将数组转成集合 List asList = Arrays.asList(nums); System.out.println(asList); Collection coll1 = new ArrayList(); coll1.add("lilei"); coll1.add("hanmeimei"); //addAll 将另一个集合中元素添加到当前集合中 coll1.addAll(coll); System.out.println(coll1); //containsAll 判断集合中是否包含另一个集合 System.out.println(coll1.containsAll(coll)); // coll1.removeAll(coll); // System.out.println(coll1); //retainAll 保留coll中包含的元素 coll1.retainAll(coll); System.out.println(coll1); } }
14.3 迭代器
14.3.1 迭代器原理
迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。
迭代器原理 |
|
//迭代器的作用:获取集合中的所有的元素 Collection coll = new ArrayList(); coll.add("jack"); coll.add("rose"); coll.add(10); coll.add(20.2); //1、获取迭代器对象 Iterator it = coll.iterator(); while(it.hasNext()) { System.out.println(it.next()); } System.out.println(coll);
14.3.2 迭代器使用常见问题
- 1、迭代器迭代完成之后,迭代器的位置在最后一位。 所以迭代器只能迭代一次
- 2、迭代器在迭代的时候,不要调用多次next方法,可能会出错 NoSuchElementException
- 3、在迭代器迭代的时候,不能向集合中添加或者删除元素 ConcurrentModificationException
public class IteratorDemo { public static void main(String[] args) { //使用迭代器需要注意的问题 //1、迭代器只能使用一次 // Collection coll = new ArrayList(); // coll.add("jack"); // coll.add("rose"); // coll.add(10); // coll.add(20.2); // Iterator it = coll.iterator(); // while(it.hasNext()){ // System.out.println(it.next()); // } // while(it.hasNext()){ // System.out.println(it.next()); // } //2、迭代器使用的时候不能多次使用next方法 // Collection coll = new ArrayList(); // coll.add("jack"); // coll.add("rose"); // coll.add(10); // coll.add(20.2); // coll.add(100); // Iterator it = coll.iterator(); // while(it.hasNext()) { // Object obj = it.next(); // System.out.println(it.next()); // } //3、迭代器在迭代的时候不要添加或者删除元素 Collection coll = new ArrayList(); coll.add("jack"); coll.add("rose"); coll.add(10); coll.add(20.2); coll.add(100); Iterator it = coll.iterator(); while(it.hasNext()) { coll.remove(10); //coll.add("zhaosi"); System.out.println(it.next()); } } }
14.4 泛型基本使用
泛型:参数化类型 JDK1.5之后
- 用途:
- 因为如果不使用泛型,那么向集合中添加元素,实际当做Object对象传递进去的,此时发生向上转型了当从集合中获取数据,得到的是Object类型,那么在使用的需要向下转型,,才能正常使用。因此频繁向上向下转型。可能会出现类转换异常。 这个时候就需要使用泛型。
- 泛型的作用实际上就是讲类型转换的检查提前到了编译期
- 泛型擦除: JDK1.7之后
- 集合类型<泛型> 变量名 = new 集合类型<>();
- 泛型需要注意的问题:
- 1、泛型上不存在多态
- Collection coll = new ArrayList();//错误
- 2、泛型只能是引用数据类型
- 如果是基本数据类型,则使用它的包装类
public class GenericDemo { public static void main(String[] args) { // Collection coll = new ArrayList(); // coll.add(new Student("我要去输液了",38)); // coll.add(new Student("要输什么液",20)); // coll.add(new Teacher("想你的夜",30)); // coll.add("哈哈哈~~平衡了"); // //获取迭代器对象 // Iterator it = coll.iterator(); // while(it.hasNext()) { // Student stu = (Student) it.next(); // stu.play(); // } // Collection<Student> coll = new ArrayList<>(); // coll.add(new Student("我要去输液了",38)); // //coll.add(""); 不能添加其他类型的元素 // coll.add(new Student("我要去输液了",38)); // //获取迭代器对象 // Iterator<Student> it = coll.iterator(); // while(it.hasNext()) { // Student stu = it.next(); // stu.play(); // } // Collection<Person> coll = new ArrayList<Person>(); // coll.add(new Student("我要去输液了",38)); // Collection<Integer> coll = new ArrayList<Integer>(); } } class Person{ } class Teacher extends Person{ String name; int age; public Teacher() { } public Teacher(String name, int age) { super(); this.name = name; this.age = age; } } class Student extends Person{ String name; int age; public Student() { } public Student(String name, int age) { super(); this.name = name; this.age = age; } public void play() { System.out.println("就是玩儿"); } }
14.5 ArrayList类
14.5.1 常用方法
- add(innt index, E element)
- remove(int index)
- set(int index, E element)
- get(int index)
- subList(int beginIndex,int endIndex)
- list.listIterator();
package com.qf.demo02; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; public class ArrayListDemo { public static void main(String[] args) { List<String> list = new ArrayList<String>(); //List集合相对于Collection集合多了一些关于下标操作的方法 //List集合的常用方法 list.add("jack"); list.add("rose"); list.add("cxk"); list.add("尼古拉斯"); System.out.println(list); System.out.println("======================================"); //在集合指定下标位置上添加元素 add(index, element) list.add(0, "李雷"); list.add(3, "韩梅梅"); list.add(6, "亚洲舞王"); //list.add(10, "赵四"); 下标范围:0~size System.out.println(list); System.out.println("======================================"); //清空集合中所有的元素 clear() //list.clear(); //System.out.println(list); System.out.println("======================================"); //返回元素在集合中的下标,如果不存在返回-1 System.out.println(list.indexOf("cxk")); //返回元素在集合中的下标(找到集合中最后一个相同元素),如果不存在返回-1 System.out.println(list.lastIndexOf("cxk")); System.out.println("======================================"); //移除集合中指定下标位置上的元素 下标范围:0 ~ size-1 list.remove(0); System.out.println(list); System.out.println("======================================"); //修改集合中指定下标位置上的元素 下标范围:0 ~ size-1 list.set(1, "李雷"); System.out.println(list); System.out.println("======================================"); //截取集合中指定下标开始到结束位置上的元素 List<String> list1 = list.subList(2, 5); System.out.println("list1----》"+list1); System.out.println("======================================"); //获取指定下标位置上的元素 System.out.println(list.get(0)); /** * List集合遍历的三种方式: * 1、迭代器 * 2、for循环 * 3、foreach循环(增强for循环) 可以遍历数组和集合 * * 语法: * for(元素的类型 变量 : 数组|集合){ //变量就表示遍历出来的元素 * * } */ System.out.println("===================迭代器遍历==================="); Iterator<String> it = list.iterator(); while(it.hasNext()) { System.out.println(it.next()); } System.out.println("===================for循环遍历==================="); for (int i = 0; i < list.size() ; i++) { System.out.println(list.get(i)); } System.out.println("===================foreach循环遍历==================="); for(String s : list) { System.out.println(s); } System.out.println("=================list集合的迭代器====================="); ListIterator<String> li = list.listIterator(); // while(li.hasNext()) { // System.out.println(li.next()); // } // // while(li.hasPrevious()) { // System.out.println(li.previous()); // } while(li.hasNext()) { li.add("hehe"); System.out.println(li.next()); } System.out.println("--------------"); while(li.hasPrevious()) { System.out.println(li.previous()); } } }
14.5.2 实现原理
ArrayList其底层实现使用数组
实现原理 |
|
14.6 LinkedList类
14.6.1 常用方法
常用的方法与ArrayList一致。自己独有一些向首尾添加移除等方法(可以模拟对列、堆栈等数据结构)
package com.qf.demo02; import java.util.LinkedList; public class LinkedListDemo { public static void main(String[] args) { //创建LinkedList对象 LinkedList<String> list = new LinkedList<String>(); list.add("jack"); list.add("rose"); list.add("cxk"); list.add("李雷"); list.add("韩梅梅"); list.add(1, "马冬梅"); System.out.println(list); list.addFirst("尼古拉斯"); list.addLast("亚洲舞王"); System.out.println(list); System.out.println("================================================"); System.out.println(list.getFirst()); System.out.println(list.getLast()); System.out.println(list.get(3)); System.out.println("================模拟栈结构=================="); LinkedList<String> list1 = new LinkedList<String>(); list1.push("aa"); list1.push("bb"); System.out.println(list1.pop()); System.out.println(list1.pop()); System.out.println("================模拟对列结构=================="); LinkedList<String> list2 = new LinkedList<String>(); //向对列的尾部添加元素 list2.offer("哈哈"); list2.offer("呵呵"); list2.offer("嘻嘻"); list2.offer("hiahia"); //获取并移除对列的头部的元素 System.out.println(list2.poll()); System.out.println(list2.poll()); System.out.println(list2.poll()); System.out.println(list2.poll()); //获取但不移除对列的头部的元素 //System.out.println(list2.element()); //获取但不移除对列的头部的元素 //System.out.println(list2.peek()); System.out.println(list2); //LinkedList集合三种遍历方式 } }
14.6.2 LinkedList实现原理
实现原理 |
|
14.6.3 堆栈和队列结构
堆栈和队列结构 |
|
14.7 Vector类
14.7.1 常用方法
与
ArrayList
的方法基本一致
public class VectorDemo { public static void main(String[] args) { Vector<String> vector = new Vector<String>(); vector.add("aa"); System.out.println(vector); /** * ArrayList、LinkedList、Vector的区别 * * ArrayList和Vector底层使用数组实现(增删慢、查询快) * ArrayList是当添加元素的时候,才会扩容数组,默认长度为10 * Vector是当创建对象的是,就创建长度为10的数组 * ArrayList线程不安全,效率高 * Vector是线程安全的,效率低 * * LinkedList底层使用双向链表实现(增删快、查询慢) */ } }
14.7.2 实现原理
与
ArrayList
的底层一致,使用数组实现
14.7.3 常见面试问题
ArrayList
、LinkedList
、Vector
的区别:
ArrayList和Vector底层使用数组实现(增删慢、查询快)
- ArrayList是当添加元素的时候,才会扩容数组,默认长度为10, Vector是当创建对象的是,就创建长度为10的数组
- ArrayList线程不安全,效率高 Vector是线程安全的,效率低
- LinkedList底层使用双向链表实现(增删快、查询慢)
14.8 HashSet类
14.8.1 HashSet基本使用
常用方法与Collection接口中定义的方法一致
特点:
- 无序 (插入顺序)
- 无下标
- 不可重复
HashSet<String> set = new HashSet<String>(); set.add("jack"); set.add("rose"); set.add("cxk"); set.add("jack"); System.out.println(set);
14.8.2 HashSet 去重原理
HashSet底层去重:
首先会比较两个对象的hashCode的值,如果hashCode值不一样,则直接认为两个对象是不同的对象,如果HashCode值一样,那么就会比较两个方法的equals方法, 如果equals方法返回false,则表示两个对象是不同的对象,如果equals方法返回true,则表示两个对象是相同的对象,则不会向HashSet中添加
总之:HashSet确定对象是否重复,是先判断hashcode再判断equals,两者都相等则认为是相同对象
HashSet<User> userSet = new HashSet<User>(); User cxk = new User("cxk", "123"); userSet.add(cxk); userSet.add(new User("jack", "456")); userSet.add(new User("王校长", "输液...")); userSet.add(new User("jack", "456")); // 相同对象无法插入 userSet.add(cxk);// 相同对象无法插入
重写hashCode
和equals
方法
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((password == null) ? 0 : password.hashCode()); result = prime * result + ((username == null) ? 0 : username.hashCode()); return result; } @Override public boolean equals(Object obj) { //判断两个对象是否是同一个对象 if (this == obj) return true; //判断比较的对象是否为null if (obj == null) return false; //getClass() 返回对象的真实(运行)类型 if (getClass() != obj.getClass()) return false; User other = (User) obj; if (password == null) { if (other.password != null) return false; } else if (!password.equals(other.password)) return false; if (username == null) { if (other.username != null) return false; } else if (!username.equals(other.username)) return false; return true; }
14.9 LinkedHashSet类
LinkedHashSet
特点::
- 1、有序
- 2、无下标
- 3、不可重复
与父类的方法一致,去重的原理,也与父类一致
public class LinkedHashSetDemo { public static void main(String[] args) { //LinkedHashSet 有序(链表维护顺序) 不能重复 LinkedHashSet<String> set = new LinkedHashSet<>(); set.add("jack"); set.add("大娃"); set.add("二娃"); set.add("rose"); set.add("爷爷"); set.add("爷爷"); for (String s : set) { System.out.println(s); } //1、底层实现 (LinkedHashMap) //2、去重原理 (与hashSet一致) } }
14.10 Collections工具类
集合: 工具类(Collections)
Collections.reverse(List list)
将集合中的元素反转
Collections.shuffle(List list)
将集合中的元素随机打乱
- Collections.sort(List list)
- 将集合中的元素排序 (必须要实现Comparable接口)
public class CollectionsDemo { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("jack"); list.add("大娃"); list.add("二娃"); list.add("rose"); list.add("妖怪"); list.add("蛇妖"); list.add("蛇妖"); System.out.println(list); //按照字典顺序 Collections.sort(list); System.out.println(list); //将集合元素进行翻转 Collections.reverse(list); System.out.println(list); //将集合中的元素进行随机打乱 Collections.shuffle(list); System.out.println(list); //Arrays数组工具类 Collections集合工具类 } }