单列:Collection
双列: Map 实现类: HashMap, TreeMap…
Collection 是一个接口:Public interface Collection< E >
使用,通过多态的方法:
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("hello");
c.add("world");
System.out.println(c);
// [hello, world]
Collection 集合的常用方法
集合的遍历
Iterator 中的常用方法
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("hello");
c.add("world");
System.out.println(c);
// [hello, world]
Iterator<String> iterator = c.iterator();
// if(iterator.hasNext()) {
// System.out.println(iterator.next()); // hello
// }
//
// if(iterator.hasNext()) {
// System.out.println(iterator.next()); // world
// }
//
// if(iterator.hasNext()) {
// System.out.println(iterator.next()); // 不会执行
// }
// 循环遍历
while (iterator.hasNext()){
String s = iterator.next();
System.out.println(s);
}
}
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("world");
System.out.println(list);
// [hello, world, world]
}
List集合的特有方法
都是通过索引的操作
// 用for循环改进遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
这里注意一个问题:并发修改异常(ConcurrentModificationException)
当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的结果是不确定的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。
来看一个案例:
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
System.out.println(list);
// [hello, world, world]
// 用for循环改进遍历
// for (int i = 0; i < list.size(); i++) {
// System.out.println(list.get(i));
// }
Iterator<String> it = list.iterator();
while (it.hasNext()){
String s = it.next();
if(s.equals("world")){
list.add("javaee");
}
}
}
解决方案
列表迭代器:
ListIterator< E > 是通过List 集合的listIterator() 的方法得到的。允许我们沿任一方向遍历该迭代器。
列表迭代器的常用方法:
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
System.out.println(list);
// 生成列表迭代器
ListIterator<String> lit = list.listIterator();
while(lit.hasNext()){
String s =lit.next();
if(s.equals("world")){
lit.add("javaee");
}
System.out.println(s);
}
System.out.println(list);
简化数组和Collection集合的遍历
我们来看看Collection 的定义:
public interface Collection< E >extends Iterable< E >
它继承了 Iterable< E >
我们接着来看:public interface Iterable< T >
实现这个接口允许对象成为 “foreach” 语句的目标。(增强for 循环)
其内部原理是Iterator的迭代器
注意:容易发生并发修改异常
// 增强 for循环
int[] arr = new int[] {1,2,3};
for (int i:arr) {
System.out.println(i);
}
所以我们目前如果想要遍历一个数组,可以用三种方法:
// LinkedList 的特有功能
LinkedList<String> linklist = new LinkedList<>();
linklist.add("hello");
linklist.add("world");
linklist.add("java");
linklist.addLast("javase");
linklist.addLast("python");
System.out.println(linklist.getFirst());
System.out.println(linklist.getLast());
System.out.println(linklist.removeFirst());
System.out.println(linklist.removeLast());
public interface Set< E >extends Collection< E >
HashSet 实现了该接口,但是并不能保证数据的存储顺序
public class HashSet< E >extends AbstractSet< E >implements Set< E >, Cloneable, Serializable
实现了Set 的结构,此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
哈希值:
哈希值是JDK根据对象的地址或字符串或数字,计算出来的int类型的数值
Object 类有一个 public int hashCode() 的方法或者对象的哈希值
HashSet 集合保证元素唯一性的原因:
哈希表:
是通过数组加链表实现的
案例:利用HashSet 存储对象并遍历:
HashSet<String> hashSet = new HashSet<>();
hashSet.add("hello");
hashSet.add("world");
hashSet.add("java");
for (String s:hashSet
) {
System.out.println(s);
}
对于类对象,我们有时认为对象的成员变量一致时,则对象是重复的,所以我们需要重新写一下hashCode() 和 equals() 的方法,在Idea中,我们可以 Alt + Insert 可以自动生成这两个方法
public class LinkedHashSet< E >extends HashSet< E >implements Set< E >, Cloneable, Serializable
// LinkedHashSet
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("hello");
linkedHashSet.add("world");
linkedHashSet.add("java");
for (String s:linkedHashSet
) {
System.out.println(s);
}
// hello
//world
//java
LinkedHashSet 循环遍历的时候,元素的顺序是可以保证的
public class TreeSet< E >extends AbstractSet< E >implements NavigableSet< E >, Cloneable, Serializable
案例:实现不重复随机数的生产和遍历
public class DetRandom {
// 获取不重复的随机数
// 获取10个1-20
public static void main(String[] args) {
// Set s = new HashSet<>();
Set<Integer> s = new TreeSet<Integer>();
Random r = new Random();
while (s.size()<10){
int random = r.nextInt(20)+1;
s.add(random);
}
for(Integer i: s){
System.out.println(i);
}
}
泛型的定义格式:
类型通配符:
public class GenericDemo {
public static void main(String[] args) {
//类型通配符:>
List<?> list1 = new ArrayList<Object>();
List<?> list2 = new ArrayList<Number>();
List<?> list3 = new ArrayList<Integer>();
System.out.println("--------");
//类型通配符上限: extends 类型> //
List<? extends Number> list4 = new ArrayList<Object>();
List<? extends Number> list5 = new ArrayList<Number>();
List<? extends Number> list6 = new ArrayList<Integer>();
System.out.println("--------");
//类型通配符下限: super 类型>
List<? super Number> list7 = new ArrayList<Object>();
List<? super Number> list8 = new ArrayList<Number>();
// List super Number> list9 = new ArrayList();
}
}
可变参数:
public static int sum(int... a) {
int sum = 0;
for(int i : a) {
sum += i;
}
return sum;
}
可变参数的使用:
map集合的概述
map 集合的特点
public class MapDemo02 {
public static void main(String[] args) {
//创建集合对象
Map<String,String> map = new HashMap<String,String>();
//V put(K key,V value):添加元素
map.put("张无忌","赵敏");
map.put("郭靖","黄蓉");
map.put("杨过","小龙女");
//V remove(Object key):根据键删除键值对元素
// System.out.println(map.remove("郭靖"));
// System.out.println(map.remove("郭襄"));
//void clear():移除所有的键值对元素
// map.clear();
//boolean containsKey(Object key):判断集合是否包含指定的键
// System.out.println(map.containsKey("郭靖"));
// System.out.println(map.containsKey("郭襄"));
//boolean isEmpty():判断集合是否为空
// System.out.println(map.isEmpty());
//int size():集合的长度,也就是集合中键值对的个数
System.out.println(map.size());
//输出集合对象
System.out.println(map);
}
}
public class MapDemo02 {
public static void main(String[] args) {
//创建集合对象
Map<String, String> map = new HashMap<String, String>();
//添加元素
map.put("张无忌", "赵敏");
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
//获取所有键值对对象的集合
Set<Map.Entry<String, String>> entrySet = map.entrySet();
//遍历键值对对象的集合,得到每一个键值对对象
for (Map.Entry<String, String> me : entrySet) {
//根据键值对对象获取键和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "," + value);
}
}
}
方式二:
public class HashMapDemo {
public static void main(String[] args) {
//创建HashMap集合对象
HashMap<String, Student> hm = new HashMap<String, Student>();
//创建学生对象
Student s1 = new Student("林青霞", 30);
Student s2 = new Student("张曼玉", 35);
Student s3 = new Student("王祖贤", 33);
//把学生添加到集合
hm.put("itheima001", s1);
hm.put("itheima002", s2);
hm.put("itheima003", s3);
//方式1:键找值
Set<String> keySet = hm.keySet();
for (String key : keySet) {
Student value = hm.get(key);
System.out.println(key + "," + value.getName() + "," + value.getAge());
}
System.out.println("--------");
//方式2:键值对对象找键和值
Set<Map.Entry<String, Student>> entrySet = hm.entrySet();
for (Map.Entry<String, Student> me : entrySet) {
String key = me.getKey();
Student value = me.getValue();
System.out.println(key + "," + value.getName() + "," + value.getAge());
}
}
}
案例:统计字符串中每个字符出现的次数
案例需求
import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;
/*
需求:
键盘录入一个字符串,要求统计字符串中每个字符串出现的次数。
举例:键盘录入“aababcabcdabcde” 在控制台输出:“a(5)b(4)c(3)d(2)e(1)”
思路:
1:键盘录入一个字符串
2:创建HashMap集合,键是Character,值是Integer
3:遍历字符串,得到每一个字符
4:拿得到的每一个字符作为键到HashMap集合中去找对应的值,看其返回值
如果返回值是null:说明该字符在HashMap集合中不存在,就把该字符作为键,1作为值存储
如果返回值不是null:说明该字符在HashMap集合中存在,把该值加1,然后重新存储该字符和对应的值
5:遍历HashMap集合,得到键和值,按照要求进行拼接
6:输出结果
*/
public class HashMapDemo {
public static void main(String[] args) {
//键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String line = sc.nextLine();
//创建HashMap集合,键是Character,值是Integer
// HashMap hm = new HashMap();
TreeMap<Character, Integer> hm = new TreeMap<Character, Integer>();
//遍历字符串,得到每一个字符
for (int i = 0; i < line.length(); i++) {
char key = line.charAt(i);
//拿得到的每一个字符作为键到HashMap集合中去找对应的值,看其返回值
Integer value = hm.get(key);
if (value == null) {
//如果返回值是null:说明该字符在HashMap集合中不存在,就把该字符作为键,1作为值存储
hm.put(key,1);
} else {
//如果返回值不是null:说明该字符在HashMap集合中存在,把该值加1,然后重新存储该字符和对应的值
value++;
hm.put(key,value);
}
}
//遍历HashMap集合,得到键和值,按照要求进行拼接
StringBuilder sb = new StringBuilder();
Set<Character> keySet = hm.keySet();
for(Character key : keySet) {
Integer value = hm.get(key);
sb.append(key).append("(").append(value).append(")");
}
String result = sb.toString();
//输出结果
System.out.println(result);
}
}
Collections类的作用
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
Collections类的概述
是针对集合操作的工具类
Collections类的常用方法
public static > void sort(List list):将指定的列表按升序排序
public static void reverse(List> list):反转指定列表中元素的顺序
public static void shuffle(List> list):使用默认的随机源随机排列指定的列表
*/
public class CollectionsDemo01 {
public static void main(String[] args) {
//创建集合对象
List<Integer> list = new ArrayList<Integer>();
//添加元素
list.add(30);
list.add(20);
list.add(50);
list.add(10);
list.add(40);
//public static > void sort(List list):将指定的列表按升序排序
// Collections.sort(list);
//public static void reverse(List> list):反转指定列表中元素的顺序
// Collections.reverse(list);
//public static void shuffle(List> list):使用默认的随机源随机排列指定的列表
Collections.shuffle(list);
System.out.println(list);
}
}