目录
集合
认识:集合是Java中存储对象数据的一种容器
特点:
-
集合的大小是不固定的,启动后可以动态变化,类型选取也是不固定 通配符 的使用 的;
-
集合适合做元素的增删操作;
-
集合只能存储 引用类型数据,对于基本数据类型需要包装类
一、Collection
- 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 boolean addAll(Collection<? extends E> c) | 将集合中的元素添加到另一个集合中 |
public class CollectionApiDemo {
public static void main(String[] args) {
//1.HashSet 无序,不重复,无索引
Collection<String> c = new ArrayList<>();
//2.添加
c.add("Java");
c.add("java");
c.add("false");
c.add("true");
//3.集合可以直接输出
System.out.println(c);
//4.清空元素
// c.clear();
// System.out.println(c);
//5.从集合中删除
c.remove("java");
System.out.println(c);
System.out.println(c.remove("ss"));
System.out.println("-------------");
//6.判断是否含有给定对象 contains
System.out.println(c.contains("Java"));
//7.isEmpty
System.out.println(c.isEmpty());
//8.size 大小
System.out.println(c.size());
//9.toArray() 转变为Object 类型 数组
Object[] arr = c.toArray();
System.out.println(Arrays.toString(arr));
//10.addAll() 将集合添加到另一个集合中!!!
Collection<String> c1 = new HashSet<>();
c1.add("156");
c1.add("123");
c.addAll(c1);
System.out.println(c);
}
}
1.1Collection 迭代
- 1迭代器Iterator
- 遍历: 一个一个 把容器中的元素访问一遍;
- 迭代器在Java中 的代表Iterator , 迭代器是集合的专门遍历方式
- 第一步要先获取迭代器,Iterator iterator = 集合对象.iterator(); // 迭代器对象默认指向当前集合的0索引
- 第二步: 通过以下方法遍历
- boolean hasNext() ; 询问当前位置是否有元素存在,存在返回true , 否则false;
- E next() ; 获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止越界
//使用迭代器 Iterator
Collection<String> c1 = new ArrayList<>();
c1.add("fa");
c1.add("fifa");
c1.add("monkey");
//获取迭代器
Iterator iterator = c1.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
-
2加强for
-
可以遍历集合与数组
-
格式:
-
for (元素数据类型 变量名 : 数组/Collection集合){ //在此处使用 变量即可; }
-
-
Collection<String> c1 = new ArrayList<>();
c1.add("fa");
c1.add("fifa");
c1.add("monkey");
//加强for
for(String s : c1){
System.out.println(s);
}
-
3forEach
-
Collection结合Lambda表达式,提供更便捷的遍历集合的方式
-
default void forEach(Consumer<? super T> action): 结合Lambda遍历集合
-
Collection<String> collection = new ArrayList<>();
collection.add("fa");
collection.add("fifa");
collection.add("hhh");
collection.add("xhh");
collection.forEach(new Consumer<String>() { //Consumer 一个函数式接口
@Override
public void accept(String s) {
System.out.println(s);
}
});
//Lambda表达式化简
collection.forEach(s->{System.out.println(s);});
//最终
collection.forEach(System.out::println); //优雅
1.2List
- List的实现类 ArrayList 和 LinkedList 有序,可重复,有索引
- List的实现类的底层原理
- ArrayList底层是基于 数组 实现的,查询元素快,增删速度慢;
- LinkedList底层是基于 双链表实现的,查询速度慢,增删收尾元素块;
public class ListDemo {
public static void main(String[] args) {
//1.创建List对象
List<String> list = new ArrayList<>();
//2.添加元素
list.add("Java");
list.add("HTML");
list.add("java");
list.add("CS");
System.out.println(list);
//指定索引,添加元素
list.add(2,"JavaStrip");
System.out.println(list);
System.out.println("----------------------------");
//3.删除元素 , 返回被删元素
System.out.println(list.remove(2));
System.out.println(list);
System.out.println("---------------------------");
//4.修改索引处元素,返回被修改的元素
System.out.println(list.set(2, "JavaStrip"));
System.out.println(list);
//5.返回指定索引处元素
System.out.println(list.get(3));
}
}
1.2.1ArrayList
-
初始容量为10,满的时候,按照1.5倍扩容迁移。 size指向索引
-
虽然存储的是地址,但是输出时为地址指向元素值
-
注意: 使用 remove后, size会立即变小 , 需要再次检测当前位置
1.2.2LinkedList
首尾操作:可以实现 栈和队列
public class LinkedListDemo2 {
public static void main(String[] args) {
//1.栈 后进先出
LinkedList<String> list = new LinkedList<>();
// list.addFirst("java");
// list.addFirst("Java");
list.push("java"); //push 优雅!!!
list.push("Java");
list.push("HTML");
while (list.size()>0){
System.out.println(list.pop()); //pop 优雅!!!
}
System.out.println("---------------------");
//2.队列 先进先出
LinkedList<String> list1 = new LinkedList<>();
list1.addLast("java");
list1.addLast("Java");
list1.addLast("HTML");
while (list1.size()>0){
System.out.println(list1.removeFirst());
}
}
}
1.3Set
- 无序:存储 与 取出顺序不一致, 每次取出顺序 很有可能不一致
- 不重复:可以自动除去重复;
- 无索引:没有带索引的方法,所以不能使用普通for 循环遍历, 也不能通过索引获取元素;
Set集合实现类特点:
- HashSet : 无序、不重复、无索引;
- LinkedHashSet:有序、不重复、无索引; 特殊:有序
- TreeSet:排序、不重复、无索引; 特殊:排序(升序)
api 参考 Collection
1.3.1HashSet
底层原理:哈希表(散列表) 无序、无索引
-
哈希值
- 哈希值是 JDK 根据对象的地址,按照某种规则算出来的int类型的数值
-
Object 的 Api
- public int hashCode() : 返回对象的哈希值
-
对象的哈希值特点
- 同一个对象 多次调用hashCode()方法返回的哈希值是相同的
- 默认情况下,不同对象的哈希值是不同的
不重复
- 右键generate ,点击 equals 和 hashCode 重写(如下) ;
- 使用官方的方法 , 实体类所有内容完全一致也可以去重;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return id == student.id && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
1.3.2LinkedHashSet
1.3.3TreeSet
底层原理: 红黑树 排序(升序),不重复,无索引
排序规则:
-
基本类型:大小比较;字符串:从首位置开始匹配 通过ASCII
-
接口Comparable< E > , 实现compareTo(类 o) {return 1/-1/0}; 依据成员变量大小,自动排序类对象
-
函数式接口 Comparator< E >
-
Set<Apple> set4 = new TreeSet<>(new Comparator<Apple>() { @Override public int compare(Apple o1, Apple o2) { return 0; } });
-
public class TreeSetDemo {
public static void main(String[] args) {
//1.基本数据类型
Set<Integer> set1 = new TreeSet<>(); //默认升序 , 比大小
set1.add(123);
set1.add(12);
set1.add(1);
System.out.println(set1);
//2.字符串
Set<String> set2 = new TreeSet<>(); //默认升序 , 比 首字符 ASCII
set2.add("java");
set2.add("Java");
set2.add("你好");
System.out.println(set2);
//3.自定义 价格降序
Set<Apple> set4 = new TreeSet<>(new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return 0;
}
});
// lambda表达式
Set<Apple> set3 = new TreeSet<>((o1, o2) -> Double.compare(o2.getPrice() , o1.getPrice()));
set3.add(new Apple("红苹果","红色",12.5,500));
set3.add(new Apple("青苹果","青色",10.5,900));
set3.add(new Apple("绿苹果","绿色",15.5,700));
set3.add(new Apple("蓝苹果","蓝色",8.5,500));
//注意 ; 就近原则
System.out.println(set3);
}
}
//省略 setXxx() / getXxx()方法
public class Apple implements Comparable<Apple> {
private String name;
private String color;
private double price;
private int weight;
public Apple(){
}
public Apple(String name, String color, double price, int weight) {
this.name = name;
this.color = color;
this.price = price;
this.weight = weight;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Apple apple = (Apple) o;
return Double.compare(apple.price, price) == 0 && weight == apple.weight && Objects.equals(name, apple.name) && Objects.equals(color, apple.color);
}
@Override
public int hashCode() {
return Objects.hash(name, color, price, weight);
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", price=" + price +
", weight=" + weight +
'}';
}
/**
* 按照重量 升序
* @param o 对象
* @return 1/-1/0
*/
@Override
public int compareTo(Apple o) {
return this.getWeight() - o.getWeight() ; //set 不可重复
// return this.getWeight() - o.getWeight() >= 0 ? 1 : -1;
}
}
二、Map
认识和使用
- Map集合是一种 双列集合,每个元素包含两个数据;
- Map集合的每个元素的格式:Key = value(键值对);
- Map集合也称为 “键值对”集合
格式对比:
- Collection [元素1,元素2,…]
- Map {key1 = value , key2 = value2,key3 = value}
Map特点:
- Map的特点取决于 键
- Map的键是 无序的、不重复的、无索引的,值不做要求的(可重复)
- Map集合后面重复的键对应的值 会覆盖前面的值
- Map集合的键值对 都可以为null
Map集合实现类的特点:
- HashMap: 元素按照键 是 无序、不重复、无索引,值不做要求; 键(HashSet)
- LinkedHashMap:元素按照键是 有序、不重复、无索引,值不做要求; 键(LinkedHashSet)
- TreeMap:元素按照键是 排序、不重复、无索引的,值不做要求; 键(TreeSet)
Map常用Api
方法 | 描述 |
---|---|
Map<K,V> map = new HashMap<>(); | 创建一个Map<K,V>对象 |
put(K,V) | 添加元素 |
clear() | 清空元素 |
boolean isEmpty() | 判空 |
public V get (Object key) | 获取指定键对应的值 |
V remove(Object key) | 删除整个元素 |
boolean containsKey(Object key) | 是否包含指定键 |
boolean containsValue(Object V) | 是否包含指定的值 |
public Set< K > keySet() | 获取全部键的集合 |
public Collection< V > values() | 获取全部值的集合 |
size() | 集合的大小 |
putAll() | 合并其他Map集合 |
public static void main(String[] args) {
//1.创建一个Map<K,V> 对象
Map<String,Integer> map = new HashMap<>();
//添加元素 .put()
map.put("鸿星尔克",3);
map.put("红牛",3);
map.put("枸杞",3);
map.put("鸿星尔克",5); //后 覆盖 前面
map.put(null,null);
System.out.println(map);
//2.清空元素
// map.clear();
// System.out.println(map);
//3.判空
System.out.println(map.isEmpty()); //false
//4.获取键对应的值:public V get (Object key)
System.out.println(map.get("枸杞")); //3
System.out.println(map.get("枸杞1")); //null
System.out.println("-----------");
//5.删除整个元素 V remove(Object key)
System.out.println(map.remove("枸杞")); //3
System.out.println(map.remove("枸杞1"));//null
System.out.println(map);
//6.包含指定键
map.put("枸杞",3);
System.out.println(map.containsKey("枸杞")); //true
System.out.println(map.containsKey(null)); //true
System.out.println(map.containsKey("拉菲")); //false
//7.包含指定的值
System.out.println(map.containsValue(5)); //true
System.out.println(map.containsValue(3)); //true
System.out.println(map.containsValue(null)); //true
//8.获取全部键 的 集合 public Set<K> keySet()
Set<String> set = map.keySet();
System.out.println(set);
//9.获取全部值 的 集合 public Collection<V> values()
Collection<Integer> list = map.values();
System.out.println(list);
//10.集合的大小
System.out.println(map.size());
//11.合并其他Map集合(拓展) .putAll
Map<String,Integer> map1 = new HashMap<>();
map1.put("雀巢",12);
map1.put("槟榔",13);
map1.put("枸杞",100); //覆盖!!!
System.out.println(map);
map.putAll(map1);
System.out.println(map);
}
-
遍历
-
1键找值
- 先获取Map集合的所有key的 Set集合 Set< K > keySet()
- 遍历键的Set集合,然后通过键 提取对应值 V get(Object key)
-
2键值对
-
先把Map集合 转换为 存储键值对 实体类型的 Set集合 Set<Map.Entry<K,V>> entrySet()
-
加强for 遍历Set ,然后提取键,提取值 K getKey() V getValue
public class MapPrintDemo2 { public static void main(String[] args) { Map<String,Integer> m1 = new HashMap<>(); m1.put("联想",1); m1.put("鸿星尔克",5); m1.put("耐克",0); m1.put("雀巢",3); System.out.println(m1); //无法确定 直接类型 来利用forEach //Set存储键值对对象 , map.entrySet() Set<Map.Entry<String, Integer>> entries = m1.entrySet(); for (Map.Entry<String, Integer> entry : entries) { //1.Entry接口泛型 存储 键值对 , 然后利用getKey , getValue System.out.println(entry.getKey() +"===>"+ entry.getValue()); } } }
-
-
3Lambda
-
default void forEach(BiConsumer<? super K , ? super V> action) 结合lambda遍历Map集合
-
map.forEach(new BiConsumer<String, Integer>() { @Override public void accept(String k, Integer v) { System.out.println(k + "===>" + v); } }); map.forEach(( k, v) -> System.out.println(k + "===>" + v));
-
-
2.1HashMap
特点:
- 常用
- HashMap 是 Map里面的一个实现类;特点由键决定:无序、不重复、无索引
- 没有额外需要学习的特有方法,直接使用Map里面的方法就可以了;
- HashMap 跟 HashSet底层原理 是 一致的,都是哈希表结构;只是HashMap的每个元素包含两个值
实际,Set系列集合的底层就是Map实现的,只是Set集合中的元素只要键数据,不要值数据
- 不重复 依赖 equals 与 hashCode , 自定义类 需要重写
2.2LinkedHashMap
- 由键决定: 有序、不重复、无索引
- 原理:底层数据结构 依然是哈希表,只是每个键值对元素 又额外多一个双链表的机制记录存储的顺序。
2.3TreeMap
- 由键决定:可排序、不重复、无索引
- 可排序:按照键数据的大小 ,默认升序; 只对键排序;也可以自定义规则(与TreeSet一致)
- TreeMap跟 TreeSet的底层原理是一样的
三、工具类
3.1Collections
-
java.util.Collections是集合工具类;
-
Collections是操作集合的工具类,不属于集合;
-
常用Api
方法名称 | 描述 |
---|---|
public static < T > boolean addAll(Collection < ? super T> c , element1, element2,…) | 给集合c对象批量添加元素 |
public static void shuffle(list<?> list) | 打乱list集合元素的顺序 |
List<String> list = new ArrayList<>();
//1.addAll(list , element1,element2,...)
Collections.addAll(list,"faf","fifa","fei");
System.out.println(list);
//2.public static void shuffle(List<?> list) //打乱list顺序 , 随机数 , 每次都不一样
Collections.shuffle(list);
System.out.println(list);
- 排序
- public static < T > void sort (list< T > list) 将集合元素按照默认规则排序(升序)
- public static < T > void sort(list< T >list ,Comparator<? super T> c) 自定义规则排序
List<Integer> integerList = new ArrayList<>();
Collections.addAll(integerList,12,35,0,13);
Collections.sort(integerList); //升序
System.out.println(integerList);
Collections.sort(list1, new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return Double.compare(o2.getPrice(),o1.getPrice());//价格降序
}
});
//lambda表达式
Collections.sort(list1, (o1,o2) -> Double.compare(o2.getPrice(),o1.getPrice()));
四、认识
4.1可变参数
- 用在形参中,可以接收多个数据 , 可变参数只能放在形参列表的后面
- 格式:数据类型 … 参数名
- 本质:一个数组
public class ParamsDemo {
public static void main(String[] args) {
sum(12,23,43);
sum(2);
add(56,23,5,2,3);
}
/**
* 形参里面只能有一个可变参数,可变参数只能放在形参列表的后面
* @param arr 可变参数
*/
public static void sum(int...arr){
int number = 0;
for (int i = 0; i < arr.length; i++) {
number += arr[i];
}
System.out.println(number);
}
public static void add(int age , int...arr){
System.out.println(age);
System.out.println(Arrays.toString(arr));
}
}
4.2不可变集合
JDK 11
List<String> list = List.of("张三", "李四", "王五", "赵六");
Set<String> set = Set.of("张三","李四","王麻子","赵六");
Map<String, String> map = Map.of("张三", "南京", "李四", "北京", "王五", "上海",
"赵六", "广州"); // "张三" => "南京"
4.3泛型实例(补充)
1.自定义泛型方法
public class MethodDemo1 {
public static void main(String[] args) {
String[] arr1 = {"java","Java","HTML"};
printArray(arr1);
Integer[] arr2 = {1,2,4,5,6}; //引用类型 <T>
printArray(arr2);
printArray(null);
String[] arr = send(arr1);
printArray(arr);
}
public static <T> T[] send(T[] arr){
return arr;
}
//打印形如[1,2,3,4]
public static <T> void printArray(T[] arr){// 限定 传输的数据类型
if(arr != null){
StringBuilder stringBuilder = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
stringBuilder.append(arr[i]).append(i==arr.length-1?"":", ");
}
stringBuilder.append("]");
System.out.println(stringBuilder);
}else {
System.out.println(arr);
}
}
}
2.通配符
public class LimitDemo {
public static void main(String[] args) {
ArrayList<BWM> arrayList1 = new ArrayList<>();
arrayList1.add(new BWM());
ArrayList<BEN> arrayList2 = new ArrayList<>();
arrayList2.add(new BEN());
go(arrayList1);
go(arrayList2);
// ArrayList<Dog> dogs = new ArrayList<>();
// go(dogs); 应该为Car本身与子类
}
/**
* 赛车比赛
* @param arrayList 各类汽车集合
*/
public static void go(ArrayList<? extends Car> arrayList){ //读入,做参数 (上界通配符),不能读入
System.out.println(arrayList.size());
}
}
class Dog{
}
class BEN extends Car{
}
class BWM extends Car{
}
class Car{
}
参考:
[Java不可变集合(超详解)_java不可变集合原理-CSDN博客](不可变集合)