1 为什么用集合?
- 数组的特点
- 数组定义完成并启动后,类型确定、长度固定
- 不适合元素的个数和类型不确定的业务场景,更不适合做需要增删数据操作
- 数组的功能比较的单一,处理数据的能力并不是很强大
- 集合的特点
- 集合的大小不固定,启动后可以动态变化,类型也可以选择不固定
- 集合非常适合元素个数不能确定,且需要做元素的增删操作的场景
- 集合提供的种类特别的丰富,功能非常强大,开发中集合用的更多
2 集合类体系结构
- Collection单列集合,每个元素(数据)只包含一个值
- Map双列集合,每个元素包含两个值(键值对)
3 Collection集合
- List系列集合:添加的元素是有序、可重复、有索引
- ArrayList、LinekdList :有序、可重复、有索引
- Set系列集合:添加的元素是无序、不重复、无索引
- HashSet:无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:按照大小默认升序排序、不重复、无索引
3.1 Collection常用API
- Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的
方法名称 | 说明 |
---|---|
public boolean add(E e) | 把给定的对象添加到当前集合中 |
public void clear() | 清空集合中所有的元素 |
public boolean remove(E e) | 把给定的对象在当前集合中删除 |
public boolean contains(Object obj) | 判断当前集合中是否包含给定的对象 |
public boolean isEmpty() | 判断当前集合是否为空 |
public int size() | 返回集合中元素的个数 |
public Object[] toArray() | 把集合中的元素,存储到数组中 |
代码示例
public class CollectionDemo {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
// 1.添加元素, 添加成功返回true。
c.add("Java");
c.add("HTML");
System.out.println(c.add("HTML")); // true
c.add("MySQL");
c.add("Java");
System.out.println(c); // [Java, HTML, HTML, MySQL, Java]
// 2.清空集合的元素。
c.clear();
System.out.println(c);
// 3.判断集合是否为空 是空返回true,反之。
System.out.println(c.isEmpty());
// 4.获取集合的大小。
System.out.println(c.size());
// 5.判断集合中是否包含某个元素。
System.out.println(c.contains("Java")); // true
System.out.println(c.contains("java")); // false
// 6.删除某个元素:如果有多个重复元素默认删除前面的第一个!
System.out.println(c.remove("java")); // false
System.out.println(c);
System.out.println(c.remove("Java")); // true
System.out.println(c);
// 7.把集合转换成数组 [HTML, HTML, MySQL, Java, 黑马]
Object[] arrs = c.toArray();
System.out.println("数组:" + Arrays.toString(arrs));
System.out.println("----------------------拓展----------------------");
Collection<String> c1 = new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection<String> c2 = new ArrayList<>();
c2.add("赵敏");
c2.add("殷素素");
// addAll把c2集合的元素全部倒入到c1中去。
c1.addAll(c2);
System.out.println(c1); // [java1, java2, 赵敏, 殷素素]
System.out.println(c2); // [赵敏, 殷素素]
}
}
3.2 Collection三种遍历方式
- 遍历就是一个一个的把容器中的元素访问一遍
3.2.1 迭代器
- 迭代器在Java中的代表是Iterator,迭代器是集合的专用的遍历方式
- 默认指向当前集合的索引’0‘位置
/*
-- 方法:
public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的
boolean hasNext():判断是否有下一个元素,有返回true ,反之。
E next():获取下一个元素值!
--流程:
1.先获取当前集合的迭代器
Iterator<String> it = lists.iterator();
2.定义一个while循环,问一次取一次。
通过it.hasNext()询问是否有下一个元素,有就通过
it.next()取出下一个元素。
*/
ArrayList<String> lists = new ArrayList<>();
lists.add("方");
lists.add("佬");
lists.add("肆");
System.out.println(lists); // [方,佬,肆]
// 1、得到当前集合的迭代器对象。
Iterator<String> it = lists.iterator();
// 2、定义while循环
while (it.hasNext()){
System.out.println(it.next());
}
3.2.2 增强for循环
- 可以遍历集合也可以遍历数组
/*
for(元素数据类型 变量名 : 数组或者Collection集合) {
} //在此处使用变量即可,该变量就是元素
*/
Collection<String> list = new ArrayList<>();
...
for(String ele : list) {
System.out.println(ele);
} // 修改第三方变量(ele)的值不会影响到集合中的元素
3.2.3 Lambda表达式
Collection<String> lists = new ArrayList<>();
...
// 三种lambda表达式
lists.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
ystem.out.println(s);
}
});
list.forEach(s -> {System.out.println(s);});
// 只适用于只有一条java语句的
list.forEach(s -> System.out.println(s) );
4 List集合
- ArrayList、LinekdList :有序,可重复,有索引。
- 有序:存储和取出的元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复:存储的元素可以重复
4.1 ArrayList
- ArrayList底层是基于数组实现的,根据查询元素快,增删相对慢
- 第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组
方法名称 | 说明 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
public int size() | 返回集合中的元素的个数 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
public boolean remove(Object o) | 删除指定的元素,返回删除是否成功 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
ArrayList<String> list = new ArrayList<>(); // 一行经典代码!
...
// 1.在某个索引位置插入元素。
list.add(2, "hello");
// 2.返回集合中元素个数
System.out.println(list.size());
// 3.根据索引删除元素,返回被删除元素
System.out.println(list.remove(1));
// 4.根据索引获取元素:public E get(int index):返回集合中指定位置的元素。
System.out.println(list.get(1));
// 5.修改索引位置处的元素: public E set(int index, E element)
System.out.println(list.set(1, "方佬肆"));
4.2 LinkedList
- LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素是非常快的
方法名称 | 说明 |
---|---|
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
public void push(E e) | 将元素推入此列表所表示的堆栈 |
public E pop() | 从此列表所表示的堆栈处弹出一个元素 |
// LinkedList可以完成队列结构,和栈结构 (双链表)
// 1、做一个队列:
LinkedList<String> queue = new LinkedList<>();
// 入队
queue.addLast("1");
queue.addLast("2");
queue.addLast("3");
System.out.println(queue); // [1,2,3]
// 出队
// System.out.println(queue.getFirst());
System.out.println(queue.removeFirst()); // 1
System.out.println(queue.removeFirst()); // 2
System.out.println(queue); // [3]
// 2、做一个栈
LinkedList<String> stack = new LinkedList<>();
// 入栈 压栈 (push)
stack.push("1");
stack.push("2");
stack.push("3");
stack.push("4");
System.out.println(stack); // [4,3,2,1]
// 出栈 弹栈 pop
System.out.println(stack.pop()); // 4
System.out.println(stack.pop()); // 3
System.out.println(stack.pop()); // 2
System.out.println(stack); // [1]
5 Collections集合工具类(注意:不是Collection)
- java.utils.Collections:是集合工具类
- 作用:Collections并不属于集合,是用来操作集合的工具类
Collections常用API
方法名称 | 说明 |
---|---|
public static boolean addAll(Collection<? super T> c, T… elements) | 给集合对象批量添加元素 |
public static void shuffle(List<?> list) | 打乱List集合元素的顺序 |
List<String> names = new ArrayList<>();
//names.add("楚留香");
//names.add("胡铁花");
//names.add("张无忌");
//names.add("陆小凤");
Collections.addAll(names, "中国","美国", "英国","德国");
System.out.println(names);
// 2、public static void shuffle(List<?> list) :打乱集合顺序。
Collections.shuffle(names);
System.out.println(names);
Collections排序相关API
- 使用范围:只能对于List集合的排序
方法名称 | 说明 |
---|---|
public static void sort(List list) | 将集合中元素按照默认规则排序 |
public static void sort(List list,Comparator<? super T> c) | 将集合中元素按照指定规则排序 |
注意:第一种方式不可以直接对自定义类型的List集合排序,除非自定义类型实现了比较规则Comparable接口
第一种方式排序(只能对基本数据类型)
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 12, 23, 2, 4);
System.out.println(list); // [12, 23, 2, 4]
Collections.sort(list);
System.out.println(list); // [2, 4, 12, 23]
在类定义时实现Comparable接口
public class Apple implements Comparable<Apple>{
private String name;
private String color;
private double price;
private int weight;
...
/**
方式一:类自定义比较规则
o1.compareTo(o2)
* @param o
* @return
*/
@Override
public int compareTo(Apple o) {
// 按照重量进行比较的
return this.weight - o.weight ; // 升序排序;List集存储相同大小的元素 会保留!
}
}
第二种方式排序
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>(); // 可以重复!
apples.add(new Apple("红富士", "红色", 9.9, 500));
apples.add(new Apple("青苹果", "绿色", 15.9, 300));
apples.add(new Apple("绿苹果", "青色", 29.9, 400));
apples.add(new Apple("黄苹果", "黄色", 9.8, 500));
// Collections.sort(apples); // 方法一:可以的,Apple类已经重写了比较规则
// System.out.println(apples);
// 方式二:sort方法自带比较器对象
Collections.sort(apples, new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return Double.compare(o1.getPrice() , o2.getPrice()); // 按照价格排序!!
} // double类型数据比较时用Double.compare(),防止精度损失
});
//Lambda表达式
//Collections.sort(apples, ( o1, o2) -> Double.compare(o1.getPrice() , o2.getPrice()) );
System.out.println(apples);
}
6 泛型
泛型概述
- 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
- 泛型的格式:<数据类型>
- 注意:泛型只能支持引用数据类型
- 集合体系的全部接口和实现类都是支持泛型的使用的
泛型的好处
- 统一数据类型
- 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来
泛型三种定义
- 自定义泛型类
- 自定义泛型方法
- 自定义泛型接口
6.1 自定义泛型类
- 定义类时同时定义了泛型的类就是泛型类
- 泛型类的格式:修饰符 class 类名<泛型变量>{}
public class MyArrayList<T>{}
- 此处泛型变量T可以随便写为任意标识,常见的如E、T、K、V等
- 作用:编译阶段可以指定数据类型,类似于集合的作用
public class MyArrayList<E> {
private ArrayList lists = new ArrayList();
public void add(E e){
lists.add(e);
}
public void remove(E e){
lists.remove(e);
}
@Override
public String toString() {
return lists.toString();
}
}
6.2 自定义泛型方法
- 定义方法时同时定义了泛型的方法就是泛型方法
- 泛型方法的格式:修饰符 <泛型变量> 方法返回值 方法名称(形参列表){}
public <T> void show(T t){}
- 作用:方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性
public static<T> String getString(T[] arr){
StringBuilder sb = new StringBuilder("[");
for(int i = 0; i < arr.length; i++){
sb.append(arr[i]).append( i == arr.length - 1 ? "" : ", " );
}
sb.append("]");
return sb.toString();
}
Integer[] ages = {10, 20, 30};
String s = getString(ages);
System.out.println(s);
6.3 自定义泛型接口
- 使用了泛型定义的接口就是泛型接口
- 泛型接口的格式:修饰符 interface 接口名称<泛型变量>{}
public interface Data<E>{}
- 作用:泛型接口可以让实现类选择当前功能需要操作的数据类型
public interface Data<E> {
void add(E e);
void delete(int id);
void update(E e);
E queryById(int id);
}
// 实现类必须实现接口内的方法(可用 alt + insert 快速插入重写方法)
public class StudentData implements Data<Student>{
@Override
public void add(Student student) {
}
@Override
public void delete(int id) {
}
@Override
public void update(Student student) {
}
@Override
public Student queryById(int id) {
return null;
}
}
6.4 泛型通配符
泛型的上下限
- ? extends Car: ?必须是Car或者其子类 泛型上限
- ? super Car : ?必须是Car或者其父类 泛型下限