1. Collection接口
①引入集合
- 集合和数组都是容器
- 集合:长度可变,存储对象且对象的类型可以不同
- 数组:长度固定,存储对象或基本数据类型但都是同类型元素
//存放person类对象,一旦创建,运行期间长度不可以发生改变
Person[] array = new Person[3];
....
②Collection接口公共方法
- Collection是单列集合中的最顶层的接口,接口中的方法可以被所有单列集合使用
public boolean add(E e)
public void clear()
public boolean remove(E e)
public boolean contains(E e)
public boolean isEmpty()
public int size()
public Object[] toArray() //集合元素——>数组
Collection<String> coll = new ArrayList<>();
System.out.println(coll);// []
Collections.addAll(coll,"林俊杰","周杰伦","孙燕姿","五月天","泽野弘之")
System.out.println(coll); //[林俊杰, 周杰伦, 孙燕姿, 五月天, 泽野弘之, 夏目贵志]
coll.remove("泽野弘之");//true
coll.contains("孙燕姿");//true
coll.isEmpty();//false
coll.size());//5
coll.clear();//清空集合元素,只保留集合本身 []
//public Object[] toArray(): 把集合中的元素,存储到数组中。
Object[] arr = coll.toArray();
③Collections接口工具类方法
public static <T> boolean addAll(Collection<T> c, T... lements)
public static void shuffle(List<?> list)
//静态方法,可以用接口直接调用
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a","b","c","d","e");
//[a, b, c, d, e]
Collections.shuffle(list);
//[b, d, c, a, e]
④Comparable接口 Integer+ Person
public static <T> void sort(List<T> list) //按默认规则排序
public interface Comparable<T> { public int compareTo(T o); }
Integer
1.Integer类实现该接口并重写了接口中的抽象方法compareTo
public final class Integer implements Comparable<Integer>
public int compareTo(Integer anotherInteger) { ... }
ArrayList<Integer> list01 = new ArrayList<>();
Collections.addAll(list01,1,3,2); //[1, 3, 2]
Collections.sort(list01);//默认是升序 [1, 2, 3]
ArrayList<String> list02 = new ArrayList<>();
Collections.addAll(list02,"a","c","b");//[a, c, b]
Collections.sort(list02);//默认是升序[a, b, c]
Person
- 分析:Person类必须要实现Comparable接口并重写compareTo方法才能排序
ArrayList<Person> list03 = new ArrayList<>();
list03.add(new Person("张三",18));
list03.add(new Person("李四",20));
list03.add(new Person("王五",15));
//重写前:按输入顺序输出
[Person{name='张三', age=18}, Person{name='李四', age=20}, Person{name='王五', age=15}]
//重写后:按年龄升序顺序输出
Collections.sort(list03);
[Person{name='王五', age=15}, Person{name='张三', age=18}, Person{name='李四', age=20}]
public class Person implements Comparable<Person>{
...
@Override
public int compareTo(Person o) {
//自定义规则,比较年龄(this,参数Person)
return this.getAge() - o.getAge();//年龄升序排序
}
}
⑤Comparator接口 Intege+ Student
public static <T> void sort(List<T> list,Comparator<? super T>) //自定义规则排序。
public interface Comparator<T> {//抽象接口
int compare(T o1, T o2);
boolean equals(Object obj);
}
Integer
ArrayList<Integer> list01 = new ArrayList<>();
Collections.addAll(list01,1,3,2); //[1, 3, 2]
Comparator<Integer> com = new Comparator<Integer>() {
@Override //重写比较的规则
public int compare(Integer o1, Integer o2) {
return o1-o2;//升序
}
}
Collections.sort(list01,com);
System.out.println(list01);//[1, 2, 3]
Student
public class Student{
...
@Override
toString
}
ArrayList<Student> list02 = new ArrayList<>();
list02.add(new Student("a迪丽热巴",18));
list02.add(new Student("古力娜扎",20));
list02.add(new Student("杨幂",17));
list02.add(new Student("b杨幂",18));
//按输入顺序,输出
//仅年龄比较
Comparator<Student> com = new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年龄升序排序
return o1.getAge()-o2.getAge();
}
}
Collections.sort(list02,com);
//带姓名一起
Collections.sort(list02, new Comparator<Student>() {?
@Override
public int compare(Student o1, Student o2) {
//按照年龄升序排序
int result = o1.getAge()-o2.getAge();
//如果两个人年龄相同,再按首字母升序
if(result==0){ result = o1.getName().charAt(0)-o2.getName().charAt(0);}
return result;
}
});
//[Student{name='杨幂', age=17}, Student{name='a迪丽热巴', age=18}, Student{name='b杨幂', age=18}, Student{name='古力娜扎', age=20}]
}
⑥Iterator接口
- Iterable接口定义了接口Iterator
- Collection接口继承了接口Iterable
public interface Iterable<T> {
Iterator<T> iterator();
}
public interface Collection<E> extends Iterable<E>{
Iterator<E> iterator(); //返回迭代器实现类对象
}
/*
1.使用Iterator接口接收Collection中方法iterator()返回的实现类对象
2.使用Iterator接口中的方法hasNext判断下一个(-1)
3.使用Iterator接口中的方法next取出下一个
*/
Collection<String> coll = new ArrayList<>();
Collections.addAll(coll,"姚明","科比","麦迪","詹姆斯","艾弗森");
Iterator<String> it = coll.iterator();//多态
while(it.hasNext()){
String e = it.next();
System.out.println(e);
}
String s = it.next();//空集合,取元素就抛出NoSuchElementException
}
}
- Iterator接口原理
⑦增强for
- foreach遍历集合和数组:底层使用迭代器
Collection<E>extends Iterable<E>:
public interface Iterable<T>谁实现该接口,谁就能使用 "foreach"
for(集合/数组的数据类型 变量名: 集合名/数组名)
sout(变量名);
int[] arr = {1,2,3,4,5};
for(int i:arr)
System.out.println(i);
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"aaa","bbb","ccc","ddd");
for(String s : list)
System.out.println(s);
1.1 List接口
public interface List< E > extends Collection< E >
①List接口特点
- 有序,存取一致
- 有索引,包含索引方法
- 允许重复
②List接口中带索引的方法
- public void add(int index, E element)
- public E get(int index)
- public E remove(int index)
- public E set(int index, E element)
注意:
操作索引的时候,要防止索引越界异常
IndexOutOfBoundsException:集合索引越界异常
ArrayIndexOutOfBoundsException:数组索引越界异常
StringIndexOutOfBoundsException:字符串索引越界异常
③List接口的3种遍历方法
for (String s : list)
System.out.println(s);
Iterator<String> it = list.iterator();//获取迭代器对象
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
for(int i=0; i<list.size(); i++){
String s = list.get(i);
System.out.println(s);
}
④List接口实现类ArrayList-多线程
public class ArrayList< E > implements List< E >
分析:
- ArrayList底层是由数组实现,所以适合查询、遍历,不适合增删。因而
- ArrayList包含大量的索引方法!
ArrayList<String> list = new ArrayList<>();
System.out.println(list); //[] 直接打印得到的不是地址,而是内容
Collections.addAll(list,"赵丽颖","迪丽热巴","古力娜扎","玛尔扎哈");
String name = list.get(2);//古力娜扎
String whoRemoved = list.remove(1);//迪丽热巴
ArrayList<Integer> listC = new ArrayList<>();
//ArrayList<int> listB = new ArrayList<>();错误,只能写引用类型
⑤List接口实现类LinkedList-多线程
public class LinkedList< E > implements List< E >
分析:
- LinkedList底层是由链表实现,所以适合添加、删除,不适合查询。因而LinkedList包含大量的操作头尾的方法!
注意:LinkedList集合特有的方法!!!【多态无法使用子类特有的方法】
- public void addFirst(E e):将指定元素插入此列表的开头。
- public void addLast(E e):将指定元素添加到此列表的结尾。
- public void push(E e):将元素推入此列表所表示的堆栈。
- public E getFirst():返回此列表的第一个元素。
- public E getLast():返回此列表的最后一个元素。
- public E removeFirst():移除并返回此列表的第一个元素。
- public E removeLast():移除并返回此列表的最后一个元素。
- public E pop():从此列表所表示的堆栈处弹出一个元素。
- public boolean isEmpty():如果列表不包含元素,则返回true。
LinkedList<String> linked = new LinkedList<>();
linked.add("a");
⑥List接口实现类Vector-单线程
public class Vector< E > implements List< E >
1.2 Set接口
①Set接口特点
- 不允许重复
- 无索引
②HashSet集合特点和哈希值
public class HashSet< E > implements Set< E >
- 无序,存取不一致
- 底层是哈希表结构查询非常快
哈希值:
- 一个十进制的整数,由系统随机给出的对象地址值,它是一个逻辑地址,模拟的地址,而不是真的物理地址
**哈希值的获取方法:
1.直接打印p 16进制
2.打印p.toString 16进制
3. Object类的方法——int hashCode() 返回对象的哈希值 10进制
public native int hashCode();
native:代表该方法调用的是本地操作系统的方法
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
Person类演示哈希值:
//如果重写hashCode(),对象地址就会返回1了
public class Person extends Object{
@Override
public int hashCode() { return 1; }
}
Person p1 = new Person();
int h1 = p1.hashCode(); //Person天然继承Object
System.out.println(p1);//com.itheima.demo03.hashCode.Person@7ef20235
System.out.println(p1.toString());//com.itheima.demo03.hashCode.Person@7ef20235
System.out.println(h1);//2129789493 | 1
Person p2 = new Person();
int h2 = p2.hashCode();
System.out.println(p2);//com.itheima.demo03.hashCode.Person@27d6c5e0
System.out.println(p2.toString());//com.itheima.demo03.hashCode.Person@27d6c5e0
System.out.println(h2);//668386784 | 1
System.out.println(p1==p2);
//重写hashCode(),即使地址都是1,但真正的物理地址不同,也返回false
String类演示哈希值:
//String类的哈希值——String类重写了Obejct类的hashCode方法
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.hashCode());//96354
System.out.println(s2.hashCode());//96354
System.out.println("重地".hashCode());//1179395
System.out.println("通话".hashCode());//1179395
}
}
③HashSet存储数据类型 Integer+Person
Integer
Set<Integer> set = new HashSet<>();
Collections.addAll(set,3,2,1);
for (Integer i : set)
System.out.println(i);
Iterator<Integer> it = set.iterator();
while (it.hasNext())
Integer n = it.next();
System.out.println(n);//1,2,3存取不一致
Person:需重写对象的hashCode和equals,保证HashSet集合唯一性
**要求:同名同年龄的人,视为同一个人,只能存储一次
HashSet<Person> set = new HashSet<>();
Person p1 = new Person("小美女",18);
Person p2 = new Person("小美女",18);
Person p3 = new Person("小美女",19);
System.out.println(p1.hashCode());//1967205423 | 734175839
System.out.println(p2.hashCode());//42121758 | 734175839
System.out.println(p1==p2);//false | 比较的地址依然是 false
System.out.println(p1.equals(p2));//false | true
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);
//重写前:p1 p2 p3均会输出,p1 p2哈希值不同 equals也不同,视为2个对象
//重写后:p2不会输出,p1 p2哈希值同 equals同,视为1个对象
hashCode存储自定义元素必须重写的2个方法!!!
public class Person {
...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() { return Objects.hash(name, age); }
}
④LinkedHashSet集合特点
public class LinkedHashSet< E > extends HashSet< E > implements Set< E >
- 底层是由一个哈希表(数组+链表/红黑树)+链表实现:多的链表用于维护顺序
HashSet<String> set = new HashSet<>();
Collections.addAll(set,"www","abc","abc","itcast");
System.out.println(set);//[abc, www, itcast] 无序,不允许重复
LinkedHashSet<String> linked = new LinkedHashSet<>();
Collections.addAll(linked,"www","abc","abc","itcast");
System.out.println(linked);//[www, abc, itcast] 有序,不允许重复
⑤Set集合元素不允许的原因
- 存储时会调用hashCode和equals方法,判断哈希值和内容是否相同
2.Map接口
①Map接口的特点
1.双列集合
2.key不可重复 value可重复
②Map接口常用方法
1.public V put(K key, V value):
return:V key不重复,返回null
key重复,返回被替换的value
2.public V remove(Object key):
return:V key不存在,返回null
key存在,返回被删除的value
3.public V get(Object key)
return:
key不存在,返回null
key存在,返回对应的value值
4.boolean containsKey(Object key)
Map<String,String> map = new HashMap<>();
map.put("李晨", "范冰冰1");//v1:null
map.put("李晨", "范冰冰2");//v2:范冰冰1
//此时集合中{李晨=范冰冰2}
map.put("冷锋","龙小云");
map.put("杨过","小龙女");
map.put("尹志平","小龙女");
//此时集合中{杨过=小龙女, 尹志平=小龙女, 李晨=范冰冰2, 冷锋=龙小云}
String v1 = map.remove("李晨");//v1:范冰冰2
String v2 = map.remove("林俊杰");//v2:null
String v3 = map.get("杨过");//v3:小龙女
String v4 = map.get("迪丽热巴");//v4:null
boolean b1 = map.containsKey("杨过");//b1:true
boolean b2 = map.containsKey("赵颖");//b2:false
注意
:
int V = map.remove("1");
- 自动拆箱,返回的Value赋值给V ,v是数字的时候可以,v是null则报NullPointerException
③Map接口遍历方法—键找值
键找值:需要借助2个Map接口中的方法
public Set< K > keySet() //返回map中所有的key到一个set集合中
public V get(Object key) //返回对应的value
//创建Map集合对象,准备使用map中的方法
Map<String,Integer> map = new HashMap<>();
map.put("赵丽颖",168);
map.put("杨颖",165);
map.put("林志玲",178);
//1.使用keySet(),提取所有的key,一下子存到set集合中
Set<String> set = map.keySet();
//2.遍历set集合,一步步得到其中所有key
for(String key : set){ //set也可以直接写成 map.keySet()
//3.使用get(key),找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
//2.遍历set集合,一步步得到其中所有key
Iterator<String> it = set.iterator();
while (it.hasNext()){
String key = it.next();
//3.使用get(key),找到value
Integer value = map.get(key);
System.out.println(key+"="+value);
}
林志玲=178
赵丽颖=168
杨颖=165
④Map接口遍历方法—Entry
Entry:需要借助2个Map接口中的方法
public Set<Map.Entry<K,V>> entrySet()
//Map声明的一个内部接口,返回map中所有的键值对对象到一个set集合中
public interface Map<K, V>{
interface Entry<K, V> { //Entry将键值对的对应关系封装成了对象
K getKey();//获取Entry对象中的键。
V getValue();//获取Entry对象中的值。
}
}
//创建Map集合对象,准备使用map中的方法
Map<String,Integer> map = new HashMap<>();
map.put("赵丽颖",168);
map.put("杨颖",165);
map.put("林志玲",178);
// 1.使用entrySet(),提取所有的Entry对象,一下子存到set集合中
Set<Map.Entry<String, Integer>> set = map.entrySet();
// 2.遍历set集合,一步步得到其中所有Entry对象
Iterator<Map.Entry<String, Integer>> it = set.iterator();
while(it.hasNext()){
Map.Entry<String, Integer> entry = it.next();
//3.使用Entry对象中的方法getKey()和getValue()获取键与值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
for(Map.Entry<String,Integer> entry:set){
//3.使用Entry对象中的方法getKey()和getValue()获取键与值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
林志玲=178
赵丽颖=168
杨颖=165
2.1 HashMap
①HashMap集合特点
public class HashMap<K,V> implements Map<K,V>
- HashMap底层由哈希表实现:数组+单向链表或红黑树(链表的长度超过8): (哈希表结构查询都非常快)
- hashMap无序集合 多线程
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
②HashMap存储自定义键值类型
<String,Person>分析:
- key:String类型,系统重写String类hashCode方法和equals方法,保证了key唯一性
- value:Person类型 value可以重复
HashMap<String,Person> map = new HashMap<>();
map.put("北京",new Person("张三",18));
map.put("上海",new Person("李四",19));
map.put("广州",new Person("王五",20));
map.put("北京",new Person("赵六",18));
//字符串重写了hashCode和equals方法,所以张三key北京重复被替换了
Set<String> set = map.keySet();
for (String key : set) {
Person value = map.get(key);
System.out.println(key+"-->"+value);
}
上海-->Person{name='李四', age=19}
广州-->Person{name='王五', age=20}
北京-->Person{name='赵六', age=18}
<Person,String>分析:
- key:Person类型,Person类必须重写hashCode方法和equals方法,来保证key唯一性
- value:String类型 value可以重复
HashMap<Person,String> map = new HashMap<>();
map.put(new Person("女王",18),"英国");
map.put(new Person("秦始皇",18),"秦国");
map.put(new Person("普京",30),"俄罗斯");
map.put(new Person("女王",18),"毛里求斯");
Set<Map.Entry<Person, String>> set = map.entrySet();
for (Map.Entry<Person, String> entry : set) {
Person key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"-->"+value);
}
public class Person {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
Person{name='女王', age=18}-->毛里求斯
Person{name='秦始皇', age=18}-->秦国
Person{name='普京', age=30}-->俄罗斯
③LinkedHashMap集合特点
- 哈希表+链表 有序
public class LinkedHashMap<K,V> extends HashMap<K,V>
HashMap<String,String> map = new HashMap<>();
map.put("a","a");
map.put("c","c");
map.put("b","b");
map.put("a","d");
System.out.println(map);// key不允许重复,无序 {a=d, b=b, c=c}
LinkedHashMap<String,String> linked = new LinkedHashMap<>();
linked.put("a","a");
linked.put("c","c");
linked.put("b","b");
linked.put("a","d");
System.out.println(linked);// key不允许重复,有序 {a=d, c=c, b=b}
④Hashtable与HashMap
public class Hashtable<K,V> implements Map<K,V>
HashMap<String,String> map = new HashMap<>();
map.put(null,"a");
map.put("b",null);
map.put(null,null);
System.out.println(map);//{null=null, b=null}
//Hashtable不能和null扯上关系
Hashtable<String,String> table = new Hashtable<>();
table.put(null,"a");//NullPointerException
table.put("b",null);//NullPointerException
table.put(null,null);//NullPointerException
⑤Hashtable子类Properties
参见IO流
⑥of方法一次性添加
三者都是实现了of
- static < E > List< E > of( ){E… elements}
- static < E > Set< E > of(){E… elements}
- static <K, V> Map<K, V> of( ){E… elements}
List<String> list = List.of("a", "b", "a", "c", "d");
System.out.println(list);//[a, b, a, c, d]
1.'of返回一个不能变的集合,集合不能再使用add,put方法添加元素,会抛出异常'
list.add("w");//UnsupportedOperationException:不支持操作异常
2.'Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常'
Set<String> set = Set.of("a", "b", "a", "c", "d");//IllegalArgumentException:非法参数异常,有重复的元素
Set<String> set = Set.of("a", "b", "c", "d");
System.out.println(set);
3.'of仅适用于List Set Map 本身,不适用于接口的实现类'
ArrayList<String> list1 = ArrayList.of("a", "b", "a", "c", "d");