Collection集合
数组和集合的区别
-
相同点
都是容器,可以存储多个数据
-
不同点
-
数组的长度是不可变的,集合的长度是可变的
-
数组可以存基本数据类型和引用数据类型
集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类
-
Collection 集合概述和使用
Collection集合概述
-
是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
-
JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现
创建Collection集合的对象
-
多态的方式
-
具体的实现类ArrayList
Collection集合常用方法
方法名 | 说明 |
---|---|
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
boolean removeIf(Object o) | 根据条件进行移除 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定的元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
Collection集合的遍历
迭代器遍历
迭代器介绍
- 迭代器,集合的专用遍历方式
-
Iterator中的常用方法
boolean hasNext(): 判断当前位置是否有元素可以被取出 E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置
-
Collection集合的遍历
java
Iterator<String> it = list.iterator();
boolean flag = it.hasNext(); //判断当前位置是否有元素,有true无false
String str = it.next(); //获取当前元素并把指针移向下一位
java
public class IteratorDemo {
public static void main(String[] args) {
//创建集合对象
Collection<String> c = new ArrayList<>();
//添加元素
c.add("hello");
c.add("world");
c.add("java");
c.add("javaee");
//Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
Iterator<String> it = c.iterator();
//用while循环改进元素的判断和获取
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
}
}
增强for
介绍
-
它是JDK5之后出现的,其内部原理是一个Iterator迭代器
-
实现Iterable接口的类才可以使用迭代器和增强for
-
简化数组和Collection集合的遍历
格式
for(集合/数组中元素的数据类型 变量名 : 集合/数组名) {
// 已经将当前遍历到的元素封装到变量中了,直接使用变量即可
}
代码
java
public class EnhanceForTest {
public static void main(String[] args) {
//创建集合并添加元素
Collection<String> coll = new ArrayList<>();
coll.add("zhangsan");
coll.add("lisi");
coll.add("wangwu");
//注意点:s 其实就是一个第三方变量,在循环的过程中依次表示集合中的每一个数据
//修改增强for中的变量,不会改变集合中原来的数据
for(String s : coll){
System.out.println(s);
}
}
}
List集合
List集合的概述和特点
-
List集合的概述
-
有序集合,这里的有序指的是存取顺序
-
用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
-
与Set集合不同,列表通常允许重复的元素
-
-
List集合的特点
-
存取有序
-
可以重复
-
有索引
-
List集合的特有方法【应用】
方法介绍
方法名 | 描述 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
java
public class ListTest1 {
public static void main(String[] args) {
//创建一个集合
List<String> list = new ArrayList<>();
//添加元素
list.add("aaa");
list.add("bbb");
list.add("ccc");
//增强for遍历
list.add(1, "QQQ");
for (String s : list) {
System.out.println(s);
}
//迭代器遍历
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
String remove = list.remove(0);
System.out.println(remove);//aaa [QQQ, bbb, ccc]
String result = list.set(0, "QQQ");//QQQ [QQQ, bbb, ccc]
System.out.println(result);
String s = list.get(2);
System.out.println(s);//ccc [QQQ, bbb, ccc]
//打印集合
System.out.println(list);
}
}
2.3List集合的五种遍历方式【应用】
-
迭代器
-
列表迭代器
-
增强for
-
Lambda表达式
-
普通for循环
代码示例:
java
public class ListTest2 {
public static void main(String[] args) {
//创建集合并添加元素
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
//1.迭代器
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String str = iterator.next();
System.out.println(str);
}
//增强for
for (String s : list) {
System.out.println(s);
}
//Lambda表达式
list.forEach(s -> System.out.println(s));
//普通for循环
for (int i = 0; i < list.size(); i++) {
//i:依次表示集合中的每一个索引
String s = list.get(i);
System.out.println(s);
}
//列表迭代器
//获取一个列表迭代器的对象,里面的指针默认也是指向0索引
//额外添加了一个方法,在遍历的过程中,可以添加元素
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
String str = it.next();
if ("bbb".equals(str)) {
it.add("fff");
}
}
System.out.println(list);
}
}
Set集合
不可以存储重复元素
没有索引,不能使用普通for循环遍历
代码
java
public class SetTest {
public static void main(String[] args) {
//创建集合对象
Set<String> set = new TreeSet<>();
//添加元素
set.add("ccc");
set.add("aaa");
set.add("aaa");
set.add("bbb");
/* for(int i = 0; i < set.size(); i++){
//Set集合是没有索引的,所以不能使用通过索引获取元素的方法
}*/
//遍历集合
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
System.out.println("-----------------------------------");
for (String s : set) {
System.out.println(s);
}
}
}
HashSet
-
底层数据结构是哈希表
-
存取无序
-
不可以存储重复元素
-
没有索引,不能使用普通for循环遍历
哈希表结构
JDK8之前: 数组+链表
JDK8开始: 数组+链表+红黑树
-
节点个数少于等于8个
数组 + 链表
-
节点个数多于8个
数组 + 红黑树
哈希值
-
哈希值简介
是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
-
如何获取哈希值
Object类中的public int hashCode():返回对象的哈希码值
-
哈希值的特点
-
同一个对象多次调用hashCode()方法返回的哈希值是相同的
-
默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
-
LinkedHashSet
底层原理
TreeSet
不重复,无索引,可排序
可排序:按照元素的默认规则(从小到大)排序
TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都很好
存储Integer类型的整数并遍历
java
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<>();
ts.add(5);
ts.add(4);
ts.add(3);
ts.add(2);
ts.add(1);//[1, 2, 3, 4, 5]
//System.out.println(ts);
//迭代器
Iterator<Integer> iterator = ts.iterator();
while(iterator.hasNext()){
int i = iterator.next();
System.out.println(i);
}
System.out.println("------------");
System.out.println();
//增强for
for(int t : ts){
System.out.println(t);
}
System.out.println("----------------");
System.out.println();
ts.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer i) {
System.out.println(i);
}
});
System.out.println("----------------");
ts.forEach(i -> System.out.println(i));
}
}
自然排序Comparable
案例需求
- 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
实现步骤
-
使用空参构造创建TreeSet集合
用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
-
自定义的Student类实现Comparable接口
自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
-
重写接口中的compareTo方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
代码实现
学生类
java
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
//按照对象的年龄进行排序
//主要判断条件: 按照年龄从小到大排序
int result = this.age - o.age;
//次要判断条件: 年龄相同时,按照姓名的字母顺序排序
result = result == 0 ? this.name.compareTo(o.getName()) : result;
return result;
}
}
测试类
java
public class MyTreeSet2 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student> ts = new TreeSet<>();
//创建学生对象
Student s1 = new Student("zhangsan",28);
Student s2 = new Student("lisi",27);
Student s3 = new Student("wangwu",29);
Student s4 = new Student("zhaoliu",28);
Student s5 = new Student("qianqi",30);
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
//遍历集合
for (Student student : ts) {
System.out.println(student);
}
}
}
比较器排序Comparator
代码
学生
java
public class Student2 implements Comparable<Student2>{
private String name;
private int age;
private int chinese;
private int math;
private int english;
public Student2() {
}
public Student2(String name, int age, int chinese, int math, int english) {
this.name = name;
this.age = age;
this.chinese = chinese;
this.math = math;
this.english = english;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getEnglish() {
return english;
}
public void setEnglish(int english) {
this.english = english;
}
@Override
public String toString() {
return "Student2{" +
"name='" + name + '\'' +
", age=" + age +
", chinese=" + chinese +
", math=" + math +
", english=" + english +
'}';
}
@Override
public int compareTo(Student2 o) {
int sum1 = this.getChinese() + this.getMath() + this.getEnglish();
int sum2 = o.getChinese() + o.getMath() + o.getEnglish();
int i = sum1 - sum2;
i = i == 0 ? this.getChinese() - o.getChinese() : i;
i = i == 0 ? this.getEnglish() - o.getEnglish() : i;
i = i == 0 ? this.getMath() - o.getMath() : i;
i = i == 0 ? this.getAge() - o.getAge() : i;
i = i == 0 ? this.getName().compareTo(o.getName()) : i;
return i;
}
}
测试类
java
public class Test {
public static void main(String[] args) {
Student2 s1 = new Student2("zhangsan",23,99,55,65);
Student2 s2 = new Student2("lisi",24,65,67,46);
Student2 s3 = new Student2("wangwu",25,42,35,46);
Student2 s4 = new Student2("zhaoliu",26,86,55,86);
TreeSet<Student2> ts = new TreeSet<>();
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
int sum = 0;
for(Student2 t : ts){
sum = t.getChinese()+t.getMath()+t.getEnglish();
System.out.print(t);
System.out.print(sum);
System.out.println();
}
}
}
总结
如果想要集合中的元素可重复
用ArrayList集合,基于数组的
如果想要集合中的元素可重复,而且当前的增删操作明显多于查询
用LinkedList集合,基于链表的
如果想对集合中的元素去重
用HashSet集合,基于哈希表的
如果想对集合总的元素去重,而且保存存取顺序
用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet
如果想对集合中的元素进行排序
用TreeSet集合,基于红黑树,后续
用List集合实现排序
双列集合
特点
-
双列集合一次需要存一对数据,分别为键和值
-
键不能重复,值可以重复
-
键和值是一一对应的,每一个键只能找到自己对应的值
-
键+值这个整体,我们称之为"键值对"或者"键值对对象",在java中叫做"Entry对象"
Map集合
Map集合概述
java
interface Map<K,V> K:键的类型;V:值的类型
使用示例
java
public class MapTest {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
//V put(K key, V value) 将指定的值与该映射中的指定键相关联
map.put("1","zhangsan");
map.put("2","lisi");
map.put("2","wangwu");
map.put("3","zhaoliu");
//输出集合对象
System.out.println(map);
//{1=zhangsan, 2=wangwu, 3=zhaoliu}
}
}
Map集合的基本功能
方法介绍
方法名 | 说明 |
---|---|
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
Map集合的遍历
方式一
-
遍历思路
-
我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
-
把所有的丈夫给集中起来
-
遍历丈夫的集合,获取到每一个丈夫
-
根据丈夫去找对应的妻子
-
-
-
步骤分析
-
获取所有键的集合。用keySet()方法实现
-
遍历键的集合,获取到每一个键。用增强for实现
-
根据键去找值。用get(Object key)方法实现
-
-
代码实现
java
public class MapTest2 {
public static void main(String[] args) {
//Map集合的第一个遍历方式
//1.创建Map集合的对象
Map<String, String> map = new HashMap<>();
//添加元素
map.put("张无忌", "赵敏");
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
//3.1获取所有的键,把这些键放在一个单列集合中
Set<String> keys = map.keySet();
//3.2遍历单列集合,得到每一个键
for (String key : keys) {
//3.3利用map集合中的键获取对应的值 get
String value = map.get(key);
}
//迭代器遍历
Iterator<String> it = keys.iterator();
while (it.hasNext()) {
String key = it.next();
String value = map.get(key);
System.out.println(key + "=" + value);
}
//增强for遍历
keys.forEach(new Consumer<String>() {
@Override
public void accept(String key) {
String value = map.get(key);
System.out.println(key + " = " + value);
}
});
keys.forEach(key -> {
String value = map.get(key);
System.out.println(key + "=" + value);
});
}
}
LinkedHashMap
- 由键决定:有序,不重复,无索引
- 这里的有序指的是保证存储和取出的元素顺序一致
原理:底层数据结构依然是哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序
TreeMap集合
-
TreeMap底层是红黑树结构
-
依赖自然排序或者比较器排序,对键进行排序
-
如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则
-
由键决定特性:不重复,无索引,可排序
-
可排序:对键进行排序