1.概述
为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,Java就提供了集合类。
数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象(引用数据类型)。
集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
学习集合的4大步骤: 1、创建集合对象 2、创建集合元素 3、向集合中添加元素 4、遍历集合
2.Collection接口
我们通过观察API发现,Collection是一个接口,而接口是不允许创建对象的 要想调用Collection接口中的方法,需要借助一个实现类去创建对象调用接口中的方法
使用集合的注意事项: 1、集合中只允许存储引用数据类型 2、同一个集合可以存储不同的引用数据类型的元素,但是尽管可以存储,我们在今后开发也不这么做,今后开发中一个集合就存一种数据类型
2.1 接口成员方法
boolean add(E e)
boolean remove(Object o)
void clear()
boolean contains(Object o)
boolean isEmpty()
int size()
import java.util.Collection;
import java.util.ArrayList;
public class CollectionTest1 {
public static void main(String[] args) {
Collection c1=new ArrayList(); //collection是接口,需要借助其实现类对象去创建对象
c1.add(99); //向collection中添加元素,int类型数据底层会自动装箱
c1.add("hello");
c1.add(12.34);
c1.add(true);
System.out.println(c1);
c1.remove("hello"); //将”hello“从集合中移走,若不存在,则不进行操作
System.out.println(c1.contains("hello")); //判断集合是否包含元素
System.out.println(c1.size()); //返回集合的元素个数
c1.clear(); //清空集合
System.out.println(c1.isEmpty()); //判断集合是否为空
}
}
注:
总结目前几种获取长度的方式: 数组获取长度:length属性 String获取长度:length() StringBuffer获取容器大小:capacity() StringBuffer获取字符个数:length() Collection集合获取元素个数:size()
boolean addAll(Collection c)
boolean removeAll(Collection c)
boolean containsAll(Collection c)
boolean retainAll(Collection c)
import java.util.Collection;
import java.util.ArrayList;
public class CollectionTest2 {
public static void main(String[] args) {
//创建集合对象
Collection c1=new ArrayList();
Collection c2=new ArrayList();
//创建元素并将元素添加到集合
c1.add("hadoop");
c1.add("hive");
c1.add("java");
c2.add("hbase");
c2.add("python");
c1.addAll(c2); //把c2集合添加到c1集合后面
System.out.println(c1);
c1.removeAll(c2); //从c1中移除c2
System.out.println(c1);
System.out.println(c1.containsAll(c2)); //判断c1中是否包含c2整体
c2.add("hadoop");
c1.retainAll(c2); //仅保留c1 c2的交集,仅c1发生改变
System.out.println(c1);
}
}
2.2 集合遍历方式
第一种方式:
import java.util.Collection;
import java.util.ArrayList;
public class CollectionTest3 {
public static void main(String[] args) {
//创建集合对象
Collection c1=new ArrayList();
//创建元素对象
c1.add("hadoop");
c1.add("hive");
c1.add("java");
c1.add("hbase");
c1.add("python");
//遍历集合
Object[] arr=c1.toArray(); //将集合改为数组
for (Object o : arr) {
System.out.println(o);
}
}
}
第二种方式
import java.util.Collection;
import java.util.ArrayList;
public class CollectionTest3 {
public static void main(String[] args) {
//创建集合对象
Collection c1=new ArrayList();
//创建元素对象
c1.add("hadoop");
c1.add("hive");
c1.add("java");
c1.add("hbase");
c1.add("python");
//遍历集合
for (Object o : c1) {
System.out.println(o);
}
}
}
第三种方式:迭代器遍历
Collection集合专有的遍历方式:迭代器遍历,Iteraror迭代器只能往后访问
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest4 {
public static void main(String[] args) {
//创建集合对象
Collection c1=new ArrayList();
//创建元素对象
c1.add("hadoop");
c1.add("hive");
c1.add("java");
c1.add("hbase");
c1.add("python");
//获取迭代器对象,只有Collection集合有迭代器
Iterator iterator = c1.iterator(); //方法编译看左,运行看右,调用的是ArrayList中的方法
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next()); //超出元素个数会出现异常
// //将来我们并不清楚迭代器中有多少元素,就无法知道要next多少次,应该要在每一个获取之前先判断一下下一个位置上是否存在元素
// //如果有,咱们就next()获取一下,如果没有就不获取
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
3.List接口
List接口:是继承自Collection接口 List的相关集合具备元素是有序的,且元素允许发生重复 这里的有序不是指排序,指的是存储和取出的顺序一致 用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。索引从0开始
3.1 List中特有的方法
void add(int index,E element)
E remove(int index)
E get(int index)
E set(int index,E element)
ListIterator listIterator()
import java.util.ArrayList;
import java.util.List;
public class ListTest1 {
public static void main(String[] args) {
List list=new ArrayList();
list.add("java");
list.add("hadoop");
list.add("hive");
list.add("hbase");
list.add("python");
System.out.println(list);
list.add(4,"append"); //在指定位置添加元素
System.out.println(list);
System.out.println(list.remove(2)); //删除指定索引的元素,如果索引不存在,会报错
System.out.println(list.get(3)); //获取指定索引的元素
list.set(4,"修改"); //修改指定索引的元素,返回值是被修改的元素
System.out.println(list);
}
}
3.2 List特有的遍历方式(size和get方法的结合)
import java.util.ArrayList;
import java.util.List;
public class ListTest2 {
public static void main(String[] args) {
List list=new ArrayList();
list.add("java");
list.add("hadoop");
list.add("hive");
list.add("hbase");
list.add("python");
for(int i=0;i<list.size()-1;i++){
System.out.println(list.get(i));
}
}
}
3.3 list的迭代器遍历(不同的是,list的迭代器还可以向前访问)
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListTest3 {
public static void main(String[] args) {
List list=new ArrayList();
list.add("java");
list.add("hadoop");
list.add("hive");
list.add("hbase");
list.add("python");
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){
System.out.println(listIterator.next());
}
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
}
}
需求:遍历集合,如果遇到了"java",就添加一个元素"flink" 针对这个需求而言,如果想用迭代实现,必须使用List特有的迭代器,只有list特有迭代器里才有add方法 我们正常去编写程序运行后报错:ConcurrentModificationException 并发修改异常 即集合发生修改了,迭代器并未改变 解决方案:迭代器遍历迭代器修改,集合遍历集合修改
4.List接口的子类
4.1 ArrayList类
底层数据结构是数组,查询快,增删慢的场景使用,线程不安全的一个类,效率高,是List接口的实现子类
方法和list一样
4.2 Vector类
Vector 底层数据结构依旧是数组,查询快,增删慢,线程是安全的,效率低。
即使这个是线程安全的,我们今后也不用,后面会学习如何将ArrayList变成线程安全的。
Vector特有的方法
//public void addElement(E obj)
//public E elementAt(int index)
//public Enumeration elements()
public class VectorTest {
public static void main(String[] args) {
//创建集合对象
Vector vector = new Vector();
//创建元素并添加到集合中
vector.add("python");
vector.add("java");
vector.add("hive");
vector.add("mysql");
vector.add("hbase");
//Vector特有的方法
vector.addElement("hello"); //在末尾添加元素,使用add()方法代替
System.out.println(vector.elementAt(2));//返回指定索引位置的元素,使用get代替
Enumeration enumeration=vector.elements(); //获取所有元素的组合,使用迭代器代替
while (enumeration.hasMoreElements()){
System.out.println(enumeration.nextElement());
}
}
}
4.3 LinkedList
底层数据结构是链表,查询慢,增删快,线程不安全,效率高
public void addFirst(E e)及addLast(E e)
public E getFirst()及getLast()
public E removeFirst()及public E removeLast()
import java.util.LinkedList;
public class LinkedListTest1 {
public static void main(String[] args) {
//创建集合对象
LinkedList objects = new LinkedList();
//向集合中添加元素
objects.add("java");
objects.add("python");
objects.add("redis");
objects.add("mysql");
objects.add("hadoop");
objects.addFirst("hive"); //在头部插入元素
objects.addLast("hbase"); //在尾部插入元素
System.out.println(objects.getFirst()); //打印头部元素
System.out.println(objects.getLast()); //打印尾部元素
System.out.println(objects.removeFirst()); //移除头部元素并打印
System.out.println(objects.removeLast()); //移除尾部元素并打印
}
}
4.4 List集合练习
1.去除集合中字符串的重复值(字符串的内容相同)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
//去除集合中字符串的重复值(字符串的内容相同)
public class ListTest1 {
public static void main(String[] args) {
//创建集合对象
ArrayList arrayList = new ArrayList();
ArrayList arrayList1 = new ArrayList();
//向集合中添加元素
arrayList.add("hive");
arrayList.add("hbase");
arrayList.add("hadoop");
arrayList.add("python");
arrayList.add("hive");
//创建迭代器对象
Iterator iterator=arrayList.iterator();
//遍历迭代器对象,若新集合中不包含元素,则将其添加进去
while(iterator.hasNext()){
String s=(String) iterator.next(); //向下转型
if(!arrayList1.contains(s)){
arrayList1.add(s);
}
}
System.out.println(arrayList1);
}
}
2.去除集合中自定义对象的重复值(对象的成员变量值都相同)
package com.bigdata.learn.day10;
import java.util.ArrayList;
//去除集合中自定义对象的重复值(对象的成员变量值都相同),假设是学生类
public class ListTest2 {
public static void main(String[] args) {
//创建集合对象
ArrayList arrayList = new ArrayList();
ArrayList arrayList1 = new ArrayList();
//创建学生对象
Student s1 = new Student("绫华", 18);
Student s2 = new Student("绫人", 20);
Student s3 = new Student("神子", 17);
Student s4 = new Student("申鹤", 19);
Student s5 = new Student("绫华", 18);
//向集合中添加元素
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
arrayList.add(s5);
System.out.println(arrayList);
//使用for循环遍历
for(int i=0;i<arrayList.size();i++){
Object s=arrayList.get(i);
if(!arrayList1.contains(s)){
arrayList1.add(s);
}
}
System.out.println(arrayList1);
}
}
注:使用上述代码发现,并未进行去重,这是因为contains方法中判断依据是equals方法,而equals方法默认比较的是地址值,故需要重写student类中的equals方法,使其比较的是元素的具体值
3.请用LinkedList模拟栈数据结构的集合,并测试
import java.util.LinkedList;
//要求是底层是LinkedList
public class MyCollection {
private LinkedList linkedList;
public MyCollection() {
linkedList = new LinkedList();
}
//创建添加元素的方法
public void myAdd(Object o){
// linkedList.addFirst(o);
linkedList.add(o); //压栈
}
public Object myGet(){
// return linkedList.get(index);
return linkedList.removeLast(); //弹栈
}
public int getLength(){
return linkedList.size();
}
}
5.泛型及其他
5.1 概述
我们之前的集合程序写法,发现有很多的警告,而且获取元素对象时候,并不能直观的发现元素对象的类型 我们想一下,之前学过一个容器:数组 数组的特点是对于同一个数组而言,只能存同一种数据类型的元素,在数组定义的时候就确定的这个数组的元素类型 int[] arr = new int[2]; 所以我们又想到,集合能否像数组一样,在定义的时候就确定这个集合就只能存某种引用数据类型,这样就不用做向下转型了。 java中提供了一个机制给我们使用:泛型机制 使用语句定义格式:<引用数据类型> 泛型的好处: 1、取消了很多的警告,使程序更加美观 2、获取元素的时候,不需要向下转型了 3、严格确定了集合中能存储的元素数据类型
//创建集合对象
ArrayList<String> list1 = new ArrayList<>(); //泛型的时候,前面必须写泛型,后面可以不写,但是要有<> jdk1.7之后会自动类型推断
5.2 泛型应用
5.2.1 泛型类
把泛型定义在类上
格式:public class 类名<泛型类型1,…>
注意:泛型类型必须是引用类型
public class Demo1<W> {
public void fun1(W w){
System.out.println(w);
}
}
将来创建对象时,给定泛型就知道W是什么类型的了,如果创建对象时没有给,那么就是Object类型
5.2.2 泛型方法
把泛型定义在方法上
格式:
public <泛型类型> 返回类型 方法名(泛型类型 .)
public class Demo1 {
public <E> void fun2(E e){
System.out.println(e);
}
}
如果泛型方法数据类型与泛型类数据类型不同,在泛型类中也可以使用泛型方法,指定数据类型,单独定义
如果泛型方法数据类型与泛型类数据类型相同,则可以不用写
5.2.3 泛型接口
把泛型定义在接口上
格式:
public interface 接口名<泛型类型1…>
public interface Inter<W> {
void fun1(W w);
}
如果接口用泛型,则类也要用泛型
5.3 泛型的高级用法
泛型通配符<?>
任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends E
向下限定,E及其子类
? super E
向上限定,E及其父类
例
addAll(Collection<? extends E> c)
可以添加某个类本身,或者某个类的子类集合进去
forEach(Consumer<? super E> action)
可以添加某个类本身,或者某个类的父类进去
1、如果在类,接口,方法中只看到单独的泛型,例如 类<E> 接口<E> 方法(E e),就给一个确定的类型即可
2、如果在方法中看到向下继承或者向上继承的泛型 fun(? extends E e) 将来可以传入E的子类或者本身类型 fun(? super E e) 将来可以传入E的父类或者本身类型
5.4 增强for循环
增强for循环,是用于遍历Collection集合和数组提供的方式。(map不适用)
语句定义格式: for(元素的数据类型 变量名:Collection集合对象名/数组名){ 操作遍历到的元素。 } 增强for循环的本意是用来替代迭代器的。
public class ZengForDemo1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
list.add("bigdata");
list.add("hive");
list.add("hadoop");
for (String s : list) {
System.out.println(s);
}
System.out.println("===========================");
int[] arr = {11, 22, 33, 44, 55};
for (int i : arr) {
System.out.println(i);
}
}
}
5.5 静态导入
import static java.lang.Math.max; //静态导入,导入到的级别是静态方法 //如果本类中有方法名与静态导入的方法名冲突的时候,使用全路径调用 //但是我们发现当使用全路径的时候还不如直接通过类名调用。
5.6 可变参数
可变参数概述 定义方法的时候不知道该定义多少个参数
格式
修饰符 返回值类型 方法名(数据类型… 变量名){}
注意: 这里的变量其实是一个数组 如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个 Arrays工具类中的一个方法
public static <T> List<T> asList(T... a)
public class Kebian {
public static void main(String[] args) {
sum(2,3);
sum(2,3,5); //可以看出,sum既可以传俩个数字也可以传三个数字
//需求:求一个学生的总分
sum2("小明",88,77,99);
}
public static void sum(int... arr){ //把若干个int类型的元素封装成一个数组使用
int sum=0;
for (int i : arr) {
sum+=i;
}
System.out.println(sum);
}
public static void sum2(String name,int... arr){ //可变参数的定义只能在最后,因为可变参数个数不能确定,且在一个方法中只能定义一个
int sum=0;
for (int i : arr) {
sum+=i;
}
System.out.println(name+"的成绩是"+sum);
}
}
5.7 集合的嵌套
public class CollectionTest1 {
public static void main(String[] args) {
//创建学校
ArrayList<ArrayList<Student>> school = new ArrayList<>();
//创建班级并创建学生对象
ArrayList<Student> clazz1 = new ArrayList<>();
Student s1 = new Student("温迪",16);
Student s2 = new Student("优菈",17);
clazz1.add(s1);
clazz1.add(s2);
school.add(clazz1);
ArrayList<Student> clazz2 = new ArrayList<>();
Student s3 = new Student("钟离",20);
Student s4 = new Student("胡桃",17);
clazz2.add(s3);
clazz2.add(s4);
school.add(clazz2);
ArrayList<Student> clazz3 = new ArrayList<>();
Student s5 = new Student("神里绫华",15);
Student s6 = new Student("心海",17);
clazz3.add(s5);
clazz3.add(s6);
school.add(clazz3);
System.out.println(school);
for (ArrayList<Student> clazz : school) { //打印学校的所有学生
for (Student student : clazz) {
System.out.println(student);
}
}
}
}
6.set接口及相关集合
6.1 set接口
特点:元素唯一且无序
6.2 HashSet类
1.存储字符串类型数据
public class SetDemo1 {
public static void main(String[] args) {
Set<String> set1=new HashSet<>();
set1.add("hello");
set1.add("hive");
set1.add("hadoop");
set1.add("hbase");
set1.add("hive");
set1.add("hadoop");
System.out.println(set1);
}
}
2.存储自定义类型数据
import java.util.HashSet;
import java.util.Set;
public class SetDemo2 {
public static void main(String[] args) {
Set<Student> set1=new HashSet<>();
Student s1 = new Student("温迪",16);
Student s2 = new Student("优菈",17);
Student s3 = new Student("钟离",20);
Student s4 = new Student("胡桃",17);
Student s5 = new Student("优菈",17);
//添加学生到集合中
set1.add(s1);
set1.add(s2);
set1.add(s3);
set1.add(s4);
set1.add(s5);
//打印set集合
System.out.println(set1);
}
}
注:运行结果发现,并未进行去重,通过观察源码发现,Hashset中的add()调用了hashmap中的put方法,先判断两个对象的哈希值是否一样hashCode()方法有关,然后调用元素类型中equals()方法进行比较,当上面两个都一样的时候,说明是同一个对象,故需要重写Student类中的equals和hashCode方法
修改过后,发现去重成功
6.3 LinkedHashSet类
LinkedHashSet:继承自HashSet,底层是哈希表和双链表构成
哈希表保证了数据的唯一性,双链表保证的是数据存储的顺序,线程不安全的,效率高
public class LinkedHashSetDemo {
public static void main(String[] args) {
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("hello");
set.add("world");
set.add("java");
set.add("hello");
set.add("hadoop");
set.add("java");
set.add("hive");
System.out.println(set);
}
}
6.4 TreeSet类
底层数据结构是红黑树,可以进行可预测的排序。
有两种对数据排序方式:
1、自然排序 2、比较器排序
使用TreeSet存储字符串会自动去重并排序,接下来看存储自定义数据类型
1.自然排序
import java.util.TreeSet;
public class TreeSet2 {
public static void main(String[] args) {
TreeSet<Dog> treeSet = new TreeSet<>();
Dog d1 = new Dog("小黑", 6);
Dog d2 = new Dog("小白", 1);
Dog d3 = new Dog("大黄", 3);
Dog d4 = new Dog("大白", 5);
Dog d5 = new Dog("小花", 4);
Dog d6 = new Dog("小白", 1);
Dog d7 = new Dog("哮天犬", 1);
treeSet.add(d1);
treeSet.add(d2);
treeSet.add(d3);
treeSet.add(d4);
treeSet.add(d5);
treeSet.add(d6);
treeSet.add(d7);
System.out.println(treeSet);
}
}
运行结果出现错误
在源码中,add方法实现运用了TreeMap无参调用方法,即是自然排序,此时TreeMap引用了Comparable接口,而String类型引用了此接口,故可以直接排序并去重输出,而Dog类并未引用此接口,故会出现错误,此时需要Dog类引用Comparable并进行重写其中的compareto()方法
重写的方法如下:
@Override
public int compareTo(Dog o) {
//这里的返回值不能随便给,要根据需求来
//主要条件:将存储的元素进行去重,且以年龄从小到大排序
//this -- 待插入的元素
//o -- 已经在树中的元素
// return this.age - o.getAge();
//次要条件:因为年龄一样,姓名不一定一样
int i = this.age - o.age;
//如果年龄一样比较姓名
int i2 = (i == 0) ? this.getName().compareTo(o.getName()) : i;
return i2;
}
2.比较器排序
public class TreeSetDemo3 {
public static void main(String[] args) {
//如果是比较器排序,元素类型不需要实现什么接口,只需要在创建集合对象的时候,传入比较器对象,编写比较的逻辑即可
TreeSet<Dog> treeSet = new TreeSet<>(new Comparator<Dog>() {
@Override
public int compare(Dog o1, Dog o2) {
//o1 -- 待插入的元素
//o2 -- 已经存在树中的元素
//主要条件:年龄从小到大排序
int i = o1.getAge() - o2.getAge();
//年龄一样,姓名不一定一样
int i2 = (i == 0) ? o1.getName().compareTo(o2.getName()) : i;
return i2;
}
});
Dog d1 = new Dog("小黑", 6);
Dog d2 = new Dog("小白", 1);
Dog d3 = new Dog("大黄", 3);
Dog d4 = new Dog("大白", 5);
Dog d5 = new Dog("小花", 4);
Dog d6 = new Dog("小白", 1);
Dog d7 = new Dog("哮天犬", 1);
treeSet.add(d1);
treeSet.add(d2);
treeSet.add(d3);
treeSet.add(d4);
treeSet.add(d5);
treeSet.add(d6);
treeSet.add(d7);
System.out.println(treeSet);
}
}
7.map继承体系
Map接口概述
将键映射到值的对象 一个映射不能包含重复的键
每个键最多只能映射到一个值
Map接口和Collection接口的不同
Map是双列的,Collection是单列的
Map的键唯一,Collection的子体系Set是唯一的
Map集合的数据结构值针对键有效,跟值无关
Collection集合的数据结构是针对元素有效
7.1 接口成员方法
V put(K key,V value)
V remove(Object key)
void clear()
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
int size()
import java.util.HashMap;
import java.util.Map;
public class MapTest1 {
public static void main(String[] args) {
//创建集合对象
Map<Integer, String> map = new HashMap<>();
//添加对象
map.put(1001,"温迪");
map.put(1002,"钟离");
map.put(1003,"神里绫华");
map.put(1004,"心海");
map.put(1005,"迪卢克");
map.put(1001,"纳西妲"); //对同一个key进行添加,值会进行覆盖
System.out.println(map);
System.out.println(map.remove(1001));; //删除某个值,返回值键为对应的值
System.out.println(map);
System.out.println("======================================");
System.out.println(map.containsKey(1001)); //判断键是否存在
System.out.println(map.containsValue("心海")); //判断值是否存在
System.out.println(map.isEmpty()); //判断是否为空
System.out.println("======================================");
System.out.println(map.size()); //求map的元素个数
}
}
俩种遍历方式:
所使用到的方法: int size() V get(Object key) 根据key获取对应的value值 Set<K> keySet() Collection<V> values() Set<Map.Entry<K,V>> entrySet() 生成的对象获取键值对可以使用getKey(),getValue()方法
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTest2{
public static void main(String[] args) {
//创建集合对象
Map<Integer, String> map = new HashMap<>();
//添加对象
map.put(1001,"温迪");
map.put(1002,"钟离");
map.put(1003,"神里绫华");
map.put(1004,"心海");
map.put(1005,"迪卢克");
//遍历方式1:获取所有key,根据key获取value值
Set<Integer> keys = map.keySet(); //获取所有的key
for (Integer key : keys) {
System.out.println(map.get(key));
}
System.out.println("===================================");
//遍历方式2:获取所有key-value键值对,分别获取key,value
Set<Map.Entry<Integer, String>> entries = map.entrySet();
for (Map.Entry<Integer, String> entry : entries) {
Integer key1=entry.getKey();
String value1=entry.getValue();
System.out.println(key1+":"+value1);
}
}
}
7.2 HashMap类
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTest3 {
public static void main(String[] args) {
//1、创建集合对象
HashMap<Student, String> map = new HashMap<>();
//2、创建元素对象
Student s1 = new Student("吴涛", 18);
Student s2 = new Student("陈涛", 17);
Student s3 = new Student("王硕", 20);
Student s4 = new Student("小虎", 19);
Student s5 = new Student("吴涛", 18);
//3、添加元素到集合
map.put(s1, "小虎");
map.put(s2, "笑哥");
map.put(s3, "刘亦菲");
map.put(s4, "冯提莫");
map.put(s5, "童哥");
Set<Map.Entry<Student, String>> set = map.entrySet();
for (Map.Entry<Student, String> entry : set) {
Student key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "---" + value);
}
}
}
唯一性是针对于key来说的,如果在重写了hashCode()方法和equals()的同时,将Student类型作为value值存在,是不会去重
7.3 LinkedHashMap类
底层是哈希表(保证了key的唯一性)和双链表
public class LinkedHashMapHash {
public static void main(String[] args) {
LinkedHashMap<Student, String> map = new LinkedHashMap<>();
map.put(new Student("钟离",18),"打羽毛球");
map.put(new Student("温迪",16),"打乒乓球");
map.put(new Student("八重神子",19),"踢足球");
map.put(new Student("神里绫华",20),"打英雄联盟");
map.put(new Student("钟离",18),"打网球");
System.out.println(map);
}
}
7.4 TreeMap类
1.自然排序
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMaptest {
public static void main(String[] args) {
TreeMap<Student, String> map = new TreeMap<>();
//插入元素
map.put(new Student("钟离",18),"打羽毛球");
map.put(new Student("温迪",16),"打乒乓球");
map.put(new Student("八重神子",19),"踢足球");
map.put(new Student("神里绫华",20),"打英雄联盟");
map.put(new Student("钟离",18),"打网球");
Set<Map.Entry<Student, String>> students = map.entrySet();
for (Map.Entry<Student, String> student : students) {
Student key=student.getKey();
String value=student.getValue();
System.out.println(key+":"+value);
}
}
}
student需要调用Comparable接口
2.迭代器排序
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMaptest {
public static void main(String[] args) {
TreeMap<Student, String> map = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int i=o1.getAge()-o2.getAge();
int i2=(i==0)?o1.getName().compareTo(o2.getName()):i;
return i2;
}
});
//插入元素
map.put(new Student("钟离",18),"打羽毛球");
map.put(new Student("温迪",16),"打乒乓球");
map.put(new Student("八重神子",19),"踢足球");
map.put(new Student("神里绫华",20),"打英雄联盟");
map.put(new Student("钟离",18),"打网球");
Set<Map.Entry<Student, String>> students = map.entrySet();
for (Map.Entry<Student, String> student : students) {
Student key=student.getKey();
String value=student.getValue();
System.out.println(key+":"+value);
}
}
}
HashMap和Hashtable的区别 (常问) 1、HashMap允许key-value值为null,但是Hashtable不允许 2、HashMap是线程不安全的集合,而Hashtable是线程安全的集合 List,Set,Map等接口是否都继承子Map接口? 答:不是,List和Set接口是继承自Collection接口的,Collection接口与Map接口是平级关系。
8.Collections类
Collections类概述
针对集合操作的工具类
Collections成员方法
public static <T> void sort(List<T> list) 排序
public static <T> int binarySearch(List<?> list,T key) 二分查找
public static <T> T max(Collection<?> coll) 求最大值
public static void reverse(List<?> list) 反转
public static void shuffle(List<?> list) 随机排列
public class CollectionsDemo {
public static void main(String[] args) {
//public static <T> void sort(List<T> list) 只能对List相关集合做排序
ArrayList<Integer> list = new ArrayList<>();
list.add(23);
list.add(11);
list.add(26);
list.add(15);
list.add(56);
list.add(8);
System.out.println(list);
System.out.println("===================================");
Collections.sort(list); //底层调用的是Arrays工具类中的快速排序的方法
System.out.println(list);
System.out.println("===================================");
//[8, 11, 15, 23, 26, 56]
//public static <T> int binarySearch(List<?> list,T key)
int i = Collections.binarySearch(list, 100);
System.out.println(i);
System.out.println("===================================");
//public static <T> T max(Collection<?> coll)
Integer max = Collections.max(list);
System.out.println(max);
System.out.println("===================================");
//public static void reverse(List<?> list)
Collections.reverse(list);
System.out.println(list);
System.out.println("===================================");
//public static void shuffle(List<?> list)
Collections.shuffle(list);
System.out.println(list); //[56, 11, 8, 26, 23, 15] [15, 56, 8, 26, 11, 23]
}
}
将ArrayList转成线程安全的
/*
填坑:之前我们说过Vector即使是线程安全的类,我们也不用它
我们可以将不安全的集合变成安全的。
*/
public class CollectionsDemo2 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(23);
list.add(11);
list.add(26);
list.add(15);
list.add(56);
list.add(8);
System.out.println(list);
System.out.println("==================================");
List<Integer> list1 = Collections.synchronizedList(list); //将list集合变成线程安全的集合
}
}