一、集合体系结构介绍和课程安排
1、单列集合
一次添加一个元素
-
都是Collection接口的实现类
-
ArrayList、LinkedList实现了List接口
- 特点:存取有序、有索引、可以存储重复的
-
TreeSet、HashSet、LinkedHashSet实现了Set接口
- 特点:存取无序、无索引、不可以存储重复的
-
都继承了Collection,是Collection类的子接口
2、双列集合
一次添加两个元素
-
TreeMap、HashMap、LinkedHashMap

二、Collection的使用

java
Collection常用成员方法
public boolean add(E e) : 把给定的对象添加到当前集合中
public void clear() : 清空集合中所有的元素
public boolean isEmpty() : 判断当前集合是否为空
public boolean remove(E e) : 把给定的对象在当前集合中删除
public boolean contains(Object obj) : 判断当前集合中是否包含给定的对象
public int size() : 返回集合中元素的个数(集合的长度)
package com.itheima.collection;
方法的使用范例
java
import com.itheima.pojo.Student;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo1 {
public static void main(String[] args) {
Collection<Student> c = new ArrayList<>();
c.add(new Student("张三", 23));
c.add(new Student("李四", 24));
c.add(new Student("王五", 25));
//判断当前集合中是否包含给定的对象 需要重写equals方法
System.out.println(c.contains(new Student("李四", 24)));
//把给定的对象在当前集合中删除 需要重写equals方法
c.remove(new Student("李四", 24));
System.out.println(c);
}
private static void method() {
// 使用多态的形式创建集合对象
Collection<String> c = new ArrayList<>();
//把给定的对象添加到当前集合中
c.add("张三");
c.add("李四");
c.add("王五");
System.out.println(c);
//判断当前集合是否为空
System.out.println(c.isEmpty());
System.out.println(c.size());
//清空集合中所有的元素
c.clear();
System.out.println(c);
System.out.println(c.isEmpty());
System.out.println(c.size());
}
}
三、集合的通用遍历方式
1、迭代器
iterator() 返回此集合中元素的迭代器
hashNext():判断集合中是否还有元素 next():取出集合元素,并将指针向后移动
java
package com.itheima.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo2 {
/*
集合通用遍历方式 - 迭代器
*/
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
c.add("张三");
c.add("李四");
c.add("王五");
//以下为迭代器的使用案例
// 1. 通过集合对象, 获取迭代器
Iterator<String> it = c.iterator(); // new Itr();
// 2. 循环判断是否还有元素可以迭代
while (it.hasNext()) {
// 3. 循环内部获取元素
String s = it.next();
System.out.println(s);
}
}
}

cursor代表内部的指针,默认值为0
迭代器源码解析:
java
//源码
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
// prevent creating a synthetic constructor
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}

注意:在循环过程中next方法最好只调用一次

会抛出NoSuchElementException异常,表示没有元素,指针已经指空了,不能再往后指了
2、增强for循环
简化迭代器的代码书写 它是JDK5之后出现的,其内部原理就是一个Iterator迭代器
java
格式:
for(元素的数据类型变量名:数组或者集合){}
//输入list.for
for (String s: list){
System.out.println(s);
}
package com.itheima.collection;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo3 {
/*
集合通用遍历方式 - 增强 for 循环
*/
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
c.add("张三");
c.add("李四");
c.add("王五");
//遍历集合时,底层(字节码文件)会转换成迭代器
for (String s : c) {
System.out.println(s);
}
int[] arr = {11, 22, 33, 44, 55};
//遍历数组时,底层(字节码文件)是数组表示的
for (int i : arr) {
System.out.println(i);
//System.out.println(arr[i]);
//这里的i不是索引,所以不能用数组的索引遍历
}
}
}
3、forEach方法

是一个默认方法,所有的单列集合都可以直接调用该方法
java
package com.itheima.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;
public class CollectionDemo4 {
/*
集合通用遍历方式 - foreach 方法
*/
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
c.add("张三");
c.add("李四");
c.add("王五");
//forEach方法中的Consumer参数是一个函数式接口,所以可以用Lambda表达式
c.forEach(s -> System.out.println(s));
Collection<Integer> c2 = new ArrayList<>();
c2.add(111);
c2.add(222);
c2.add(333);
c2.forEach(num -> System.out.println(num));
//可以改为方法引用形式
//c2.forEach(System.out::println);
}
}
所有的单列集合都可以用以上三种方式遍历
四、方法引用
方法引用是JDK8开始出现,主要的作用,是对Lambda表达式进行进一步的简化 方法引用使用一对冒号:: 通过方法的名字来指向一个方法 可以使语言的构造更紧凑简洁,减少冗余代码
方法调用 -> MethodReference.change(s);
方法引用 -> MethodReference::change
java
Collection<string> c = new ArrayList<>();
c.add("张三");
c.add("李四");
c.add("王五");
c.forEach(System.out::println);
"ABC".toLowerCase():将字母转化为小写字母
toUpperCase():转化为大写字母
//匿名内部类:方法调用的形式
list.forEach(new Consumer<String>() {
@override
public void accept(String s) {
MethodReference.change(s);
}
});
//变为Lambda表达式:方法调用的形式
list.forEach(s->MethodReference.change(s));
//再变为方法引用
list.forEach(MethodReference::change);
//参数去哪了?
//可推导即可省略:因为上面的匿名内部类正好传了一个参数s过去,所以可以推导参数为字符串s
-
代码案例
javapackage com.itheima.reference; import java.util.ArrayList; public class MethodReference { /* 方法引用是 JDK8 开始出现,主要的作用,是对 Lambda 表达式进行进一步的简化 方法引用使用一对冒号 :: 通过方法的名字来指向一个方法 可以使语言的构造更紧凑简洁,减少冗余代码 方法调用 -> MethodReference.change(s); 方法引用 -> MethodReference::change */ public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Hello"); list.add("Hi"); list.add("HEIma"); MethodReference mr = new MethodReference(); list.forEach(mr::change); } public void change(String s) { System.out.println(s.toLowerCase()); } }
五、List接口
列表迭代器 (ListIterator):list接口下特有的迭代器
java
package com.itheima.list;
import com.itheima.pojo.Student;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class ListDemo1 {
/*
List接口特点: 存取有序, 有索引, 可以存储重复的
遍历方式:
1. 迭代器
2. 增强for
3. foreach方法
4. 普通for循环
5. 列表迭代器 (ListIterator)
*/
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student("张三", 23));
list.add(new Student("李四", 24));
list.add(new Student("王五", 25));
list.add(new Student("王五", 25));
// 1. 迭代器
Iterator<Student> it = list.iterator();
while (it.hasNext()) {
Student stu = it.next();
System.out.println(stu);
}
System.out.println("------------------------------");
// 2. 增强for
for (Student stu : list) {
System.out.println(stu);
}
System.out.println("------------------------------");
// 3. foreach方法
list.forEach(System.out::println);
System.out.println("------------------------------");
// 4. 普通for循环
for (int i = 0; i < list.size(); i++) {
Student stu = list.get(i);
System.out.println(stu);
}
System.out.println("------------------------------");
// 5. 列表迭代器 (ListIterator)
//这两个方法了解即可
ListIterator<Student> listIt = list.listIterator();
System.out.println("列表迭代器正序遍历: ");
while(listIt.hasNext()){
Student stu = listIt.next();//正序遍历的方法
System.out.println(stu);
}
System.out.println("列表迭代器倒序遍历: ");
while(listIt.hasPrevious()){
Student stu = listIt.previous();//倒序遍历的方法
System.out.println(stu);
}
}
}
-
常见异常:并发修改异常(ConcurrentModificationException)
javapublic class ConcurrentModificationException extends RuntimeException //当不允许这样的修改时,检测到对象的并发修改的方法可能抛出此异常。 //使用迭代器遍历集合的过程中,调用了集合对象的添加,删除方法,就会出现此异常代码案例:
javapackage com.itheima.list; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; public class ListDemo2 { /* 并发修改异常: ConcurrentModificationException 使用迭代器遍历集合的过程中,调用了集合对象的添加,删除方法,就会出现此异常 解决方案: 不允许使用集合的添加或删除方法, 就使用迭代器自身的添加或删除. */ public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("张三"); list.add("李四"); list.add("王五"); list.add("赵六"); //获取列表迭代器,因为只有他有添加方法 list.listIterator.var直接生成 ListIterator<String> it = list.listIterator(); while (it.hasNext()) { String name = it.next(); if ("李四".equals(name)) { it.remove(); it.add("赵四"); } } System.out.println(list); } }
六、数据结构(栈、队列、数组、链表)
栈和队列
数组:
优点:查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同 弊端:增、删效率低:新增或删除数据的时候,都有可能大批量的移动数组中其他的元素
链表:包括自己的地址、数据、下一个的地址
链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
链表查询慢,无论查询哪个数据都要从头开始找。
链表增删相对快
栈:后进先出,先进后出。 队列:先进先出,后进后出。 数组:内存连续区域,查询快,增删慢。 链表:元素是游离的,查询慢,首尾操作极快。
七、ArrayList类
ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢
ArrayList底层是数组结构的,数组默认长度为10 当数组添加满了之后,会自动扩容为1.5倍
java
/*ArrayList 源码解析
使用空参构造器创建的集合,在底层创建一个**默认长度为0**的数组
添加**第一个元素时**,底层会创建一个新的长度为10的数组
存满时,会扩容1.5倍*/
//未调用add方法之前的源码
public ArrayList(){
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
八、LinkedList类
LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的

九、泛型
泛型介绍 JDK5引入的,可以在编译阶段约束操作的数据类型,并进行检查 泛型的好处: 统一敬据类型 将运行期的错误提升到了编译期 注意事项 泛型中只能编写引用数据类型
泛型用E来表示
使用泛型:
java
package com.itheima.generics;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
public class GenericsDemo1 {
/*
泛型介绍 : JDK5引入的, 可以在编译阶段约束操作的数据类型, 并进行检查
泛型如果没有指定具体的类型, 默认为Object
泛型的好处 :
1. 统一数据类型
2. 将运行期的错误提升到了编译期
*/
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("abc");
list.add("abc");
list.add("abc");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();//it.next
System.out.println(s.length());
}
}
}
使用E不指定泛型类型
泛型常见的标识符:
E : Element 元素
T : Type 类型
K : Key 键
V : Value 值
java
package com.itheima.generics;
public class GenericsDemo2 {
/*
泛型常见的标识符:
E : Element 元素
T : Type 类型
K : Key 键
V : Value 值
*/
public static void main(String[] args) {
Student<Integer> stu1 = new Student<>();
stu1.setE(10);
}
}
class Student<E> {//在创建对象的时候由调用者自己指定数据类型
private E e;
public E getE() {
return e;
}
public void setE(E e) {
this.e = e;
}
}
泛型类
java
//在创建对象的时候由调用者自己指定数据类型
public class ArrayList<E>{
public boolean add(E e){
}
}
public class A{
public static void main(string[] args) {
ArrayList<String> list =new ArrayList<>();
list.add(String e);
}
}
public class A{
public static void main(string[] args) {
ArrayList<Integer> list =new ArrayList<>();
list.add(Integer e);
}
}
泛型方法
在方法当中加泛型
java
package com.itheima.generics;
public class GenericsDemo3 {
/*
泛型方法
非静态方法: 跟着类的泛型去匹配的
类的泛型, 是在创建对象的时候确定到具体数据类型.
静态方法: 调用方法的时候, 传入实际参数, 在这时候确定到具体的数据类型
注意: 静态方法如果声明了泛型, 必须声明出自己独立的泛型.
*/
public static void main(String[] args) {
String[] arr1 = {"张三", "李四", "王五"};
Integer[] arr2 = {11, 22, 33};
Double[] arr3 = {11.1, 22.2, 33.3};
printArray(arr1);
printArray(arr2);
printArray(arr3);
}
//静态方法的泛型在创建的时候自己作为Tybe类型,需要声明处自己独立的泛型
//调用方法的时候, 传入实际参数的时候确定具体类型的
public static <T> void printArray(T[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length - 1; i++) {
System.out.print(arr[i] + ", ");
}
System.out.println(arr[arr.length - 1] + "]");
}
}
泛型接口:
类实现接口的时候,如果接口带有泛型,有两种操作方式 1.类实现接口的时候,直接确定类型 2.保持接口的泛型,等创建对象的时候再确定
java
package com.itheima.generics;
import java.util.ArrayList;
import java.util.List;
public class GenericsDemo4 {
/*
泛型接口
1. 实现类, 实现接口的时候确定到具体的类型
2. 实现类实现接口, 没有指定具体类型, 就让接口的泛型, 跟着类的泛型去匹配
*/
public static void main(String[] args) {
InterCImpl<String> c1 = new InterCImpl<>();
c1.show("abc");
InterCImpl<Integer> c2 = new InterCImpl<>();
c2.show(123);
}
}
interface Inter<E> {//用户自己指定
void show(E e);
}
//实现接口的时候确定到具体类型
class InterAImpl implements Inter<String> {
@Override
public void show(String s) {
}
}
class InterBImpl implements Inter<Integer> {
@Override
public void show(Integer integer) {
}
}
//实现类在实现接口的时候可以在创建对象的时候给类指定泛型
class InterCImpl<E> implements Inter<E> {
@Override
public void show(E e) {
}
}
泛型通配符
可以接收任意类型
? : 任意类型
? extends E : 可以传入的是E, 或者是E的子类
? super E : 可以传入的是E, 或者是E的父类
java
package com.itheima.generics;
import java.util.ArrayList;
public class GenericsDemo5 {
/*
泛型通配符
? : 任意类型
? extends E : 可以传入的是E, 或者是E的子类
? super E : 可以传入的是E, 或者是E的父类
*/
public static void main(String[] args) {
ArrayList<Coder> list1 = new ArrayList<>();
list1.add(new Coder());
ArrayList<Manager> list2 = new ArrayList<>();
list2.add(new Manager());
ArrayList<String> list3 = new ArrayList<>();
list3.add("abc");
method(list1);
method(list2);
}
public static void method(ArrayList<? extends Employee> list) {
for (Employee e : list) {
e.work();
}
}
}
abstract class Employee {
private String name;
private double salary;
public Employee() {
}
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public abstract void work();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String toString() {
return "Employee{name = " + name + ", salary = " + salary + "}";
}
}
class Coder extends Employee {
@Override
public void work() {
System.out.println("程序员写代码...");
}
}
class Manager extends Employee {
@Override
public void work() {
System.out.println("项目经理分配任务...");
}
}
总结:
泛型类 创建对象的时候确定具体类型 泛型方法 非静态:泛型是根据类的泛型去匹配的 静态:需要声明出自己独立的泛型 泛型接口: 类实现接口的时候,直接确定类型 保持接口的泛型,等创建对象的时候再确定 泛型限定: ?(任意类型) ?extendsE(只能接收E或者是E的子类) ?superE(只能接收E或者是E的父类)