一、集合体系结构
Collection单列集合:Collection代表单列集合,每个元素(数据)只包含一个值。
Map:Map代表双列集合,每个元素包含两个值(键值对)
1. Collection集合体系
Collection<E> 接口和实现类
List系列集合:添加的元素是有序、可重复、有索引。
- ArrayList、LinekdList:有序、可重复、有索引。
Set系列集合:添加的元素是无序、不重复、无索引。
- HashSet:无序、不重复、无索引;
- LinkedHashSet:有序、不重复、无索引。
- TreeSet:按照大小默认升序排序、不重复、无索引。
1.1 Collection接口中必须实现的方法
Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
public class CollectionList {
public static void main(String[] args) {
Collection<String> collection= new ArrayList<>();// 多态写法
//1.public boolean add(E e):添加元素,添加成功返回true.
collection.add("java1");
collection.add("java2");
collection.add("java3");
System.out.println(collection);
System.out.println(collection);
//2.public boolean isEmpty():判断集合是否为空 是空返回true,反之。
boolean empty = collection.isEmpty();
System.out.println(empty);
//3.public int size():获取集合的大小。
System.out.println(collection.size());
//4.public boolean contains(0bject obj):判断集合中是否包含某个元素。
System.out.println(collection.contains("java1"));
//5.public boolean remove(E e)f删除某个元素:如果有多个重复元素默认删除前面的第一个!
System.out.println(collection.remove("java2"));
//6.public 0bject[]toArray():把集合转换成数组
Object[] array = collection.toArray();
System.out.println(Arrays.toString(array));
//7.public 0bject[]toArray(new String[]):把集合转换成指定类型的数组
String[] array1 = collection.toArray(new String[collection.size()]);
System.out.println(Arrays.toString(array1));
//8.public void clear():清空集合的元素。
collection.clear();
Collection<String> c1=new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection<String> c2 =new ArrayList<>();
c2.add("java3");
c2.add("java4");
c1.addAll(c2);//就是把c2集合的全部数据倒入到c1集合中去。
System.out.println(c1);
System.exit(0);
ArrayList<String> strings = new ArrayList<>();
strings.add("java1");
strings.add("java2");
strings.add("java3");
System.out.println(strings.get(1));
strings.set(1,"java4");
System.out.println(strings);
HashSet<String> strings1 = new HashSet<>();
strings1.add("java1");
strings1.add("java2");
strings1.add("java3");
System.out.println(strings1);
}
}
1.2 Collection的遍历方式
1.2.1 迭代器
迭代器是用来遍历集合的专用方式(数组没有迭代器),在lava中迭代器的代表是Iterator
next()将数据取出来并移动到下一个位置
1.2.2 增强for(常见)
- 增强for可以用来遍历集合或者数组
- 增强for遍历集合,本质就是迭代器遍历集合的简化写法。
1.2.3 lambda表达式
- 得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的方式来遍历集合。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.function.Consumer;
public class CollectionTest {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
c.add("花火");
c.add("希儿");
c.add("符玄");
c.add("银狼");
System.out.println(c);
System.out.println("------------迭代器遍历------------");
Iterator<String> iterator = c.iterator();
while (iterator.hasNext()){
String ele=iterator.next();
System.out.println(ele);
}
System.out.println("------------for 增强遍历------------");
for(String s:c){
System.out.println(s);
}
System.out.println("------------foreach 遍历------------");
c.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
c.forEach(s-> System.out.println(s));
c.forEach(System.out::println);
}
}
package com.CollectionTest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest1 {
public static void main(String[] args) {
//1.创建一个集合容器负责存储多部电影
Collection<Movie> movies = new ArrayList<>();
movies.add(new Movie("三大队",9.5,"张译"));
movies.add(new Movie("非诚勿扰3",9.5,"葛优"));
movies.add(new Movie("照明商店",9.5,"章若楠"));
System.out.println(movies);
System.out.println("---iterator---");
Iterator<Movie> iterator = movies.iterator();
while (iterator.hasNext()){
Movie m = iterator.next();
System.out.println(m);
}
System.out.println("---for增强---");
for (Movie movie : movies) {
System.out.println(movie);
}
System.out.println("---foreach---");
movies.forEach(System.out::println);
}
}
package com.CollectionTest;
public class Movie {
private String name;
private double score;
private String actor;
public Movie() {
}
public Movie(String name, double score, String actor) {
this.name = name;
this.score = score;
this.actor = actor;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String getActor() {
return actor;
}
public void setActor(String actor) {
this.actor = actor;
}
@Override
public String toString() {
return "Movie{" +
"name='" + name + '\'' +
", score=" + score +
", actor='" + actor + '\'' +
'}';
}
}
2. List集合
List系列集合特点:有序,可重复,有索引
- 底层实现不同!适合的场景不同!
- ArrayList:有序,可重复,有索引。
- LinkedList:有序,可重复,有索引。
List集合因为支持索引,所以多了很多与索引相关的方法,当然,Collection的功能List也都继承了
package com.CollectionTest;
import java.util.ArrayList;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
// 1.创建一个ArrayList集合对象(有序、可重复、有索引)
List<String> str = new ArrayList<>();// 一行经典代码
str.add("花火");
str.add("银狼");
str.add("希儿");
str.add("田馥甄");
// 2.public void add(int index,E element):在某个索引位置播入元素。
str.add(1,"导演");
System.out.println(str);
// 3.publicE remove(int index):根据索引删除元素,返回被删除元素
System.out.println(str.remove("花火"));
System.out.println(str.remove(3));
System.out.println(str);
// 4.public E get(int index):返回集合中指定位置的元素。
System.out.println(str.get(0));
// 5.public E set(int index,E element): 修改索引位置处的元素,修改成功后,会返回原来的数据
System.out.println(str.set(0,"阮梅"));
System.out.println(str);
}
}
List集合支持的遍历方式
for循环 因为有索引的
for增强
迭代器
foreach
for (int i = 0; i < str.size(); i++) {
System.out.println(str.get(i));
}
Iterator<String> iterator = str.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
for (String s : str) {
System.out.println(s);
}
str.forEach(System.out::println);
2.1 底层原理
数据结构不同,应用场景不同底层采用的。存储、组织数据的方式不同的。
2.1.1 ArrayList
- 基于数组实现的。查改快,增删慢。
- 查询速度快(注意:是根据索引查询数据快)
- 删除效率低:可能需要把后面很多的数据进行前移
- 添加效率极低:可能需要把后面很多的数据后移,再添加元素;或者也可能需要进行数组的扩容。
- 1、ArrayList适合:根据索引查询数据比如根据随机索引取数据(高效)!或者数据量不是很大时!
- 2、ArrayList不适合:数据量大的同时,又要频繁的进行增删操作!
2.1.2 LinkedList
- 基于双链表实现的。
- 特点:查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的。
- LinkedList新增了:很多首尾操作的特有方法。
链表的特点1:查询慢,无论查询哪个数据都要从头开始找
链表的特点2:链表增删相对快
特点:查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的。
package com.CollectionTest;
import java.util.LinkedList;
import java.util.List;
public class LinkedListTest {
public static void main(String[] args) {
List<Movie> movies = new LinkedList<>();
movies.addLast(new Movie("三大队",9.5,"张译"));
movies.addLast(new Movie("非诚勿扰3",9.5,"葛优"));
movies.addLast(new Movie("照明商店",9.5,"章若楠"));
System.out.println(movies);
System.out.println(movies.removeFirst());
System.out.println(movies);
---------------------------------------
System.out.println(movies.getFirst());
movies.addFirst(new Movie("照明商店",9.5,"章若楠"));
System.out.println(movies);
}
}
可以把addFirst换成push 把removeFirst换成pop
package com.CollectionTest;
import java.util.LinkedList;
import java.util.List;
public class StackTest {
public static void main(String[] args) {
List<String> stacks = new LinkedList<>();
stacks.addFirst("1");
stacks.addFirst("2");
stacks.addFirst("3");
stacks.addFirst("4");
System.out.println(stacks);
System.out.println(stacks.removeFirst());
System.out.println(stacks.removeFirst());
System.out.println(stacks);
}
}
3. Set集合
Set系列集合特点:无序:添加数据的顺序和获取出的数据顺序不一致;不重复;无索引; 只会无序一次的
- HashSet:无序、不重复、无索引
- LinkedHashset:有序、不重复、无索引。
- TreeSet:排序、不重复、无索引。 默认升序排序的。
注意:
Set要用到的常用方法,基本上就是Collection提供的!
自己几乎没有额外新增一些常用功能!
Movie m1 =new Movie("三大队",9.5,"张译");
Movie m2 =new Movie("非诚勿扰3",9.5,"葛优");
System.out.println(m1.hashCode());
System.out.println(m2.hashCode());
String st1 = "abc";
String str2 = "acD";
System.out.println(st1.hashCode());
System.out.println(str2.hashCode());
3.1 HashSet集合的底层原理
- 基于哈希表实现。
- 哈希表是一种增删改查数据,性能都较好的数据结构。
哈希表
- JDK8之前,哈希表数组+链表
- JDK8开始,哈希表=数组+链表+红黑树
在加载因子 16x0.75=12个时就自动扩容两倍了。
3.1.1 HashSet集合去重复的机制
- Hashset集合默认不能对内容一样的两个不同对象去重复!
- 比如内容一样的两个学生对象存入到Hashset集合中去,Hashset集合是不能去重复的!
- 如何让Hashset集合能够实现对内容一样的两个不同对象也能去重复???
- 结论:如果希望Set集合认为2个内容一样的对象是重复的必须重写对象的hashcode()和equals()方法
3.2 LinkedHashSet集合的底层原理
- 依然是基于哈希表(数组、链表、红黑树)实现的。
- 但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置
3.3 TreeSet集合的底层原理
- 特点:不重复、无索引、可排序
- 默认升序排序 ,按照元素的大小,由小到大排序)
- 底层是基于红黑树实现的排序
注意:
- 对于数值类型:Integer,Double,默认按照数值本身的大小进行升序排序。
- 对于字符串类型:默认按照首字符的编号升序排序。
- 对于自定义类型如student对象,Treeset默认是无法直接排序的。
注意:如果类本身有实现Comparable接口,TreeSet集合同时也自带比较器,默认使用集合自带的比较器排序。
注意事项:集合的并发修改异常问题
集合的并发修改异常
- 使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。
- 无法使用for增强循环和lambda表达式解决该问题
- 使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。
- 由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删R除集合中的数据时,程序也会出现并发修改异常的错误
- 使用迭代器遍历集合,但用迭代器自己的删除方法删除数据即可。
- 如果能用for循环遍历时:可以倒着遍历并删除;或者从前往后遍历,但删除元素后做i --操作。
for (int i = 0; i < integers.size(); i++) {
if(integers.get(i).contains("小")){
integers.remove(integers.get(i));
i--;
}
}
System.out.println(integers);
for (int i = integers.size()-1; i >=0 ; i--) {
if(integers.get(i).contains("小")){
integers.remove(integers.get(i));
}
}
System.out.println(integers);package com.CollectionTest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TreeSetTest {
public static void main(String[] args) {
List<String> integers = new ArrayList<>();
integers.add("小李子");
integers.add("王富贵");
integers.add("小彩蝶");
integers.add("小日子");
System.out.println(integers);
Iterator<String> iterator = integers.iterator();
while (iterator.hasNext()){
String next = iterator.next();
if(next.contains("小")){
iterator.remove();
}
}
System.out.println(integers);
for (int i = 0; i < integers.size(); i++) {
if(integers.get(i).contains("小")){
integers.remove(integers.get(i));
i--;
}
}
System.out.println(integers);
for (int i = integers.size()-1; i >=0 ; i--) {
if(integers.get(i).contains("小")){
integers.remove(integers.get(i));
}
}
System.out.println(integers);
}
}