集合
数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其它类型的数据。
集合和数组有什么区别?
1)长度区别
数组:长度固定
集合:长度可变2)存储数据类型的区别
数组:可以存储基本数据类型,也可以存储引用数据类型
集合:前提条件:集合中加入泛型<>
也是在模拟数组的特点:只能存储引用类型 Collection :泛型<引用类型>3)存储元素的区别:
数组:存储的元素必须为同一种数据类型
集合:如果没有加入泛型 :就出任意类型的元素(必须引用类型)
集合框架
基本功能:
添加
boolean add(Object e):添加元素 E(Element)
删除:
void clear() 暴力删除(将集合的素有元素全部干掉)
boolean remove(Object o):从集合中删除指定的元素
获取集合的元素数 :int size()
判断功能:
boolean isEmpty():判断集合是否为空,为空元素,则返回true
boolean contains(Object o):判断集合中是否包含指定元素,包含则返回true
Collection接口:
Map接口
Collection集合的高级功能
boolean addAll(Collection c);//添加一个集合中的所有元素
boolean containsAll(Collection c);//包含一个集合中的所有元素
boolean removeAll(Collection c);//删除集合中的所有元素, (删除一个算删除,还是删除所有)
boolean retainAll(Collection c);//A集合对B集合求交集, boolean的返回值是什么意思,交集的元素是保存在A中还是B中
//Collection最基本的遍历功能,不属于集合的专有遍历
Object[] toArray();//将集合转换成了对象数组
迭代器
Collection的迭代器:集合的专有遍历方式
Iterator iterator();//返回值类型接口类型,需要返回的子实现类对象
//Iterator接口:
boolean hasNext();//判断迭代器中是否存在下一个元素
Object next();//获取下一个可以遍历的元素
//给Collection中存储String类型,遍历出来
eg,
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Scanner;
public class Test01 {
public static void main(String[] args) {
Collection<Student> collection = new ArrayList<Student>();
collection.add(new Student("老王",34));
collection.add(new Student("老张",41));
collection.add(new Student("老梁",52));
collection.add(new Student("老刘",35));
collection.add(new Student("老李",61));
for (Object object : collection) {
Student s = (Student) object;
System.out.println(s.toString() + "学生");
System.out.println(object.toString() + "toString");
/*
Iterator<Student> iterator = collection.iterator();
while(iterator.hasNext()){
Object object = iterator.next();
Student s = (Student)object;
System.out.println(s.toString()+"学生");
System.out.println(object.toString()+"toString");
*/
}
}
}
class Student{
String name;
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 +
'}';
}
}
运行结果:
Student{name=‘老王’, age=34}学生
Student{name=‘老王’, age=34}toString
Student{name=‘老张’, age=41}学生
Student{name=‘老张’, age=41}toString
Student{name=‘老梁’, age=52}学生
Student{name=‘老梁’, age=52}toString
Student{name=‘老刘’, age=35}学生
Student{name=‘老刘’, age=35}toString
Student{name=‘老李’, age=61}学生
Student{name=‘老李’, age=61}toString
迭代器原理
内部具备一个指针,当在第一次获取元素的时候,指针处在第一个元素前面的位置,不指向任何元素,当通过hasNext()判断,如果存在下一个可以迭代的元素,那么指针就会向下一个索引进行移动,并且next()获取前面的元素,依次这样操作,直到hasNext()为false的时候,没有元素了,指针就不会在移动;Iterator是一个接口,具体的移动的操作是通过ArrayList的成员内部类Itr来进行实现;
泛型
格式:
集合类型<引用数据类型> 集合对象名 = new 子实现类<引用数据类型>() ;
泛型的好处:
1)将运行时期异常提前了编译时期
2)避免了强制类型转换
3)提高了程序安全性
eg.使用Collection集合存储5个学生,加入泛型 Collection,使用迭代器遍历并获取
public class GenericDemo {
public static void main(String[] args) {
//创建Collection集合对象
Collection<String> c = new ArrayList<String>() ; //new XXX<数据类型>: jdk7以后泛型推断
c.add("hello") ;
c.add("高圆圆") ;
c.add("你好吗") ;
//获取迭代器Iteratr<E>是集合中存储的泛型是一致的
Iterator<String> it = c.iterator();
while(it.hasNext()){
//获取String字符串的同时,还要获取长度
String str = it.next();
System.out.println(str+"---"+str.length());
}
}
}
List集合
特点
有序(存储元素和取出元素一致)
允许元素重复
具备Collection相关的功能
Object [] toArray()
Iterator iterator()
特有功能
void add(int index,Object element):在指定的索引处插 入元素
Object get(int index):获取指定位置处的元素 + int size():一种新的集合遍历方式
Object remove(int index):删除指定位置处的元素
Object set(int index,E element):修改指定位置处的元素(替换)
ListIterator<E> listIterator():列表迭代器
ListIterator接口:
void add(E e)有添加
remove():有删除
特有功能
void add(int index,Object element):在指定的索引处插 入元素
Object get(int index):获取指定位置处的元素 + int size():一种新的集合遍历方式
Object remove(int index):删除指定位置处的元素
Object set(int index,E element):修改指定位置处的元素(替换)
ListIterator listIterator():列表迭代器
ListIterator接口:
void add(E e)有添加
remove():有删除
集合的遍历
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Test01 {
public static void main(String[] args) {
List<Person> list = new ArrayList<Person>();
list.add(new Person("老大", 12));
list.add(new Person("老二", 11));
list.add(new Person("老三", 10));
//①toArray
Object[] objects = list.toArray();
for (int i = 0; i < objects.length; i++) {
Person person = (Person) objects[i];
System.out.println(person.toString());
}
System.out.println("————————");
//②get/set
Object[] objects1 = list.toArray();
for (int i = 0; i < objects1.length; i++) {
Person person = (Person) objects[i];
System.out.println(person.getName()+"----"+person.getAge());
}
System.out.println("————————");
//③迭代器
Iterator<Person> iterator = list.iterator();
while (iterator.hasNext()) {
Person p = iterator.next();
System.out.println(p.toString());
}
System.out.println("————————");
//④list迭代器
ListIterator<Person> iterator1 = list.listIterator();
while (iterator1.hasNext()) {
Person p = iterator1.next();
System.out.println(p.toString());
}
System.out.println("————————");
while (iterator1.hasPrevious()) {
Person p = iterator1.previous();
System.out.println(p);
}
System.out.println("————————");
//⑤增强for
for (Person p : list) {
System.out.println(p);
}
}
}
class Person {
String name;
int age;
public Person() {
}
public Person(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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
运行结果:
Person{name=‘老大’, age=12}
Person{name=‘老二’, age=11}
Person{name=‘老三’, age=10}
————————
老大----12
老二----11
老三----10
————————
Person{name=‘老大’, age=12}
Person{name=‘老二’, age=11}
Person{name=‘老三’, age=10}
————————
Person{name=‘老大’, age=12}
Person{name=‘老二’, age=11}
Person{name=‘老三’, age=10}
————————
Person{name=‘老三’, age=10}
Person{name=‘老二’, age=11}
Person{name=‘老大’, age=12}
————————
Person{name=‘老大’, age=12}
Person{name=‘老二’, age=11}
Person{name=‘老三’, age=10}
并发修改异常
通过List集合ArrayList集合对象,如果当前集合中存在"world"元素,那么就给集合中添加一个"javaEE"元素,最后将集合中的所有元素进行遍历!
问题描述
当集合的元素正在被迭代器进行遍历,那么集合对象是不能够对元素进行增加或者删除 (一个线程正在遍历,一个线程在修改元素)
解决方案
1)要么就是迭代器去遍历集合的元素,迭代器去添加元素 :列表迭代器才具备添加的动作
2)要么集合遍历,集合添加
eg.
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Test02 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("helo");
list.add("world");
list.add("java");
/*
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String s = iterator.next();//java.util.ConcurrentModificationException并发修改异常
if("world".equals(s)){
list.add("javaee");
}
System.out.println(list);
}
会报错
[helo, world, java]
[helo, world, java, javaee]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at HemoWork.day19.ClassTest.ListTest.Test02.main(Test02.java:19)
*/
//解决方法1
//用迭代器添加
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
String s = it.next();
if ("world".equals(s)) {
//迭代器添加
it.add("javaee");
}
}
System.out.println(list);
System.out.println("-------------");
//解决方法2
//用集合添加(只能加到末尾
for (int i = 0; i < list.size(); i++) {
String string = list.get(i);
if("world".equals(string)){
list.add("javaee");
}
}
System.out.println(list);
}
}
运行结果:
[helo, world, javaee, java]
[helo, world, javaee, java, javaee]
foreach
JDK5以后 提供了增强for循环,替代集合中迭代器去遍历集合使用的(优先在集合中使用)
格式:
for(存储的引用数据类型 变量名: 集合/数组对象){ //集合使用居多,数组一般都是使用普通for
使用变量名即可
}
注意事项:
当前集合对象不能为空 null :foreach语句;
增强for它本身就是获取迭代器了,就会出现空指针异常
cantions方法
List集合如何去重?
eg.1
import java.util.ArrayList;
import java.util.List;
public class Test03 {
public static void main(String[] args) {
List<String> list = new ArrayList();
list.add("hello");
list.add("hello");
list.add("hello");
list.add("hello1");
list.add("hello");
list.add("hello3");
list.add("hello");
list.add("hello");
list.add("hello5");
list.add("hello");
//去重
//方法一:新建一个空集合,
List<String> newlist = new ArrayList<>();
for (String s : list) {
if (!newlist.contains(s)) {
newlist.add(s);
}
}
for (String s2 : newlist) {
System.out.println(s2);
}
list.add("hello");
list.add("hello");
list.add("hello");
list.add("hello1");
list.add("hello");
list.add("hello3");
list.add("hello");
list.add("hello");
list.add("hello5");
list.add("hello");
System.out.println("——————————");
//方法二:利用选择排序的思想
//两辆比较
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).contains(list.get(j))) {
list.remove(j);
j--;
}
}
}
for (String s2 : list) {
System.out.println(s2);
}
}
}
运算结果:
hello
hello1
hello3
hello5
——————————
hello
hello1
hello3
hello5
eg.2
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class Test04 {
public static void main(String[] args) {
List<Student> list = new ArrayList();
list.add(new Student("老大"));
list.add(new Student("老大"));
list.add(new Student("老二"));
list.add(new Student("老大"));
list.add(new Student("老三"));
list.add(new Student("老大"));
//新建集合
List<Student> newList = new ArrayList<>();
for (Student student : list) {
if (!newList.contains(student)) {
newList.add(student);
}
}
for (Student s : newList) {
System.out.println(s);
}
System.out.println("————————————");
//选择排序思想
list.add(new Student("老大"));
list.add(new Student("老大"));
list.add(new Student("老二"));
list.add(new Student("老大"));
list.add(new Student("老三"));
list.add(new Student("老大"));
for (int i = 0; i < list.size()-1; i++) {
for (int j = i+1; j < list.size(); j++) {
if(list.get(i).getName().contains(list.get(j).getName())){
list.remove(j);
j--;
}
}
}
for (Student s : list){
System.out.println(s);
}
}
}
class Student {
String name;
public Student() {
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return name.equals(student.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}
运行结果:
Student{name=‘老大’}
Student{name=‘老二’}
Student{name=‘老三’}
————————————
Student{name=‘老大’}
Student{name=‘老二’}
Student{name=‘老三’}
list子实现类的特点
ArrayList
ArrayList集合初始化容量10
扩容为原容量1.5倍。
底层是数组,查询快,增删慢
另外要注意:ArrayList集合末尾增删元素效率还是可以的。
线程角度: 线程不安全的类,实现不同步的 ----->执行效率高
Vector
Vector初始化容量是10.
扩容为原容量的2倍。
底层是数组,查询快,增删慢
Vector底层是线程安全的。
线程角度:线程安全的类----同步的方法---->执行效率低
怎么得到一个线程安全的List:
Collections.synchronizedList(list);单线程程序中.考虑集合默认都会使用 ArrayList,多线程环境集合---->Vector集合
LinkedList
底层数据结构是链表,查询慢,增删快
线程角度:线程不安全的类---->不同步---->执行效率高
特有功能:
addFirst() removeFirst() getFirst()
xxxLast()
应用场景:模拟栈结构特点,先进后出
如果没有明确要求使用什么(List)集合的时候 ,默认都是用ArrayList
Vector类
特有功能:
public void addElement(Object obj);//在vector对象的末尾添加元素 ------> 一直使用的add(Object e)
删除
public boolean removeElement(Object obj);//删除元素
获取功能
public Object elementAt(int index);//获取指定位置的元素---->类似于 public Object get(int index)
public Enumeration<E> elements();//Vector集合的专有遍历方式---->类似于 Iterator literator();接口
boolean hasMoreElements();//判断是否有更多的元素可以迭代
Object nextElement();//获取元素
eg.
import java.util.ArrayList;
import java.util.List;
public class Test01 {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<String >();
//添加元素
list.add("hello") ;
list.add("hello") ;
list.add("world") ;
list.add("world") ;
list.add("world") ;
list.add("javaEE") ;
list.add("javaEE") ;
// void add(int index,Object element):在指定的索引处插 入元素
list.add(1,"高圆圆");
//Object get(int index):获取指定位置处的元素 :返回的被获取到的元素内容
System.out.println(list.get(1));
// Object remove(int index):删除指定位置处的元素,返回被删除的元素
System.out.println(list.remove(2));
//Object set(int index,E element):修改指定位置处的元素(替换)
System.out.println(list.set(1,"赵又廷"));
System.out.println(list);
}
}
直接插入排序
核心思想:使用1角标对应的元素进行和0角标比较,如果前面元素大,向右移动,确定角标1对应的元素的位置,再次使用2角标对应的元素依次和1和0都元素比较,依次这样比较。
/*
Integer类:包含了int类型的值:
Integer实现自然排序(默认升序排序)
*/
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) { //提高程序的执行效率
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
eg.
public class InsertSort {
public static void main(String[] args) {
int[] arr = {34, 8, 64, 51, 32, 21};
System.out.println("排序前:");
printArr(arr);
System.out.println("排序后:");
insertSort(arr);
}
private static void printArr(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.println(arr[i] + "]");
} else {
System.out.print(arr[i] + ",");
}
}
}
private static void insertSort(int[] arr) {
//定义一个变量,记录当前角标的变化
int index;
//定义变量:P表示一个比较次数
for (int p = 0; p < arr.length; p++) {
//定义临时变量temp
Integer temp = arr[p];//temp = 8;temp = 64
//开始比较
for (index = p; index > 0 && temp.compareTo(arr[index - 1]) < 0; index--) {
// j=1 ; 1>0 && 8 < 34 j-- : j= 0
// j=2 ; 2>0 && 64 < 32
//数据移动
arr[index] = arr[index - 1];
}
//确定temp的位置
arr[index] = temp;
}
printArr(arr);
}
}
运行结果:
排序前:
[34,8,64,51,32,21]
排序后:
[8,21,32,34,51,64]
LinkedList类
集合特点:
线程不安全,执行效率较高,是个列表结构
特有功能:
public void addFirst(0bject e):在列表开头插入元素
pub1ic void addLast(0bject e):将元素追加到列表的末尾
public 0bject getFirst(): 获取列表的第一个元 素
public 0bject getLast():获取 列表的最后一 个元素
public 0bject removeFirst(): 删除列表的第个元素
public 0bject removeLast() :删除列表的最后一个元素
push压栈
pop弹栈
利用Linkedlist模拟栈数据结构:
import java.util.LinkedList;
//栈方法类
public class MyStack {
private LinkedList<Object> link;
//空参构造
public MyStack() {
link = new LinkedList<Object>();
}
public MyStack(LinkedList<Object> link) {
this.link = link;
}
//添加方法
public void add(Object o) {
link.addFirst(o);
}
//获取获取元素
public void get(){
System.out.println(link.removeFirst());
}
//判断是否为空
public void isEmpty(){
if (link.isEmpty()){
System.out.println("栈为空");
}else {
System.out.println("栈不为空");
}
}
public LinkedList getLink() {
return link;
}
public void setLink(LinkedList link) {
this.link = link;
}
}
//工具类
public class Test01 {
public static void main(String[] args) {
//创建对象
MyStack stack = new MyStack();
//压栈
stack.add("sad");
stack.add(123);
stack.add(1.2234);
stack.add(true);
//判断是否为空
stack.isEmpty();
//弹栈
stack.get();
stack.get();
stack.get();
stack.get();
//判断是否为空
stack.isEmpty();
}
}
运行结果:
栈不为空
true
1.2234
123
sad
栈为空
HashSet类
底层数据结构是一个哈希表
线程不安全的类---->不同步---->执行效率高
Set集合特点:
无序(存储和取出不一致),能够保证元素唯一
JUC(java.util.concurrent)
JDK8以后,提供了juc(并发包:java.util.concurrent):
ConcurrentHashMap<K,V>和HashMap的区别 ?
前者线程安全,后者线程不安全
hashCode方法及equals方法
String类型:String类型本身已经重写了hashCode()和equals,如果hashCode和equals()都相同,那么认为同一个元素,存储以前的值
如果现在存储是自定义对象,如何保证元素唯一?
HashSet<Student>
Student s1 = new Student("高圆圆"42) ;
Student s2 = new Student("高圆圆"42) ;
/*
HashSet集合依赖于add方法---->HashMap的put方法
首先要比较元素的哈希码值相同----->hash()就相同
还要比较成员信息是否相同,对应存储自定的类必须要重写Object的equals方法
Student的这个类,必须手动给出hashCode()和equals
Hashset集合不能保证顺序迭代恒久不变!
*/
应用场景:
在一些需求中,如果没有明确要求元素重复,那就可以使用hashSet,保证元素唯一!
类型:String,Integer,Long,…常用类都已经重写了hashCode和equals方法
TreeSet类:
集合特点:
无序性,元素唯一
底层依赖于TreeMap集合, 红黑树结构(也称为 “自平衡的二叉树结构”),可以实现Map的自然排序以及比较器排序取决于使用的构造方法
构造方法:
public TreeSet();//构造一个空的树,实现元素自然排序 (取决于存储的元素类型能否实现Comparable接口)
TreeSet能够实现两种排序:
自然排序:
TreeSet<E>();//E类型必须实现Comparable接口,实现自然排序(实现的compareTo(T t))
比较强排序:
public TreeSet(Comparator<? super E> comparator)
Comparator是一个接口类型
1)自定义一个类实现Comparator接口,重写compare方法
eg.
import com.sun.istack.internal.NotNull;
import java.util.Objects;
import java.util.TreeSet;
public class TreeSetTest01 {
public static void main(String[] args) {
TreeSet<Student> set = new TreeSet<>();
set.add(new Student("laoAAAAA", 14));
set.add(new Student("laoA", 10));
set.add(new Student("laoAA", 11));
set.add(new Student("laoA", 11));
set.add(new Student("laoAAAA", 13));
set.add(new Student("laoAA", 12));
set.add(new Student("laoAAA", 12));
for (Student s : set) {
System.out.println(s.toString());
}
}
}
class Student implements Comparable<Student> {
String name;
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 boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
name.equals(student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//利用接口的子实现类完成比较
public int compareTo(@NotNull Student s) {
int num = this.age - s.age;
int num2 = this.name.compareTo(s.name);
int num3 = num2 == 0 ? num : num2;
return num3;
}
}
2)使用接口的匿名内部类(推荐)
eg.
public class TreeSetTest02 {
public static void main(String[] args) {
//匿名内部类完成比较
TreeSet<Student2> set = new TreeSet<>(new Comparator<Student2>() {
@Override
public int compare(Student2 s1, Student2 s2) {
int num = s1.age - s2.age;
int num2 = s1.name.compareTo(s2.name);
int num3 = num2 == 0 ? num : num2;
return num3;
}
});
set.add(new Student2("laoAAAAA", 14));
set.add(new Student2("laoA", 10));
set.add(new Student2("laoAA", 11));
set.add(new Student2("laoA", 11));
set.add(new Student2("laoAAAA", 13));
set.add(new Student2("laoAA", 12));
set.add(new Student2("laoAAA", 12));
for (Student2 s : set) {
System.out.println(s.toString());
}
}
}
class Student2 {
String name;
int age;
public Student2() {
}
public Student2(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 boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student2 student = (Student2) o;
return age == student.age &&
name.equals(student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}