Java 06 集合

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集合变成线程安全的集合
        
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值