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); } }
虽不能至,心向往之