Day20 Java基础-集合基础

Day20 Java基础-集合基础01

集合引入和ArrayList

集合的使用场合-Where

新闻列表、就业喜报、就业明星、邮件列表、购物车;

当我们需要将一些相同结构的个体整合在一起时,就可以考虑使用集合了。

为什么使用集合而不是数组-Why

集合和数组相似点:搜可以存储多个对象,对外作为一个整体存在

数组的缺点:

  • 长度必须在初始化时指定,且固定不变
  • 数组采用连续存储空间,删除和添加效率低下
  • 数组无法直接保存映射关系
  • 数组缺乏封装,操作繁琐

集合中使用map实现映射关系

集合框架

Java集合框架提供了一套性能优良,使用方便地接口和类,他们位于java.util包中。存放在集合中的数据,被称为元素(element)

集合分为两大类:Collection Map

又分3大类:list set map(核心)


集合架构

  • Collection接口存储一组不唯一(重复),无序的对象

  • List接口存储一组不唯一,有序(索引顺序)的对象(想象成数组,可以重复)(与Set一起继承Collection)

  • Set接口存储一组唯一,无序的对象(想象成一个麻袋,里面放杂乱无章的东西,不重复)

  • Map接口存储一组键值对象,提供key到value的映射(也想象成麻袋,但对象中有两个值)

    ​ Key 唯一 无序

    ​ value 不唯一 无序

Set里面的内容就是Map里面的Key,Map中的value去了只有其实就是Set

Set就是在Map的基础上简化的


List的主要实现类

List特点:有序 不唯一(可重复)

ArrayList

  • 在内存中分配连续的空间,实现了长度可变的数组
  • 优点:遍历元素和随机访问元素的效率比较高(按照索引效率高)
  • 缺点:添加和删除需大量移动元素效率低,按照内容查询效率低

LinkedList

  • 采用双向链表存储方式

  • 缺点:遍历和随机访问元素效率低下

  • 优点:插入、删除元素效率比较高(但是前提也是必须先低效率查询才可。如果插入删除发生在头尾可以减少查询次数)

ArrayList和LinkedList共同缺点:按照内容查询效率低

ArrayList和LinkedList有什么区别也就是问顺序表和链表有什么区别

ArrayList的基本操作

package com.ashuu.list;
import java.util.ArrayList;
import java.util.Iterator;

/*
* 使用ArrayList存储多个分数的信息
* 分数会重复,分数有顺序,所有用集合比较合适
* */
public class TestArrayList {
    public static void main(String[] args) {
        //1.创建一个ArrayList对象,用来存储多个分数
        ArrayList list = new ArrayList();


        //2.向ArrayList添加分数
        list.add(89);//集合的元素必须是对象类型,不能是基本数据类型
        list.add(96);//如果放入基本数据类型,需要使用包装类
        list.add(98);//JDK5之后,自动装箱
        list.add(85);
        list.add(87);
        list.add(2,100);//索引是2的地方,添加100分


        ArrayList list2 = new ArrayList();
        list2.add(85);
        list2.add(86);
        list2.add(69);

        //list.addAll(list2);
        list.addAll(0,list2);

        //3.获取ArrayList中的分数
        System.out.println(list.toString());
        System.out.println(list.size());
        System.out.println(list.get(2));

        System.out.println("===========for循环遍历=============");
        //遍历ArrayList的方法1:使用for循环
        for ( int i=0; i<list.size(); i++){
        int elem = (int)list.get(i);//因为list.get返回值类型是object,所以需要强制转换integer也可以
        System.out.println(i+" "+elem);
        }

        //遍历ArrayList的方法2:使用增强for(for-each)
        System.out.println("---------------增强for遍历----------------");
        for(Object elem:list){
            System.out.println(elem);
        }

        //遍历ArrayList的方法1:使用迭代器Iterator
        System.out.println("============迭代器遍历==================");
        Iterator it = list.iterator();
        while (it.hasNext()){
         int elem = (int) it.next();
         System.out.println(elem);
        }

    }
}
/*
* 在集合中使用泛型
*
* 目前代码的问题有两个:
* 不安全:list.add("ashuu");
* 繁琐:int elem = (int)list.get(i);需要强制转换
*
* 解决:使用泛型来解决
* 安全、简单、不需要强制转换
* JDK1.5提供了泛型
* */
public class TestArrayList1 {
    public static void main(String[] args) {
        //1.创建一个ArrayList对象,用来存储多个分数
        ArrayList<Integer> list = new ArrayList<Integer>();
        //泛型里面不能写基本类型,只能写包装类

        //2.向ArrayList添加分数
        list.add(89);//集合的元素必须是对象类型,不能是基本数据类型
        list.add(96);//如果放入基本数据类型,需要使用包装类
        list.add(98);//JDK5之后,自动装箱
        list.add(85);
        list.add(87);
        list.add(2,100);//索引是2的地方,添加100分



        //3.获取ArrayList中的分数
        System.out.println(list.toString());
        System.out.println(list.size());
        System.out.println(list.get(2));

        System.out.println("===========for循环遍历=============");
        //遍历ArrayList的方法1:使用for循环
        for ( int i=0; i<list.size(); i++){
        int elem = list.get(i);//因为list.get返回值类型是object,所以需要强制转换integer也可以
        System.out.println(i+" "+elem);
        }

        //遍历ArrayList的方法2:使用增强for(for-each)
        System.out.println("---------------增强for遍历----------------");
        for(int elem:list){
            System.out.println(elem);
        }

        //遍历ArrayList的方法1:使用迭代器Iterator
        System.out.println("============迭代器遍历==================");
        Iterator<Integer> it = list.iterator();
        while (it.hasNext()){
         int elem = it.next();
         System.out.println(elem);
        }

    }
}

ArrayList的更多操作

package com.ashuu.list;
import java.util.ArrayList;
import java.util.Iterator;

/*
*ArrayList的其他方法
*
* 添加
* list.add(89);
* list.add(2,100);
* list.addAll(list2);
* list.addAll(0,list2);
*
* 删除
* list.clear();
* list.remove(new Integer(95));
* list.remove(1);
* list.removeAll(list2)//取并集,保留不同的
* list.retainAll(list2);//取交集,保留相同的
*
* 修改
* list.set(1,98)
*
* 查询
* list.get(2)
* list.size()
* list.contains(98);
* list.isEmpty();
* 
* */
public class TestArrayList2 {
    public static void main(String[] args) {
        //1.创建一个ArrayList对象,用来存储多个分数
        ArrayList<Integer> list = new ArrayList<Integer>();
        //泛型里面不能写基本类型,只能写包装类

        //2.向ArrayList添加分数
        list.add(89);//集合的元素必须是对象类型,不能是基本数据类型
        list.add(96);//如果放入基本数据类型,需要使用包装类
        list.add(98);//JDK5之后,自动装箱
        list.add(85);
        list.add(87);
        list.add(2,100);//索引是2的地方,添加100分
        System.out.println(list.toString());


        ArrayList<Integer> list2 = new ArrayList<Integer>();
        list2.add(98);
        list2.add(89);
        list2.add(44);
        list.retainAll(list2);
        System.out.println(list2.toString());
        //删除
        //list.clear();清除所有的
        //list.remove(new Integer(96));//因为索引是整数类型,元素也是整数类型,加了这个说明删的是对象
        //list.remove(1);//根据索引删除
        list.retainAll(list2);//保留
        //修改
        //list.set(1,89);

        //3.获取ArrayList中的分数
        System.out.println(list.toString());
        //System.out.println(list.size());
        //System.out.println(list.get(2));
        //System.out.println(list.contains(98));
        //System.out.println(list.isEmpty());
    }
}

ArrayList的源码理解

  • ArrayList底层就是一个长度可以动态增长的Objct数组;(StringBuiolder底层就是一个长度可以动态增长的char数组)
public class ArrayList<E> extends AbstractList<E>//ArrayList继承了一个类 
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable//实现了List接口、随机存取(按照索引),克隆(快速复制),序列化,这三个接口没有方法,有用,作为判断来使用
{
    private static final long serialVersionUID = 8683452581122892189L;
    private static final int DEFAULT_CAPACITY = 10;
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    transient Object[] elementData; 
    private int size;
private static final int DEFAULT_CAPACITY = 10;//定义了一个私有的静态常量叫默认的容量等于10
private static final Object[] EMPTY_ELEMENTDATA = {};//定义一个空的元素数据
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认的空的元素数据


/*
JDK8中默认给ArrayList中赋值的情况
定义初始容量initialCapacity
*/
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

transient Object[] elementData;



LinkedList

package com.ashuu.list2;
import java.util.LinkedList;
/*
* 1.ArrayList转变成LinkedList的时候,不变的是什么?
* 运行结果没有变
* 代码没有变(除了创建对象)
*
* 2.ArrayList转变成LinkedList的时候,变化的是什么?
* 底层的存储结构发生了变化
* ArrayList:数组
* LinkedList:双向链表
*
* 功能的底层实现变了
* add(2,67)
* ArrayList:需要大量的后移元素  效率低
* LinkedList:修改前后节点的指针  效率高
*
* get(2)
* ArrayList:计算地址  1012+4*2=1020  效率高
* LinkedList:顺藤摸瓜,逐个数数 0 1 2  效率低
*
* 3.到底是使用ArrayList还是LinkedList?
* 视情况而定
* 按照索引查询多:ArrayList
* 删除添加操作多:LinkedList
*
* 4.LinkedList相比ArrayList提供了更多的方法
* 底层代码中LinkedList相比ArrayList多了一个Deque<E>接口
*
* 5.List<Integer> list = new ArrayListList<Integer>();推荐向上转型
*
*
* */

public class TestLinkedlist {
    public static void main(String[] args) {
        //1.创建一个ArrayList对象,用来存储多个分数
        LinkedList<Integer> list = new LinkedList<Integer>();
        //泛型里面不能写基本类型,只能写包装类

        //2.向ArrayList添加分数
        list.add(89);//集合的元素必须是对象类型,不能是基本数据类型
        list.add(96);//如果放入基本数据类型,需要使用包装类
        list.add(98);//JDK5之后,自动装箱
        list.add(85);
        list.add(87);
        list.add(2,100);//索引是2的地方,添加100分

        //LinkedList特有的方法
        list.addFirst(12);
        list.addLast(21);
        list.getFirst();
        list.getLast();
        list.removeFirst();
        list.removeLast();

        System.out.println(list.toString());


        LinkedList<Integer> list2 = new LinkedList<Integer>();
        list2.add(98);
        list2.add(89);
        list2.add(44);
        list.retainAll(list2);
        System.out.println(list2.toString());
        //删除
        //list.clear();清除所有的
        //list.remove(new Integer(96));//因为索引是整数类型,元素也是整数类型,加了这个说明删的是对象
        //list.remove(1);//根据索引删除
        list.retainAll(list2);//保留
        //修改
        //list.set(1,89);

        //3.获取ArrayList中的分数
        System.out.println(list.toString());
        System.out.println(list.size());
        System.out.println(list.get(1));
        //System.out.println(list.contains(98));
        //System.out.println(list.isEmpty());
    }
}

Java中栈和队列的实现类

  • public class Stack extends Vector

    Vector 过时了,被ArrayList替代了,Stack也就过时了

  • public interface Queue extends Collection

    public interface Deque extends Queue

  • Duque和Queue的实现类

    1. ArrayDeque 顺序栈 数组
    2. LinkedList 链栈 链表

集合框架Set和Map

主要内容

  1. HashSet TreeSet LinkedHashSet
  2. 内部比较器和外部比较器
  3. 哈希表的原理
  4. HashMap TreeMap LinkedeHashMap
  5. HashMap源码解析
  6. TreeMap源码解析
  7. HashSet源码解析
  8. TreeSet源码解析

Set集合类型

Set

  • 特点:无序 唯一(不重复)

HashSet

  • 采用Hashtable哈希表存储结构(神奇的结构)
  • 优点:添加速度快 查询速度快 删除速度快
  • 缺点:无序

LinkedHashSet

  • 采用哈希表存储结构,同时使用链表维护次序

  • 有序(添加顺序)

    TreeSet

  • 采用二叉树(红黑树)的存储结构

  • 优点:有序 查询速度比List快(按照内容查询)

  • 缺点:查询速度没有HashSet快


使用各种Set存储课程信息

/*
* 使用set存储课程信息
*
* HashSet 唯一 无序   哈希表(快)
* LinkedHashSet  唯一 添加顺序有序    哈希表(快)+链表(有序)
* TreeSet  唯一 自然顺序(由小到大)红黑树
*
*
* Set相比Collection ,没有增加任何方法。而List却增加和索引相关的一些方法
* add(index,elem)   get(index) remove(index)
* */
public class TestSet {
    public static void main(String[] args) {
        //创建一个set对象

        //Set <String>set = new <String>HashSet();
        //Set <String>set =  new <String>LinkedHashSet;
        Set <String>set = new TreeSet<String>();

        //添加元素
        set.add("Java");
        set.add("Mysql");
        set.add("JavaEE");
        set.add("SSM");
        set.add("Java");

        //因为数据少,所以输出有顺序是偶然的
        System.out.println(set.size());
        System.out.println(set.toString());

        //遍历1:for-each
        for (String elem:set) {
            System.out.println(elem);
        }

        //遍历2:使用迭代器
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String elem = it.next();
            System.out.println(elem);
        }
    }
}
import java.util.Objects;

public class Student implements Comparable<Student>{
    private int age;
    private String name;
    private double score;
    private int sno;

    public Student() {
    }

    public Student(int age, String name, double score, int sno) {
        this.age = age;
        this.name = name;
        this.score = score;
        this.sno = sno;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public int getSno() {
        return sno;
    }

    public void setSno(int sno) {
        this.sno = sno;
    }

    @Override
    public int compareTo(Student other) {
        return this.sno - other.sno;
        //return -(this.sno - other.sno);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        if (Double.compare(student.score, score) != 0) return false;
        if (sno != student.sno) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = age;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        temp = Double.doubleToLongBits(score);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + sno;
        return result;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", score=" + score +
                ", sno=" + sno +
                '}';
    }
}




import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

/*
* 使用Set存储多个学生信息
*
* 问题1:为什么课程名称(String)放入到HashSet  LinkedHashSet都可以保证唯一性,但是学生(Student)放入到HashSet  LinkedHashSet却无法实现唯一性?
*
*
* 问题2:为什么课程名称(String)放入到TreeSet都可以保证唯一性,有序性,但是学生(Student)放入到TreeSet却直接抛出异常?
*
*
* 思考?:是否因为String类是系统类,Student是用户自定义类
*       String类应该已经做了某些操作,但是Student类还没有做
*
* 解答问题1:任何对象放入HashSet  LinkedHashSet等底层结构有哈希表的集合中,必须重写两个方法
* hashcode() equals()
* String类已经重写了这两个方法,而Student类没有重写
*
* 解答问题2:任意对象放入TreeSet等底层结构是红黑树的集合中,都需要实现comparable接口(内部比较器),并实现其方法
*
* 问题3:comparable接口至多指定一种规则,如果希望按照更多的排序规则放入TreeSet等集合中该怎么办?
* 解决:可以使用外部比较器Comparator
* */
public class TestSet2 {
    public static void main(String[] args) {
        //创建学生对象
        //Set <Student>set = new HashSet<Student>();
        //Set <Student>set = new LinkedHashSet<Student>();
        Set <Student>set = new TreeSet<Student>();

        //添加学生信息
        Student stu = new Student(20,"张三",80,1);
        Student stu2 = new Student(19,"李四",81,2);
        Student stu3 = new Student(18,"王五",84,3);
        Student stu4 = new Student(21,"赵六",85,4);
        Student stu5 = new Student(20,"张三",80,1);

        set.add(stu);
        set.add(stu2);
        set.add(stu3);
        set.add(stu4);
        set.add(stu5);

        //输出学生信息
        System.out.println(set.size());


        for(Student stu6 : set){
            System.out.println(stu6);
        }
    }
}

定义多个外部比较器实现对TreeSet的存储

/*定义姓名排序外部比较器*/
import java.util.Comparator;

public class StudentNameComparator  implements Comparator <Student> {
    @Override
    public int compare(Student stu1, Student stu2) {
        return stu1.getName().compareTo(stu2.getName());//字符串和字符串不能相减,只能调用String类的compareTo方法

    }
}
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;


public class TestSet3 {
    public static void main(String[] args) {
        //创建学生对象
        //Set <Student>set = new HashSet<Student>();
        //Set <Student>set = new LinkedHashSet<Student>();
        Set <Student>set = new TreeSet<Student>();

        //添加学生信息
        Student stu = new Student(20,"张三",80,1);
        Student stu2 = new Student(19,"李四",81,2);
        Student stu3 = new Student(18,"王五",84,3);
        Student stu4 = new Student(21,"赵六",85,4);
        Student stu5 = new Student(20,"张三",80,1);
        Student stu6 = new Student(20,"zhangsan",80,1);
        Student stu7 = new Student(19,"lisi",81,2);
        Student stu8 = new Student(18,"wangwu",84,3);
        Student stu9 = new Student(21,"zhaoliu",85,4);


        set.add(stu);
        set.add(stu2);
        set.add(stu3);
        set.add(stu4);
        set.add(stu5);

        //输出学生信息
        System.out.println(set.size());


        for(Student stu11 : set){
            System.out.println(stu6);
        }

        System.out.println("=====================================================");
        Comparator comp1 = new StudentScoreDescComparator();
        Set <Student>set2 = new TreeSet<Student>(comp1);//底层代码的调用是优先使用外部比较器
        set2.add(stu);
        set2.add(stu2);
        set2.add(stu3);
        set2.add(stu4);
        set2.add(stu5);
        System.out.println(set2.size());
        for(Student nbnb : set2){
            System.out.println(nbnb);
        }



        System.out.println("=====================================================");
        Comparator comp2 = new StudentNameComparator();
        Set <Student>set3 = new TreeSet<Student>(comp2);//底层代码的调用是优先使用外部比较器
        set3.add(stu6);
        set3.add(stu7);
        set3.add(stu8);
        set3.add(stu9);
        System.out.println(set3.size());
        for(Student nbnb2 : set3){
            System.out.println(nbnb2);
        }



        System.out.println("=====================================================");
        //觉得一个外部比较器只是用一次还要重新写一个类太浪费,下面代码展示
        //局部内部类
        class StudentNameComparator implements Comparator<Student>{
            @Override
            public int compare(Student stu1, Student stu2) {
                return stu1.getName().compareTo(stu2.getName());//字符串和字符串不能相减,只能调用String类的compareTo方法
            }
        }
        Comparator comp3 = new StudentNameComparator();




        System.out.println("--1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1");
        //匿名内部类
        Comparator comp4 = new Comparator<Student>() {
            @Override
            public int compare(Student stu1, Student stu2) {
                return -stu1.getName().compareTo(stu2.getName());//字符串和字符串不能相减,只能调用String类的compareTo方法
            }
        };
        Set <Student>set4 = new TreeSet<Student>(comp4);//底层代码的调用是优先使用外部比较器
        set4.add(stu6);
        set4.add(stu7);
        set4.add(stu8);
        set4.add(stu9);
        System.out.println(set4.size());
        for(Student nbnb23 : set4){
            System.out.println(nbnb23);
        }
    }
}

注意1:对于外部比较器,如果使用次数较少,可以通过匿名内部类来实现

注意2:需要比较的场合

在Hash表中添加数据的时候,必须要重写equals()和hashcode()方法


哈希表的原理

引入哈希表

  • 在无序数组中按照内容查找,效率低下,时间复杂度是O(n)

  • 在有序数组中按照内容查找,可以使用折半查找,时间复杂度O(log2n)

  • 在二叉平衡树中按照内容查找,时间复杂度O(log2n)

  • 在数组中按照索引查找,不进行比较和技术,直接计算得到,效率最高 ,时间复杂度O(1)

    指定索引的元素位置=数组的起始位置+每个元素的大小*索引

  • 问题:按照内容查找,能否也不进行比较,而是通过计算得到地址,实现类似数组按照索引查询的高效率呢O(1)

    哈希表来实现

    前面查找方法共同特点:通过将关键字值与给定值比较,来确定位置。效率取决比较次数。

    理想的方法是:不需要比较,根据给定值能直接定位记录的存储位置

    这样,需要在记录的存储位置与该记录的关键字只加建立一种确定的对应关系,使每个记录的关键字与一个存储位置(数组索引)相对应

哈希表的结构和特点

hashtable 也叫散列表

特点:非常快
结构:结构有多种
最流行、最容易理解:顺序表+链表
主结构:顺序表
每个顺序表的节点在单独引出一个链表

哈希表是如何添加数据的

  1. 计算哈希码(调用hashcode(),结果是一个int值,整数的哈希码取自身即可)

  2. 计算在哈希表中的存储位置 y=k(x) = x %11

    x:哈希码 k(x) 函数y:在哈希表中的存储位置

  3. 存入哈希表

    • 情况1:一次添加成功
    • 情况2:多次添加成功(出现了冲突,调用equals()和对应链表的元素进行比较,比较到最后,结果都是false,创建新节点,存储数据,并加入链条末尾)
    • 情况3:不添加(出现了冲突,调用equals()和对应链表的元素进行比较,经过一次或者多次比较后,结果都是true,表名重复,不添加)

    结论1:哈希表添加数据快(3步即可,不考虑冲突)

    结论2:唯一,无序


hashcode和equals到底有什么神奇的作用

  • hashcode():计算哈希码,是一个整数,根据哈希码可以计算出数据在哈希表中的存储位置
  • equals():添加时出现了冲突,需要通过equals进行比较,判断是否相同;查询时也需要使用equals进行比较,判断是否相同

各种类型数据的哈希码应该如何获取 hashcode()

  1. int 取自身 看Integer的源码

  2. double 3.14 3.15 3.145 6.567 9.87 取整不可以 看Double的源码

  3. String java oracle j+a+v+a 将各个字符的编码值相加不可以

    abc cba bac a:97 b:98 c:99

    abc 197+298+399 cba 199+298+397

  4. Student 先各个属性的哈希码,进行某些相加相乘的运算

    int id String name int age double score

如何减少冲突

  1. 哈希表的长度和表中记录数的比例——装填因子

    如果Hash表的空间远远大于最后实际存储的记录个数,则造成了很大的空间浪费,如果选取小了的话,则容易造成冲突。在实际情况中,一般需要根据最终记录个数和关键字的分布特点来确定Hash表的大小。还有一种情况时可能实现不知道最终需要存储的记录个数,则需要动态维护Hash表的容量,此时可能需要重新计算Hash地址

    装填因子 = 表中的记录数/哈希表的长度 4/16=0.25

    如果装填因子越小,表名表中还有很多的空单元,则添加发生冲突的可能性越小;而装填因子越大,则发生冲突的可能性就越大,在查找时所耗费的时间就越多。有相关文献证明当装填因子在0.5左右时候,Hash性能就能够达到最优。因此,一般情况下,装填因子取经验值0.5

  2. 哈希函数的选择

直接定址法、平方取中法、折叠法、除留取余法(y = x%11)

  1. 处理冲突的方法

链地址法、开放地址法、再散列法、建立一个公共溢出区


Map集合的使用

Map(映射)集合类型

  • Map

    特点:存储的键值对映射关系,根据key可以找到value

  • HashMap

    采用Hashtable哈希表存储结构(神奇的结构)

    优点:添加速度快、查询速度快、删除速度快

    缺点:key无序

  • LinkedHashMap

    采用哈希表存储结构,同时使用链表维护次序

    key有序(添加顺序)

  • TreeMap

    采用二叉树(红黑树)的存储结构

    优点:key有序 查询速度比List快(按照内容查询)

    缺点:查询速度没有HashMap快

/*
* 使用各种Map存储各个国家的简称和国家的名称之间的映射
*
* HashMap
*   key:唯一、无序 HashSet
*   value:不唯一、无序  Collection
*
* LinkedHashMap
*   key:唯一、有序(添加顺序) LinkedHashSet
*   value:不唯一、无序  Collection
*
* TreeMap
*   key:唯一、有序(自然顺序) TreeSet
*   value:不唯一、无序  Collection
*
*
* Map的常用操作
* 1.创建对象
* 2.放入键值对
* 3.根据key找到value
* 4.遍历
*
* */
public class TestMap {
    public static void main(String[] args) {

        //创建一个Map对象
        //Map<String,String> map = new HashMap<String,String>();//前面key,后面value
        //Map<String,String> map = new LinkedHashMap<String,String>();
        Map<String,String> map = new TreeMap<String,String>();

        //向Map对象中添加键值对
        map.put("cn","China");
        map.put("jp","japan");
        map.put("us","united state");
        map.put("fr","france");
        map.put("us","american");
        map.put("uk","the united kingdom");
        map.put("en","the united kingdom");
        //map.put(null,null);  TreeMap不能放

        //输出Map对象的数据
        System.out.println(map);
        System.out.println(map.size());
        System.out.println(map.get("cn"));
        System.out.println(map.keySet());//Set
        System.out.println(map.values());//Collection

        System.out.println("================");
        //遍历1:先得到所有的key,在遍历key的过程中,再根据key获取value  不推荐
        Set<String> keyset = map.keySet();
        Iterator<String> it = keyset.iterator();
        while(it.hasNext()){
            String key = it.next();
            System.out.println(key+"----->"+map.get(key));
        }

        System.out.println("=========!==========");
        //遍历2:得到所有的key-value组成的set,直接遍历set   推荐
        Set<Map.Entry<String,String>> entryset = map.entrySet();
        for(Map.Entry<String,String> entry :entryset){
            //System.out.println(entry);
            System.out.println(entry.getKey()+"====>"+entry.getValue());
        }

    }

}
public class Student implements Comparable<Student>{
    private int age;
    private String name;
    private double score;
    private int sno;

    public Student() {
    }

    public Student(int age, String name, double score, int sno) {
        this.age = age;
        this.name = name;
        this.score = score;
        this.sno = sno;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public int getSno() {
        return sno;
    }

    public void setSno(int sno) {
        this.sno = sno;
    }

    @Override
    public int compareTo(Student other) {//内部比较器只能定义一个,频率最高的使用
        return this.sno - other.sno;
        //return -(this.sno - other.sno);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        if (Double.compare(student.score, score) != 0) return false;
        if (sno != student.sno) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = age;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        temp = Double.doubleToLongBits(score);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + sno;
        return result;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", score=" + score +
                ", sno=" + sno +
                '}';
    }
}




import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/*
* 使用Map存储学号和学生的映射
*
* */
public class TestMap2 {
    public static void main(String[] args) {

        Map<Integer,Student> map  = new HashMap<Integer,Student>();
        //HashMap<Integer,Student> map  = new HashMap<Integer,Student>();这样再去找isempty的源码


        Student stu1 = new Student(20,"张三",80,1);
        Student stu2 = new Student(19,"李四",81,2);
        Student stu3 = new Student(18,"王五",84,3);
        Student stu4 = new Student(21,"赵六",85,4);
        Student stu5 = new Student(20,"张三",80,1);

        map.put(stu1.getSno(),stu1);
        map.put(stu2.getSno(),stu2);
        map.put(stu3.getSno(),stu3);
        map.put(stu4.getSno(),stu4);
        map.put(stu5.getSno(),stu5);


        //其他方法
        //map.clear();//全部清空
        //map.remove(3);
        //map.isEmpty();
        //System.out.println(map.containsKey(5));包含是否学号为5的学生

        System.out.println(map.get(3));

        //遍历输出
        Set<Map.Entry<Integer,Student>> entryset =  map.entrySet();
        Iterator<Map.Entry<Integer,Student>> it  = entryset.iterator();
        while(it.hasNext()){
            Map.Entry<Integer,Student> entry = it.next();
            //System.out.println(entry);
            Student stu = entry.getValue();
            System.out.println(stu);
        }




    }
}


        //HashMap<Integer,Student> map  = new HashMap<Integer,Student>();这样再去找isempty的源码


        Student stu1 = new Student(20,"张三",80,1);
        Student stu2 = new Student(19,"李四",81,2);
        Student stu3 = new Student(18,"王五",84,3);
        Student stu4 = new Student(21,"赵六",85,4);
        Student stu5 = new Student(20,"张三",80,1);

        map.put(stu1.getSno(),stu1);
        map.put(stu2.getSno(),stu2);
        map.put(stu3.getSno(),stu3);
        map.put(stu4.getSno(),stu4);
        map.put(stu5.getSno(),stu5);


        //其他方法
        //map.clear();//全部清空
        //map.remove(3);
        //map.isEmpty();
        //System.out.println(map.containsKey(5));包含是否学号为5的学生

        System.out.println(map.get(3));

        //遍历输出
        Set<Map.Entry<Integer,Student>> entryset =  map.entrySet();
        Iterator<Map.Entry<Integer,Student>> it  = entryset.iterator();
        while(it.hasNext()){
            Map.Entry<Integer,Student> entry = it.next();
            //System.out.println(entry);
            Student stu = entry.getValue();
            System.out.println(stu);
        }




    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值