泛型的好处 !
为什么学习集合
对比数组,
1长度固定一旦定义 不能修改 定义多少合适呢 定义太小不够 大了浪费
自动去扩容 -》 ArrayList本质是一个数组
2能放任意类型的数据
3根据下标查询某个元素 速度快
4对于插入和删除 慢 对这个操作 我们需要挪位 同时需要拿到一个新数组去装新数据 -》链表结构
5我们之前存放的数据 一维数组存放的是单列数据 针对双列数据 比如我们常见的书的目录 -》详情页 电话号码 -》张三怎么存 假如使用数组多维,应该也很麻烦
Map(key,value)
1.3学习目标/集合体系
2集合是什么
数组是一个容器 集合也是一个容器 放数据 放任何类型的数据
2.1Collection 之方法概览
掌握这个接口中有哪些公共的方法
方法整体概览
2.2泛型集合
我们在遍历集合的时候,若该集合中存放的是多种数据类型,若只想获取某一种,需要强转,若不强转,则会抛出运行时异常 类型转换异常
1期望 能否不需要强转 将运行时异常 提前到编译时
2限定这个集合中只能存放学生,若放别的
--》使用泛型约束,泛型集合,即约束当前集合中,只能存放的数据类型
好处:1限定类型,将运行时异常,提前到编译器,
2不需要进行类型转换
2.3Iterator
使用迭代器的目的就是获取元素,不要在这里用集合的方法修改!!
1基本使用
常用的两个方法
- 1hasNext()判断是否有下一个元素
- 2next() :获取当前迭代器中的每个元素值
2使用时要注意的事项 在使用集合的方法进行修改操作(修改删除),可能出现如下异常ConcurrentModificationException
注意 在使用迭代器的时候 尽量不要使用集合的方法,进行修改操作,你要移除元素的话,用迭代器中的remove()。
3大致原理,做一个大致了解
有一个指针一样的东西,在指向你要取到哪一个元素,在hasNext()方法中,有元素的条件如下。
public boolean hasNext() {
//在ArrayList中,定义了一个内部类,
// cursor 是内部类中的一个成员,默认值是0,每次调用next()方法时,cursor会+1
return cursor != size;
}
next ()逻辑
public E next() {
//校验你是否做过修改,往集合中添加元素、删除元素、修改元素,都是修改操作,都会+1记录
checkForComodification();
//定义一变量来
int i = cursor;
//当i>=size时,会抛出没有这个元素的异常,这块就当成数组,比如数组的长度为2,则下标最大为1
if (i >= size)
throw new NoSuchElementException();
//就是将你当前集合中的元素,放在对象数组中
Object[] elementData = ArrayList.this.elementData;
//若你的i大于等于elementData.length,也会抛出ConcurrentModificationException
if (i >= elementData.length)
throw new ConcurrentModificationException();
//每次调用next方法,即从迭代器中获取一次值,要将cursor+1
cursor = i + 1;
return (E) elementData[lastRet = i]; //将i赋值给了lastRet,lastRet默认值-1
}
2.4ArrayList
重点,实际使用 的非常多,面试也喜欢问这个部分的源码部分
2.4.1基本使用
方法概览,只截取一小部分
需要掌握的特有方法
add(int index,Object obj)
get(int index)
sort(Comparator c) :
这个Comparator是一个函数式接口,可以直接使用lambda
ArrayList的便利方式,
1经典for循环
2增强for循环
3迭代器
4foreach
2.4.2源码部分
构造方法:提供了三个构造方法
3泛型
4ArrayList源码
注意:经典for的速度快于迭代器
ArrrayList练习
package kgc_byme.day16.test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
/**
* @Description:
* @author:myh
* @date: 2021/6/1 9:47
*/
public class test {
public static void main(String[] args) {
Collection list=new ArrayList();
list.add(1);
list.add("a");
list.add("b");
list.add(new Stu(4,"sasa"));
list.add(new Stu(3,"sas2333a"));
for (Object o : list) {
if(o instanceof Stu)
System.out.println(((Stu)o).name);
}
}
}
class Stu{
int age;
String name;
public Stu(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Stu{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
迭代器
执行原理
函数式接口的用法
package kgc_byme.day16.t1;
import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* @Description: TODO
* @author: azzhu
* @date:2021/6/1 14:15
*/
public class TestFunctionInterface {
public static void main(String[] args) {
//4大函数式接口的使用
// 1. `Function<T, R>`:功能型接口,`R apply(T t);`
// 2. `Consumer<T>`:消费型接口,`void accept(T t)`
// 3. `Supplier<T>`:供给型接口,`T get()`
// 4. `Predicate<T>`:预测型接口,`boolean test(T t)`
//1.进一个字符串,出一个学生对象,为name赋值
Function<String, Stu2> f1 = t -> {
Stu2 stu = new Stu2();
stu.name = t;
return stu;
};
Function<Integer, Integer> f2 = t -> t*t; //map
System.out.println(f1.apply("aaa"));
// System.out.println(f2.andThen().andThen()); //链式调用
//2.给一个学生对象,打印它的名字
Stu2 ss = new Stu2("aaaaaaa",2222);
Consumer<Stu2> cc = aa -> System.out.println(aa.name);
cc.accept(ss);
//3.返回一个学生对象
Supplier<Stu> s1 = () -> new Stu();
Supplier<Stu> s2 = Stu::new; //方法引用
System.out.println(s2.get());
//4.Predicate<T>:输入一个学生对象,看他的年龄是否大于2岁
Predicate<Stu2> p = sr -> sr.age > 20;
System.out.println(p.test(ss));
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//结合Stream一起去使用
// list.stream().filter(sr -> sr > 2).forEach(e -> System.out.println(e));
list.stream().filter(sr -> sr > 2).forEach(System.out::println);
}
}
class Stu2 {
String name;
int age;
public Stu2(String name, int age) {
this.name = name;
this.age = age;
}
public Stu2(){}
@Override
public String toString() {
return "Stu2{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}