14.枚举类、集合

枚举

方式一:jdk5.0 之前(不常用)

package com.atguigu.java;
/*
一:枚举类的使用
    1.枚举类的理解:类的对象是有限个、确定个的,称此类为枚举类
    2.当需要定义一组常量时,强烈推荐使用枚举类
    3.如果枚举类中只有一个对象,则可以作为单例模式的一种实现方式

二、如何定义枚举类
方式一: jdk5.0之前,自定义枚举类
方式二:jdk5.0,可以使用enum关键字定义枚举类

 */
public class SeasonTest {
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        String s = spring.toString();
        System.out.println(s);
        //Season{seasonName='春天', seasonDesc='穿暖花开'}
    }
}
//方式一:自定义枚举类
class Season{
    //1声明Season对象的属性,用private final修饰
    private final String seasonName;
    private final String seasonDesc;
   //2.私有化类的构造器,并给对象属性初始化
    private Season(String seasonName,String seasonDesc){
        this.seasonDesc = seasonDesc;
        this.seasonName = seasonName;
    }
    //3.提供当前枚举类的多个对象(外部可直接调用-静态方法):public static final
    public static final Season SPRING = new Season("春天","穿暖花开");
    public static final Season SUMMER = new Season("夏天","夏日炎炎");
    public static final Season AUTUMN = new Season("秋天","果实累累");
    public static final Season WINTER = new Season("冬天","白雪皑皑");

    //4.其他诉求:获取枚举类对象的属性
    public String getSeasonName() {
        return seasonName;
    }
    public String getSeasonDesc() {
        return seasonDesc;
    }
    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}

方式二:使用enum关键字定义枚举类(常用)以及常用方法、实现接口

package com.atguigu.java;
/*
二:使用enum关键字定义枚举类
   说明: 定义的枚举类默认继承与 java.lang.Enum 类

三、Enum中常用方法
      values():返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值
      valueOf(String str): 可以把一个字符串转为对相应的枚举类对象。要求字符串必须是枚举类对象
      toString():返回当前枚举类对象的名称

四、使用enum关键字定义的枚举类实现接口的情况
    情况1:实现接口,在enum类中实现抽象方法
    情况2:让枚举类的对象分别实现接口中的抽象方法


 */
public class SeasonTest1 {
    public static void main(String[] args) {
        Season autumn = Season.AUTUMN;
        //toString()
        System.out.println(autumn.toString());
        //Season{seasonName='秋天', seasonDesc='果实累累'}

        //values()
        Season1[] values = Season1.values();
        for (int i = 0 ; i< values.length; i++){
            System.out.println(values[i]);
        }
        //SPRING
        //SUMMER
        //AUTUMN
        //WINTER

        //valueOf(String objName):根据提供的objName,返回与objName相同的枚举类对象
        //如果没有objName的枚举类对象,则抛异常IllegalArgumentException
        Season1 winter = Season1.valueOf("WINTER");
        System.out.println(winter);
        //WINTER

        winter.show();
        //情况1:这是一个季节
        //情况2;冬天
    }
}

interface Info{
    void show();
}
enum Season1 implements  Info{
    //1.提供当前枚举类的对象,多个对象之间用","隔开,末尾的对象使用";"结束
    SPRING("春天", "穿暖花开"){
        //情况2
        @Override
        public void show() {
            System.out.println(getSeasonName());
        }
    },
    SUMMER("夏天", "夏日炎炎"){
        @Override
        public void show() {
            System.out.println(getSeasonName());
        }
    },
    AUTUMN("秋天", "果实累累"){
        @Override
        public void show() {
            System.out.println(getSeasonName());
        }
    },
    WINTER ("冬天", "白雪皑皑"){
        @Override
        public void show() {
            System.out.println(getSeasonName());
        }
    };

    //2声明Season对象的属性,用private final修饰
    private final String seasonName;
    private final String seasonDesc;

    //3.私有化类的构造器,并给对象属性初始化
    private Season1(String seasonName, String seasonDesc) {
        this.seasonDesc = seasonDesc;
        this.seasonName = seasonName;
    }

    //4.其他诉求:获取枚举类对象的属性
    public String getSeasonName() {
        return seasonName;
    }
    public String getSeasonDesc() {
        return seasonDesc;
    }
//情况1:
//    @Override
//    public void show() {
//        System.out.println("这是一个季节");
//    }
}

集合

Collection接口常用方法、遍历迭代器

package com.atguigu.java1;
/*
一、集合的概述
   1.集合、数组都是对多个对象进行存储操作的结构,简称Java容器
      说明:此时的存储,主要指的时内存层面的存储,不涉及到持久化的存储

   2.数组在存储多个对象方面的特点
     >数组一旦初始化,其长度就确定
     >数组一旦定义好,其元素的类型也就确定了,只能操作指定类型的数据
   2.1数组在存储多个数据方面的缺点
     >一旦初始化,长度不可变
     >数组中提供的方法有限,对于添加,删除、插入数据非常不便,同时效率不高
     >获取数组中实际元素的个数,数组没有现成的属性方法
     >数组存储数据的特点:有序、可重复,对于无序,不可重复的需求不能满足

 二、集合框架
        |------Collction接口:单列集合,用来存储一个一个的对象
               |-------List接口: 有序,可重复的数据  --> “动态数组”
                    |---实现类:ArrayList、LinkList、vector
               |-------Set接口: 无序、不可重复的数据
                    |---实现类: HashSet、LinkedHashSet、TreeSet
        |------Map接口:双列集合,用来存储一对一对的数据(key-value) --->函数
              |---实现类:HashMap、LinkedHashMap、TreeMap、Hashtable、Properties

 三、Collection接口中的方法的使用



 */

import org.junit.Test;

import java.util.*;

public class CollectionTest {
    @Test
    public void test1(){
        Collection coll = new ArrayList();
        //1.add(Object e):将集合e添加到集合coll中
        coll.add("aa");
        coll.add("bb");
        coll.add("123");//自动装箱
        coll.add(new Date());

        //2.size:获取添加的元素的个数
        System.out.println(coll.size());//4

        //3.addAll(Collection c): 将集合c中的元素添加到当前集合中
        Collection coll1 = new ArrayList();
        coll1.add("456");
        coll1.add("cc");
        coll1.addAll(coll);
        System.out.println(coll1.size());//6

        System.out.println(coll1.toString());//[456, cc, aa, bb, 123, Fri Apr 23 08:16:44 CST 2021]

        //5.clear():清空集合元素
        coll.clear();

        //4.isEmpty():判断当前集合是否为空
        System.out.println(coll.isEmpty());//false,5.true

    }
    @Test
    public void test2(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(false);
        coll.add(new String("Tom"));
        coll.add(456);
        coll.add(new Person("Jerry",20));

        //6.contains(Object obj):判断当前集合是否包含对象obj
        //在判断时,会调用obj对象所在类的equals方法。通常自定义类需要重写equals方法
        boolean contains = coll.contains(123);
        System.out.println(contains);//true
        System.out.println(coll.contains(new String("Tom")));//true

        //7.containsAll(Collection c):判断当前集合是否包含集合c中的内容
        Collection coll1 = Arrays.asList(123,456);
        System.out.println(coll.containsAll(coll1));//true

        //8.remove(Object o):从当前集合中移除对象o
        coll.remove("123");
        System.out.println(coll.toString());
        //[123, false, Tom, 456, Person{name='Jerry', age=20}]
        //9.removeall(Collection c):从当前集合中移除,集合c中对象
    }
    @Test
    public void test3(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(false);
        coll.add(new String("Tom"));
        coll.add(456);

//        Collection coll1 = Arrays.asList(123,456,789);
//        //10.retainAll(Collection c):获取当前集合与集合c的交集,并返回给当前集合
//        coll.retainAll(coll1);
//        System.out.println(coll);//[123, 456]

        //11.equals(Object o):返回true,需要当前集合和形参集合的元素都相同
        Collection coll2 = new ArrayList();
        coll2.add(123);
        coll2.add(false);
        coll2.add(new String("Tom"));
        coll2.add(456);
        //coll2.add(new Person("Jerry",20));
        System.out.println(coll.equals(coll2));//true

        //12.hashCode():返回当前对象的哈希值
        System.out.println(coll.hashCode());//8389521

        //13.集合 --->数组:toArray()
        Object[] objects = coll.toArray();
        for(int i= 0;i<objects.length;i++){
            System.out.println(objects[i]);
        }
        //14 数组 --->集合: 调用Arrays.asList()
        List<String> strings = Arrays.asList(new String[]{"aaa", "bb"});

        //15.iterator():返回Iterator接口的实例,用于遍历集合元素
    }
}
package com.atguigu.java1;
public class Person {
    private String name;
    private int age;

    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.atguigu.java1;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/*
  集合元素的遍历操作:使用Iterator接口
  1.内部方法:hasNext()、next()

  2.集合对象每次调用iterator()方法时都会得到一个全全新的迭代器

  3.内部定义了remove(),可以在遍历的时候,删除指定元素

 */
public class IteratorTest {
    @Test
    public void test1(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(false);
        coll.add(new String("Tom"));
        coll.add(456);

        Iterator iterator = coll.iterator();


//        //方式一:
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        //报异常:NoSuchElementException
//        System.out.println(iterator.next());

//        //方式二:不推荐
//        for(int i= 0; i<coll.size();i++){
//            System.out.println(iterator.next());
//        }

        //方式三:推荐
        //hasNext():判断是否还有下一个元素
        while(iterator.hasNext()){
            //next():①指针下移,②将下以后集合位置上的元素返回
            System.out.println(iterator.next());
        }
    }

    //迭代器中remove()
    @Test
    public void test2(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(false);
        coll.add(new String("Tom"));
        coll.add(456);

        Iterator iterator = coll.iterator();
        //删除集合中指定数据
        while(iterator.hasNext()){
            Object obj = iterator.next();
            if("Tom".equals(obj)){
                iterator.remove();
            }
        }
        Iterator iterator1 = coll.iterator();
        while(iterator1.hasNext()){
            //next():①指针下移,②将下以后集合位置上的元素返回
            System.out.println(iterator1.next());
        }

    }
}

 foreach(加强for)

package com.atguigu.java1;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;

/*
    JDK5.0  新增foreach循环,用于遍历集合、数组
 */
public class ForTest {
    @Test
    public void test1(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(false);
        coll.add(new String("Tom"));
        coll.add(456);

        //方式一:迭代器
        //方式二:foreach
        /*
          for(集合元素的类型 变量 :集合对象 )
           内部仍然调用迭代器
         */
        for(Object o:coll){
            System.out.println(o);
        }
    }
    @Test
    public void test2(){
        int[] arr = new int[]{1,2,3,4,5};
        for(int i :arr){
            System.out.println(i);
        }
        //1 2 3 4 5
    }
}

ArrayList、LinkedList、Vector

package com.atguigu.java1;
/*

 |------Collction接口:单列集合,用来存储一个一个的对象
               |-------List接口: 有序,可重复的数据  --> “动态数组”
                    |---实现类:ArrayList:作为List接口的主要实现类,线程不安全,效率高;
                                          使用Object[] elementDate存储
                               LinkedList:底层使用双向链表存储,对于频繁的插入、删除操作,效率比ArrayList高
                               vector:作为List接口的古老实现类,线程不安全,效率低
                                       使用Object[]存储

ArrayList、LinkedList、Vector三者的异同
同:三个类都实现了List接口,存储数据的特点相同:存储有序的、可重复的数据。后续的添加和扩容操作同jdk7.0


1.ArrayList的源码分析:jdk7.0 和 jdk8.0
jdk7.0 情况下:
    ArrayList list = new ArrayList() ;//底层创建长度为10的Object[]
    list.add(123); //elementDate[0] = new Integer(123)
     ...
    list.add(11);//如果此次的添加,导致elementDate的数组容量不够,则默认扩容至原来容量的1.5倍,同时将原有数据复制到新数组中
 结论:建议开发中使用带参的构造器:ArrayList(int capacity)

//查看API的快捷键:ctrl+shift+t
jdk8.0 情况下:
   ArrayList list = new ArrayList() ;//底层Object[] elementData初始化为{},并没有创建长度为10的数组
   list.add(123);//第一次调用add()时,底层创建10的数组,并将123 存入数组中,

jdk7.0的ArrayList的创建方式类似于单例模式饿汉式,jdk8.0的ArrayList的对象创建方式类似于单例模式的懒汉式,
    延迟了数组的创建,节省内存空间。

2.LinkedList的源码分析:
    LinkedList list = new LinkedList();内部声明了Node类型的first和last的属性,默认值为null
    list.add(123);//将123封装到Node中,创建了Node对象

总结:常用方法
增:add(Object e)
删:remove(int index),remove(Object o)
改:set(int index,Object o)
查:get(int index)
插:add(int index,Object o)
长度:size()
遍历: ①Iterator迭代器
      ②foreach
      ③ 普通循环

*/

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ListTest {
    @Test
    public void test1(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("aa");
        list.add(new String("Tom"));
        list.add(123);

        System.out.println(list);//[123, 456, aa, Tom, 123]

        //1.add(int index,Object ele):在指定位置上插入ele元素
        list.add(1,"bb");
        System.out.println(list);//[123, bb, 456, aa, Tom, 123]

        //2.addAll(int index,Collect c):在指定位置上,插入集合c中元素
        List list1 = Arrays.asList(1, 2, 3);
        list.addAll(2,list1);
        System.out.println(list.size());//9

        //3.get(int index):获取指定index位置上的元素
        System.out.println(list.get(0));//123

        //4.indexOf(Object o):判断对象o在当前集合中的首次出现的位置
        int i = list.indexOf(456);
        System.out.println(i);//5
        //5.lastIndexOf(Object o):判断对象o在当前集合中的最后出现的位置

        //6.remove(int index):移除指定index位置上的元素,并返回
        Object remove = list.remove(0);
        System.out.println(remove);//123

        //7.set(int index,Object o):设置指定index位置上的元素为对象o
        list.set(1,"cc");
        System.out.println(list);//[bb, cc, 2, 3, 456, aa, Tom, 123]

        //8.subList(int fromIndex,int toIndex):返回从fromIndex到toIndex位置上的子集合(前闭后开区间)
        List subList = list.subList(2, 4);
        System.out.println(subList);//[2, 3]
    }
}

 HashSet、LinkedHashSet、TreeSet

package com.atguigu.java2;

import org.junit.Test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
/*
 |------Collction接口:单列集合,用来存储一个一个的对象
           |-------Set接口: 无序、不可重复的数据
               |实现类:
                  HashSet:作为Set接口的主要实现类;线程不安全;可以存储null值
                  LinkedHashSet:HashSet子类;遍历其内部元素时,可以按照添加的顺序遍历
                  TreeSet:可以按照添加对象的指定属性,进行排序

1.Set接口中没有额外定义新的方法,使用的都是Collection中的方法

 一、Set:存储无序的、不可重复的元素
 以HashSet说明:
 1.无序性:不等徐随机性。
          存储的数据在底层数组中并非按照底层数组的索引添加。而是根据元素的hash值决定的
 2.不可重复性:保证添加的元素,按照equals()判断时,不能返回ture,即相同的元素只能添加一个。

 二、添加元素的过程:以HashSet为例:
    1.向HashSet中添加元素a,首先调用元素a所在类的hashCode(),计算hash值
    2.此Hash值通过算法计算出在HashSet底层数组中的存放位置(即为索引)
    3.判断数组此位置上,是否已经有元素:
         ①如果此位置无其他元素,则元素a添加成功;
         ②如果此位置有其他元素(或以链表形式存在的多个形式),则比较a与b的hash值:
              如果hash值不相同,则元素a添加成功
              如果hash值相同,进而需要调用元素a所在类的equals()
                    equals返回ture,元素a无需添加;
                    equals返回false,则元素a添加。

  对于添加成功的元素a 与已经存在指定索引位置上元素,以链表的形式存储
  jdk7.0: 元素a放入数组中,指向原来的元素
  jdk8.0:原来的元素在数组中,指向元素a

LinkedHashSet的使用:作为HashSet的子类,在添加数据的同时,还维护了两个引用,记录此数据的前一个和后一个数据
                    对于频繁的遍历操作,LinkedHashSet的效率比HashSet高

 */
public class SetTest {
    @Test
    public void test1(){
        Set hashSet = new HashSet();
        hashSet.add(123);
        hashSet.add(456);
        hashSet.add("aa");
        hashSet.add(new String("tom"));
        hashSet.add("bb");

        Iterator iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
            //aa,bb,tom,456,123
        }
    }
    @Test
    public void test2(){
        LinkedHashSet linkedHashSet = new LinkedHashSet();
        linkedHashSet.add(123);
        linkedHashSet.add(456);
        linkedHashSet.add("aa");
        linkedHashSet.add(new String("tom"));
        linkedHashSet.add("bb");

        Iterator iterator = linkedHashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
            //123,456,aa,tom,bb
        }
    }
}
package com.atguigu.java2;
import org.junit.Test;
import java.util.Iterator;
import java.util.TreeSet;

/*
1.向TreeSet中添加的数据,要求是相同类的对象。
2.两种排序方式:自然排序 和定制排序
3.在自然排序中,比较两个对象是否相同的标准是:compareTo()返回的0,不再是equals()
4.在定制排序中,比较两个对象是否相同的标准是:compare()返回的0,不再是equals()
 */
public class TreeSetTest {
    @Test
    public void test1(){
        TreeSet treeSet = new TreeSet();

        //不能添加不同类的对象
//        treeSet.add(123);
//        treeSet.add(456);
//        treeSet.add("aa");
//        treeSet.add(new String("Tom"));
        //java.lang.ClassCastException

        treeSet.add(123);
        treeSet.add(-123);
        treeSet.add(213);
        treeSet.add(113);
        treeSet.add(321);

        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
            //-123,113,123,213,321
        }
    }
}

TheeSet练习

 

--1
package com.atguigu.exe;
/*
MyDate类包含:
private成员变量year,month,day;
并为每一个属性定义Get\Set方法
 */
public class MyDate {
    private int year;
    private int month;
    private int day;
    public MyDate(){
    }
    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    public int getYear() {
        return year;
    }
    public void setYear(int year) {
        this.year = year;
    }
    public int getMonth() {
        return month;
    }
    public void setMonth(int month) {
        this.month = month;
    }
    public int getDay() {
        return day;
    }
    public void setDay(int day) {
        this.day = day;
    }
    @Override
    public String toString() {
        return "MyDate{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }
}
--2
package com.atguigu.exe;
/*
 定义一个Employee类:
  private 成员变量name,age,birthday,其中brithday为MydDate类的对象
  并为每一个属性定义Get\Set方法
  重写toString方法
 */
public class Employee implements Comparable{
    private String name;
    private int age;
    private MyDate birthday;

    public Employee() {
    }

    public Employee(String name, int age, MyDate birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }
    @Override
    public int compareTo(Object o) {
        if(o instanceof  Employee){
            Employee e = (Employee)o;
            return this.name.compareTo(e.getName());
        }
//        return 0;
        throw  new RuntimeException("传入的类型不一致");
    }
}
--3
package com.atguigu.exe;

import org.junit.Test;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

/*
 创建5个对象,并把这些对象放入TheeSet集合中,分别按照以下两中方式对集合中的元素进行排序,并遍历输出
 1.使Employee实现Comparable接口,并按照name排序
 2.创建TreeSet时,传入Comparator对象,按照生日日期的先后排序
 */
public class EmployeeTest {
    //1.使用自然排序
    @Test
    public void test1(){
        TreeSet treeSet = new TreeSet();

        Employee employee1 = new Employee("liudehua",55,new MyDate(1968,3,4));
        Employee employee2 = new Employee("zhangxueyou",43,new MyDate(1974,4,3));
        Employee employee3 = new Employee("guofucheng",44,new MyDate(1974,7,18));
        Employee employee4 = new Employee("liming",51,new MyDate(1969,1,16));
        Employee employee5 = new Employee("liangchaowei",41,new MyDate(1978,12,21));

        treeSet.add(employee1);
        treeSet.add(employee2);
        treeSet.add(employee3);
        treeSet.add(employee4);
        treeSet.add(employee5);

        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
//            Employee{name='guofucheng', age=44, birthday=MyDate{year=1974, month=7, day=18}}
//            Employee{name='liangchaowei', age=41, birthday=MyDate{year=1978, month=12, day=21}}
//            Employee{name='liming', age=51, birthday=MyDate{year=1969, month=1, day=16}}
//            Employee{name='liudehua', age=55, birthday=MyDate{year=1968, month=3, day=4}}
//            Employee{name='zhangxueyou', age=43, birthday=MyDate{year=1974, month=4, day=3}}
        }
    }

    //使用定制排序
    @Test
    public void test2(){
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
               if (o1 instanceof Employee && o2 instanceof Employee){
                    Employee e1 = (Employee)o1;
                    Employee e2 = (Employee)o2;

                    MyDate b1 = e1.getBirthday();
                    MyDate b2 = e2.getBirthday();

                   int minusYear = b1.getYear() - b2.getYear();
                   if (minusYear != 0){
                       return minusYear;
                      }

                   int minusMonth = b1.getMonth() - b2.getMonth();
                   if (minusMonth != 0){
                           return minusMonth;
                      }

                   return b1.getDay()- b2.getDay();


               }
               // return 0;
                throw new RuntimeException("输入类型不一致");
            }
        });

        Employee employee1 = new Employee("liudehua",55,new MyDate(1968,3,4));
        Employee employee2 = new Employee("zhangxueyou",43,new MyDate(1974,4,3));
        Employee employee3 = new Employee("guofucheng",44,new MyDate(1974,7,18));
        Employee employee4 = new Employee("liming",51,new MyDate(1969,1,16));
        Employee employee5 = new Employee("liangchaowei",41,new MyDate(1978,12,21));

        treeSet.add(employee1);
        treeSet.add(employee2);
        treeSet.add(employee3);
        treeSet.add(employee4);
        treeSet.add(employee5);

        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
         }
//        Employee{name='liudehua', age=55, birthday=MyDate{year=1968, month=3, day=4}}
//        Employee{name='liming', age=51, birthday=MyDate{year=1969, month=1, day=16}}
//        Employee{name='zhangxueyou', age=43, birthday=MyDate{year=1974, month=4, day=3}}
//        Employee{name='guofucheng', age=44, birthday=MyDate{year=1974, month=7, day=18}}
//        Employee{name='liangchaowei', age=41, birthday=MyDate{year=1978, month=12, day=21}}
    }
}

 Map

package com.atguigu.java3;

import org.junit.Test;

import java.util.*;

/*
一 Map结构理解
 |---Map:双列数据,存储key-value对的数据-----类似于数学中的函数
        |---HashMap:作为Map主要的实现类:线程不安全,效率高;可以存储null的key-value
            |---LinkedHashMap:保证在遍历Map元素时,按照添加的元素顺序进行遍历,
                             原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素
                             使用场景:对于频繁的遍历操作
        |---TreeMap:按照添加的key-value进行排序,实现排列遍历,按照(key)排序,则要求key必须是同一个类创建的对象
                    底层使用红黑树,
        |---Hashtable:作为Map古老的实现类;线程安全,效率低;不可存储null的key-value
            |---Properties:常用处理配置文件.key-value都是String类型

 HashMap底层:数组+链表(jdk7.0及以前)
             数组+链表+红黑树(jdk8.0及以后)

二、Map结构的理解:
   Map中的key:无序的 不可重复的,使用Set存储所有的Key ---Key所在类要重写equals和hashCode方法
   Map中的value:无序的、可重复的,使用Collection存储所有的value---value所在类要重写equals
   一个键值对:key-value构成了一个Entry对象。
   Map中的Entry:无序的、不可重复的,使用Set存储所有的Entry

三、HashMap的底层实现原理
jdk7.0:
     HashMap map = new HashMap();
        在实例化以后、底层创建了长度为16的一维数组Entry[] table
    ... 可能已经执行多次put...
     map.put(key1,value1):
         首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值根据散列计算,得到在Entry数组中的存放位置
         如果此位置上的数据为空,此时的key1-value1添加成功,---情况1
         如果此位置上的数据不为空(此位置上,存在一个或多个数据(以链表结构存储)),比较key1和已经存在的一个或多个数据的哈希值
                  如果key1的哈希值与已经存在的数据的哈希值都不同,此时key1-value1添加成功  ---情况2
                  如果key1的哈希值与已经存在的某个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)比较
                           如果equals返回false:此时key1-value1添加成功
                           如果equals返回true:使用value1替换相同的value2,---情况3
     补充:情况2和3 :此时key1-value1和原来的数据以链表的方式存储

     在不断地添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置不为空)时,默认的扩容方式:扩容到原来的2倍,并将原来的元素,放入新的容器中

jdk8.0:相比较jdk7.0在底层实现方面的不同:
       1.new HashMap():底层没有创建一个长度为16的数组
       2.jdk8.0 底层的数组是Node[],而非Entry[]
       3.首次调用put()时,底层创建长度为16的数组
       4.jdk7 底层结构只有:数组+链表。jdk8.0的底层结构:数组+链表+红黑树
          当数组的某个索引位置上的元素以链表像是存在的数据个数 >8 且当前数组的长度 > 64时,此时此索引位置上的所有数据改为红黑树存储

DEFAULT_INITIAL_CAPACITY :HashMap的默认容量,16
DEFAULT_LOAD_FACTOR: HashMap的默认加载因子:0.75
threshold : 扩容的临界值 = 容量 * 加载因子

四、LinkedHashMap的底层实现原理(了解)
   在HashMap的基础上,添加两个指针,指向前一个和后一个元素

五、Map的常用方法
添加、删除、修改操作:
     Object put(Object key,Object value): 添加
     void putAll(Map m):将map中的所有元素添加到现有的map中
     Object remove(Object key):移除key和对应的value,可有返回值为value,当找不到对应的key时,返回的value 是null
     void clear():清空map中的所有元素

     元素查询:
     Object get(Object key):获取指定key对应的value
     boolean containsKey(Object key):是否包含指定的key
     boolean containsValue(Object value):是否包含指定的value
     int size():返回map中key-value对的个数
     boolean isEmpty():判断当前map是否为空
     boolean equals(Object obj):判断档期那map和参数对象obj是否相等

     元视图操作的方法
     Set keySet():返回所有key构成的Set集合
     Collection values():返回所有value构成的collection集合
     Set entrySet():返回所有key-value对构成的Set集合
*/ public class MapTest { @Test public void test1(){ Map map = new HashMap(); map.put(null,null); // map = new Hashtable(); // map.put(null,null);//NullPointerException } @Test public void test2(){ Map map = new HashMap(); //添加 map.put("AA",123); map.put(12,123); map.put("BB",123); //修改 map.put("AA",27); System.out.println(map); //{AA=27, BB=123, 12=123} Map map1 = new HashMap(); map1.put("cc",123); map1.put("dd",123); map.putAll(map1); System.out.println(map);//{AA=27, BB=123, cc=123, dd=123, 12=123} //remove(Object key) Object value = map.remove("cc"); System.out.println(value);//123 System.out.println(map);//{AA=27, BB=123, dd=123, 12=123} //clear map.clear(); System.out.println(map.size());//0 } @Test public void test3(){ Map map = new HashMap(); map.put("AA",123); map.put(12,123); map.put("BB",56); System.out.println(map.get("BB"));//56 System.out.println(map.get(455));//null boolean isExist = map.containsKey("BB"); System.out.println(isExist);//true isExist = map.containsValue(123); System.out.println(isExist);//true } @Test public void test4(){ Map map = new HashMap(); map.put("AA",123); map.put(12,123); map.put("BB",56); //遍历所有的key集:keySet() Set keySet = map.keySet(); Iterator iterator = keySet.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next());//AA BB 12 } //遍历所有的value集:values Collection collection = map.values(); Iterator iterator1 = collection.iterator(); while(iterator1.hasNext()){ System.out.println(iterator1.next());//123 56 123 } // 遍历所有的key-value集:entrySet() // 方式一: Set set = map.entrySet(); for(Object obj:set){ System.out.println(obj);//AA=123 BB=56 12=123 } //方式二: Set entrySet = map.entrySet(); Iterator iterator2 = entrySet.iterator(); while(iterator2.hasNext()){ Object next = iterator2.next(); //entrySet集合中的元素都是entry Map.Entry entry = (Map.Entry) next; System.out.println(entry.getKey()+"-->"+entry.getValue()); //AA-->123 BB-->56 12-->123 } //方式三: //遍历所有的key集:keySet()再通过 map.get(Object key) Set keySet1 = map.keySet(); Iterator iterator3 = keySet1.iterator(); while(iterator3.hasNext()){ Object key = iterator3.next(); Object values = map.get(key); System.out.println("key:"+key+" value:"+values); } //key:AA value:123 //key:BB value:56 //key:12 value:123 } }
Collections
package com.atguigu.java3;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/*
Collections:操作 Collection 和 Map 的工具类

常用方法
revers(list):反转list
shuffle(List):将集合随机排序
sort(List):按照自然排序对list排序
sort(list,Comparator):按照定制排序对list排序
swap(list,int i,int j):将指定list集合中的i和j位置处的元素调换

Object max(Collection):根据自然排序,返回集合中最大的元素
Object max(Collection,comparator):根据指定排序,返回集合中最大的元素
Object min(Collection);根据自然排序,返回集合中最小的元素
Object min(Collection,comparator):根据指定排序,返回集合中最小的元素

int frequency(Collection,Object):返回集合中,obj出现的频率
void copy(List dest,List src):将scr中的内容复制到dest
boolean replaceAll(List list,Object oldval,Object newval):用nesval替换oldval
 */
public class CollectionsTest {
    @Test
    public void test1(){
        List list = new ArrayList();
        list.add(123);
        list.add(45);
        list.add(765);
        list.add(-97);
        list.add(0);
        System.out.println(list);//[123, 45, 765, -97, 0]
        Collections.reverse(list);
        System.out.println(list);//[0, -97, 765, 45, 123]
        Collections.shuffle(list);
        System.out.println(list);//[45, 0, 123, 765, -97]
        Collections.swap(list,1,2);
        System.out.println(list);//[45, 123, 0, 765, -97]
    }
/*
    Collections 类中提供了多个synchronizedXxx()方法,改方法可使将指定集合包装成线程同步的集合,
             从而可以解决多线程并发访问集合时的线程安全问题
 */
    @Test
    public void test2(){
        List list = new ArrayList();
        list.add(123);
        list.add(45);
        list.add(765);
        list.add(-97);
        list.add(0);
        //返回的list1 即为线程安全的集合
        List list1 = Collections.synchronizedList(list);
    }
}

 

 
 
posted @ 2021-04-22 00:53  孫sun  阅读(57)  评论(0编辑  收藏  举报