赵大超的学习周志(五)

本周是Java基础学习的第五周,学习内容包括对正则表达式的进一步补充学习,本周学习的重头戏是对集合框架的学习,集合包括单列集合和双列集合,单列集合的顶层接口为Collection,Collection又分为有序集合List和无序集合Set,List又有常用实现类:ArrayList、LinkedList、Vector、CopyOnWriteArrayList,Set又有常用实现类:HashSet、LinkedSet、TreeSet;双列集合的顶层接口为Map,Map又有常用实现类:HashMap、TreeMap。Collections是对集合进行操作的工具类,能够实现查找、排序、洗牌、交换、反转、线程安全的集合获取等操作;学习了泛型相关的内容,还有JDK8增加的新特性,主要包括对新增日期处理类的学习、对接口默认方法、函数式接口、lambda表达式、StreamAPI的学习。整体来说学习难度不算大,但是却十分重要,其中集合部分是面试中考察的重点,ArrayList和Map是日常开发中十分常用的集合,所以应当熟练掌握本周学习内容。现将其中重点的正则补充的内容和集合部分的相关重要知识点总结如下:

正则表达式

group

捕获组通过从左到右计算其开始括号进行编号。 例如,在表达式((A)(B(C)))中,存在四个这样的组:

  1. ((A)(B(C)))
  2. (A)
  3. (B(C))
  4. (C)

正则表达式三种模式

贪婪模式(greedy)

贪婪模式即从匹配到的位置开始一直往后依次搜索,并且会回溯

String html = "href=\"//cloud.video.taobao.com/video/1098/aaabbc.swf\" href=\"http://www.softeem.com/video/aaa.swf\"";
Pattern pMp4 = Pattern.compile("//cloud.video.taobao.com.+.swf");
Matcher mMp4 = pMp4.matcher(html);
while(mMp4.find()) {System.out.println(mMp4.group());
}

结果:

//cloud.video.taobao.com/video/1098/aaabbc.swf"href="http://www.softeem.com/video/aaa.swf

懒惰模式(reluctant)

通过贪婪模式能够发现,表达式会一直往后搜索,以最后一个匹配到的结尾为终止条件,获取的结果跟预期的存在差距,只需要将正则表达式做如下修改即可匹配到我们需要的资源:

//cloud.video.taobao.com.+?.swf

以上的匹配模式称之为懒惰匹配(勉强模式),寻找最短的匹配
结果:

//cloud.video.taobao.com/video/1098/aaabbc.swf
//cloud.video.taobao.com/video/aaa.swf

独占模式(possessive)

独占模式跟贪婪模式的区别在于,不会回溯,即一直往后搜索会将后续的所有字符串进行匹配

String s = "aabbbccddcaabbbdd";
String regex = "aa.*+dd";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(s);
m.find();
System.out.println(m.group());

结果:

Exception in thread "main" java.lang.IllegalStateException: No match foundat java.util.regex.Matcher.group(Unknown Source)at java.util.regex.Matcher.group(Unknown Source)at com.softeem.lesson20.regex.ReluctantDemo.main(ReluctantDemo.java:27)

集合入门

在java基础阶段,能存储大量相同数据的容器只有数组,但是是数组存在一个弊端,必须指定数组的容量,而且容量无法改变(即数组的长度一旦定义则无法修改),因此我们学习了ArrayList。在jdk1.2之前java官方就提供了一些集合的结局方案:

  • Enumeration(枚举:对集合迭代接口)
  • Vector(向量)
  • Stack(栈)
  • Hashtable(哈希表)
  • Dictionary(字典)
  • Properties(属性表)

以上集合工具在jdk1.2之前就已经存在,但是由于没有一个统一的标准,因此组织混乱,而且也存在部分bug.

从JDK1.2开始java中新增了集合API,用于将所有集合进行统一归纳,形成了两种集合的解决方案:

  • 单例集合
  • 双列集合

单列集合有一个顶层的接口:Collection

双列集合有一个顶层接口:Map

以上结构图为java集合框架组织结构图,所有虚线表示的都是接口或抽象类,实线表示的为针对接口的实现类。java中所有的集合接口以及类都位于java.util包中

Collection

Collection是所有单列集合的顶层接口,在java中存在的有序集合(List)和无需集合(Set)接口都从Collection接口继承,Collection中的常用方法有:

  • public boolean add(E e): 把给定的对象添加到当前集合中 。
  • public boolean addAll(Collection e): 把给定的集合对象添加到当前集合中 。
  • public void clear() :清空集合中所有的元素。
  • public boolean remove(E e): 把给定的对象在当前集合中删除。
  • public boolean contains(E e): 判断当前集合中是否包含给定的对象。
  • public boolean isEmpty(): 判断当前集合是否为空。
  • public int size(): 返回集合中元素的个数。
  • public Object[] toArray(): 把集合中的元素,存储到数组中。
  • public Iterator iterator():获取当前集合的迭代器对象
  • default Stream stream():获取用于进行流式处理的Stream对象(JDK8新增)

由于Collection是一顶层集合接口,因此对于不同类型的集合也存在两个子接口分别进行处理:

  • List:是一个有序的集合,并且允许重复的元素出现
  • Set:是一个无序集合,并且不允许重复元素出现

面试题:
Collection、Collections、Connection什么区别?
答:Collection是所有单列集合的顶层接口;Collections是针对集合进行处理的工具类,比如排序,查找,洗牌,逆序等操作;Connection是java访问数据库技术(JDBC)中的数据库连对象的顶层接口。

List集合

List接口是一个有序的集合,内部允许重复(e1.equals(e2))的元素出现,并且元素的存储顺序是按照添加顺序存储,因此可以通过元素的索引位置快捷的搜索到目标元素;List接口除了包含Collection中的方法之外,还新增了以下常见方法:

  • public E get(int index):根据元素的索引获取指定位置的元素并返回
  • public ListIterator listIterator(): 获取此集合对应的列表(有序)迭代器
  • public E remove(int index):移除指定位置的元素
  • public List subList(int fromIndex,int toIndex):将集合从指定位置进行截取,截取到目标位置,并将返回的数据形成新子List(假分页)

List接口有几个常见的实现类:

  • ArrayList
  • LinkedList
  • Vector

ArrayList

其中最常用的是java.util.ArrayList;ArrayList内部基于数组+数据拷贝的实现初始容量是10,当添加的元素位置超出容量时,会在原数组的容量基础上扩充为1.5倍;由于ArrayList是基于数组的实现,因此在进行数据检索时的效率很高,只需要获取到元素的索引就能快速定位到元素的位置,但是由于数组的长度一旦定义,则无法修改,因此在对ArrayList进行元素的添加和删除的时候会导致数组的容量发生变化,需要频繁的创建新数组的对象,因此在进行添加,删除时效率很低;ArrayList适合做查询不适合做修改(查快改慢)

LinkedList

前面已经了解了ArrayList的实现原理是基于数组结合数组拷贝,但是由于数组的先天性问题:长度一旦定义无法修改,因此ArryList不适合进行频繁的修改(增加,删除)操作;如果需要频繁对容器进行修改操作时,List接口还提供了另一个实现类:LinkedList;

LinkedList是基于双向链表的实现(链表的结构如下),在元素进行增删操作时,只需要修改链表的首尾指针即可轻松实现,因此LinkedList适合用于频繁的修改操作中;但是在进行元素的检索时,只能从链表头,链表尾部依次搜索,查询效率相对较低。(LinkedList改快查慢

常用方法:
实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。这些方法我们作为了解即可:

  • public void addFirst(E e):将指定元素插入此列表的开头。
  • public void addLast(E e):将指定元素添加到此列表的结尾。
  • public E getFirst():返回此列表的第一个元素。
  • public E getLast():返回此列表的最后一个元素。
  • public E removeFirst():移除并返回此列表的第一个元素。
  • public E removeLast():移除并返回此列表的最后一个元素。
  • public E pop():从此列表所表示的堆栈处弹出一个元素。
  • public void push(E e):将元素推入此列表所表示的堆栈。
  • public boolean isEmpty():如果列表不包含元素,则返回true。

在开发时,LinkedList集合也可以作为堆栈,队列的结构使用。

Vector

Vector是在JDK1.0就已经存在的基于动态数组(数组+数组拷贝)的集合实现,Vector是一个线程安全(关键方法上都使用了synchronized修饰)的集合实现,Vector在容量扩充时,增长为原来的2倍(ArrayList是1.5倍);在jdk1.2之后新的集合API出现,Vector被改造为从List集合实现,因此Vector,ArrayList,LinkedList都是源自于List接口。

Vector,LinkedList,ArrayList区别?

  • Vector是老式的集合类,内部基于动态数组实现,容量扩充为原来的2倍,Vector是线程安全的实现
  • ArrayList是JDK1.2之后新增的List集合的实现,内部也是基于动态数组实现,容量扩展为原来的1.5倍,ArrayList是线程不安全的实现(效率高),数据查询较快,修改较慢
  • LinkeadList是JDK1.2之后新增的List集合的实现,内部是基于双向链表实现,也是线程不安全的实现,在进行数据修改方面比较快,数据查询较慢。

Iterator(迭代器)

Iterator接口从jdk1.5之后新增的对集合进行快速遍历的接口,内部实现通常是由集合实现类自身通过内部类的形式来完成。
常用方法:

  • public boolean hashNext():判断迭代器是否存在下一个可以迭代的元素
  • public E next():获取下一个迭代到的元素
  • public void remove():删除当前迭代到的元素

ListIterator

ListIterator从Iterator实现而来,在Iterator的基础上扩充了一些方法:

  • public boolean hasPreviouse():是否存在上一个可迭代元素
  • public E previouse():获取上一个迭代到的元素
  • public void add(E e):通过迭代器向元素中添加一个元素
  • public void set(E e):通过迭代器,修改当前位置的元素

面试问题:
在对集合元素遍历的同时进行删除或者添加操作时会导致一个异常出现:ConcurrentModifactionException,导致原因是因为在集合内部的每一个更新方法中都包含一行代码modCount++


在获取迭代器时会首先将改值缓存到Iterator对象的成员变量中

接下来在对集合使用内部的更新方法发操作元素时每次都会重新修改modCount值,但是迭代器中只会缓存第一次赋予的值(除非调用了迭代器自己的remove);因此一旦使用集合方法更新了元素,都将导致迭代器中检查两个值是否一致,如果不一致则抛出异常(ConcurrentModifactionException)

解决方案:

  1. 使用迭代器自身的remove
Iterator it = list.iterator();
while(it.hasNext()) {Object obj = it.next();it.remove();
}
  1. 在找到满足条件的元素进行操作之后,立马结束循环
for (Object obj : list) {if("lucy".equals(obj)) {              list.remove(obj);//结束循环break;}
}
  1. 当需要更改的元素不止一个时可以,使用如下方式:
//声明临时数组
List temp = new ArrayList();
for (Object obj : list) {if("lucy".equals(obj) || "lily".equals(obj)) { //将符合条件的元素存储到临时集合中temp.add(obj);}
}
//在循环结束后统一处理
list.removeAll(temp);

Collections

Collections是从jdk1.2之后新增用于对集合进行操作的工具类,内部的所有方法都是static;Collections中常见的操作有如下:

  • 二分查找
  • 集合的创建
  • 排序
  • 顺序的打乱

集合排序

Collections中用于实现集合排序的方法有如下两个:

  • sort(List list)
  • sort(List list,Comparator c)

深入研究以上两个方法的实现,不难看出集合中元素的排序主要依靠一下两个接口实现:

  • Comparable
  • Comparator

Comparable & Comparator

​ Comparable接口中提供了一个compareTo方法,该方法需要由排序类进行实现,根据方法内部的实现,Collections中的sort方法会依赖该实现对元素进行排序,使用方式:

public class Student implements Comparable<Student> {private int sno;private String sname;private String sex;private Date birth;private double score;//构造器//setter/geeter//toString@Overridepublic int compareTo(Student s) {//按学号
//      return this.sno - s.sno;//按姓名
//      return this.sname.compareTo(s.sname); //按生日return this.birth.compareTo(s.birth);}}

测试类:

List list = new ArrayList();
list.add(new Student(6, "softeem", "男", new Date(100,1,10), 79.5));
list.add(new Student(4, "admin", "女", new Date(96,2,5), 89.5));
list.add(new Student(2, "bob", "男", new Date(98,0,10), 59.5));
list.add(new Student(1, "tom", "男", new Date(98,2,11), 66.0));
list.add(new Student(5, "jerry", "女", new Date(95,3,22), 39.5));//排序(集合中元素必须实现Comparable接口)
Collections.sort(list);for (Object object : list) {System.out.println(object);
}

运行结果:

Student [sno=5, sname=jerry, sex=女, birth=Sat Apr 22 00:00:00 CST 1995, score=39.5]
Student [sno=4, sname=admin, sex=女, birth=Tue Mar 05 00:00:00 CST 1996, score=89.5]
Student [sno=2, sname=bob, sex=男, birth=Sat Jan 10 00:00:00 CST 1998, score=59.5]
Student [sno=1, sname=tom, sex=男, birth=Wed Mar 11 00:00:00 CST 1998, score=66.0]
Student [sno=6, sname=softeem, sex=男, birth=Thu Feb 10 00:00:00 CST 2000, score=79.5]

对于以上排序的实现关键在于,需要让排序类实现Comparable接口若未对接口实现,则运行Collections.sort(list)将会导致异常

Exception in thread "main" java.lang.ClassCastException: com.softeem.lesson21.collections.Student cannot be cast to java.lang.Comparable
at java.util.ComparableTimSort.countRunAndMakeAscending(Unknown Source)
at java.util.ComparableTimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.ArrayList.sort(Unknown Source)
at java.util.Collections.sort(Unknown Source)
at com.softeem.lesson21.collections.ArrayListTest.main(ArrayListTest.java:53)

以上排序方式需要由排序类实现Comparable接口,在Collections接口中还提供了另一种排序实现方式,即**Collections.sort(list,comparator)**只需要传入集合与对应的排序比较器对象即可:

public class User {private int id;private String name;private Date regTime;private int vipLevel;//构造器//setter/getter//toString
}

测试类:

List<User> list= new ArrayList<>();
list.add(new User(1105, "softeem", new Date(), 5));
list.add(new User(1109, "rose", new Date(), 4));
list.add(new User(1106, "jack", new Date(), 5));
list.add(new User(1107, "docker", new Date(), 3));
list.add(new User(1108, "admin", new Date(), 1));
list.add(new User(1102, "bobo", new Date(), 2));//方式一:
Collections.sort(list,new Comparator<User>() {@Overridepublic int compare(User u1, User u2) {return u1.getName().compareTo(u2.getName());}
});
//方式二:观察sort方法的源码即可发现还可以以如下方法进行排序
list.sort(new Comparator<User>() {@Overridepublic int compare(User u1, User u2) {return u2.getVipLevel() - u1.getVipLevel();}
});//方式三:
Collections.sort(list, new MyCompartor());

方式三的比较器定义:

 public class MyCompartor implements Comparator<User>{@Override
public int compare(User u1, User u2) {return u1.getId() - u2.getId();
}
}

扩展:中文排序(Pinyin4j)

通过以上的两个接口实现排序只要选择合适接口实现,并通过调用Collections的sort方法即可完成排序,但是对于一些特殊的需求:比如中文排序,JDK提供的解决方案比较受限,因此需要第三方的技术来实现对于中文的排序;这里可以使用开源的对中文字符处理的框架(插件):Pinyin4j(pinyin for java);这个插件提供了用于将中文汉字转换为汉语拼音的API,具体使用方式分为以下步骤:

  1. 将插件构建到项目中
    pinyin4j-2.5.0.jar

  2. 使用pinyin4j

    //将中文字符转换为拼音
    String[] s = PinyinHelper.toHanyuPinyinStringArray('中');
    for (String string : s) {System.out.println(string);
    }//执行结果:
    //zhong1
    //zhong4
    

使用前需要导入:

   import net.sourceforge.pinyin4j.PinyinHelper;

排序方式

思路:

  1. 将中文字符的每一位获取,并转换为拼音拼接陈新的字符串
  2. 直接使用String类中已实现的comparaTo方法进行比较返回整数值即可
List<String> list = new ArrayList<>();
list.add("王老师"); //wang
list.add("阿老师"); //a
list.add("柴老师"); //chai
list.add("窦老师"); //dou
list.add("刘老师"); //liuCollections.sort(list,new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {String name1 = "";String name2 = "";for(int i = 0;i<s1.length();i++) {char c = s1.charAt(i);String s = PinyinHelper.toHanyuPinyinStringArray(c)[0];name1 += s;}for(int i = 0;i<s2.length();i++) {char c = s2.charAt(i);String s = PinyinHelper.toHanyuPinyinStringArray(c)[0];name2 += s;}//将转换成汉语拼音的字符串进行比较return name1.compareTo(name2);}
});System.out.println(list);

执行结果:

[阿老师, 柴老师, 窦老师, 刘老师, 王老师]

Set集合

之前我们已经学习过了List集合,List具备以下特点:

  • 有序(存储顺序跟添加顺序一致)
  • 允许重复(可以添加重复数据 e1.equals(e2))
  • 允许空元素

虽然对于大多数应用场景下List集合都非常实用,但是对于一些特殊需求,List集合会暴露明显的问题,比如对集合中的元素去除重复,对于List集合必然就会需要涉及到集合遍历,影响到程序的运行效率;因此对于这种需求Collection接口还提供了另一种子接口:Set

Set也是从jdk1.2开始出现,对比List集合,Set集合特点如下:

  • 元素的存储顺序与添加顺序无关(无序)
  • 内部不允许重复元素

Set由于是一个接口,因此对于该接口,集合框架内部提供了一些常见的实现类:

  • HashSet
  • LinkedHashSet
  • TreeSet

注意事项:
由于Set集合的实现中没有针对数组结构的实现,因此内部的元素也不存在索引

常用方法:

  • add(Object obj) 向集合中添加元素
  • addAll(Collection c) 将一个集合添加到当前集合中
  • clear() 清除集合中所有元素
  • isEmpty() 判断集合是否为空集合(size = 0)
  • remove(Object obj) 删除指定元素
  • iterator() 获取当前集合的迭代器对象
  • size() 获取集合中元素个数

HashSet

HashSet是基于哈希表的实现(内部实际就是一个HashMap),内部的元素存储根据调用元素的hashCode方法实现,由于对象的存储基于hashCode算法,因此如果多个对象的的hashCode值是一致的,则集合中只会存储一个(在重写hashCode方法时也必须要同时重写equals

User类:

public class User {private int id;private String name;private String pwd;//构造器//setter/getter//toString@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + id;result = prime * result + ((name == null) ? 0 : name.hashCode());result = prime * result + ((pwd == null) ? 0 : pwd.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;User other = (User) obj;if (id != other.id)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;if (pwd == null) {if (other.pwd != null)return false;} else if (!pwd.equals(other.pwd))return false;return true;}
}

测试类:

Set set = new HashSet();
set.add(10);
set.add(7);
set.add(9);
set.add(8);
set.add(3);
set.add(5);
set.add(10);
set.add(new User(1,"softeem","123"));
set.add(new User(1,"softeem","123"));

输出结果:

[3, User [id=1, name=softeem, pwd=123], 5, 7, 8, 9, 10]

TreeSet

在前面HashSet中,元素虽然不允许重复,但是由于存储顺序是无需的,在对于一些需要排序的需求场景下,HashSet也暴露了功能不足的问题,因此 ,Set集合中针对该需求,还提供了另一种能够实现排序的Set实现:TreeSet;TreeSet内部实现原理是基于二叉树中的红黑树实现,使用TreeSet的前提:

  • 元素必须是同一种数据类型
  • 元素必须实现过Comparable接口
Set set = new TreeSet();
set.add(18);
set.add(27);
set.add(45);
set.add(8);
set.add(32);
set.add(50);
set.add(10);System.out.println(set);

结果:

[8, 10, 18, 27, 32, 45, 50]

注意事项:

TreeSet内部对于元素的去除重复根据重写的comparaTo方法来决定,如果多个对象的comparaTo方法返回值是一致的,则集合中只会存储一个:

public class User implements Comparable<User>{private int id;private String name;private String pwd;//构造器//getter/setter//toString/*** 实现排序比较规则*/@Overridepublic int compareTo(User o) {return name.compareTo(o.name); }  }

测试:

Set set = new TreeSet();
set.add(new User(1,"softeem","123"));
set.add(new User(2,"softeem","456"));
System.out.println(set);

输出结果:

[User [id=1, name=softeem, pwd=123]]

TreeSet中的元素对应的类如果未实现Comparable接口,则会抛出运行时异常:

java.lang.ClassCastException

因为内部会将元素强制转换为Copparable对象

LinkedHashSet

HashSet是基于hash算法实现的元素的存储,但是由于不同的对象hash值存在差异,因此元素的存储顺序不一定按添加顺序来;在实际开发中如果需要按元素的添加顺序存储,并且要保证元素不重复,因此可以使用由Set集合提供的另一个实现:LinkedHashSet;LinkedHashSet是从HashSet继承而来,内部的实现原理实际是基于LinkedHashMap.

Set set = new LinkedHashSet();
set.add("hello");
set.add(true);
set.add(3.14);
set.add(100);
set.add(new User());Iterator it = set.iterator();
while(it.hasNext()) {System.out.println(it.next());
}

结果:

hello
true
3.14
100
User [id=0, name=null, pwd=null]

面试题:
HashSet,TreeSet和LinkedHashSet区别?
HashSet是Set集合基于hash表(散列表)的实现元素存储,内部的元素存储顺序跟hash值有关,如果多个对象的hash一致(equals也一致)则集合会认为是重复元素,因此不会加入集合中;HashSet内部实现原理是基于HashMap的。
TreeSet是Set集合基于红黑树(二叉排序树中的特殊平衡二叉树),内部元素的存储顺序是根据元素对应类实现的Comparable接口中compareTo方法进行存储,如果多个对象的comparaTo方法返回值一致,则TreeSet会认为是重复元素,因而不会重复存储;TreeSet实际就是基于TreeMap的实现
LinkedHashSet是HashSet的子类,内部基于单链表的实现,元素的存储顺序按照添加顺序来存储,是一个有序的set集合;内部实现原理使用了LinkedHashMap。

Map集合

之前所学习到的List集合以及Set集合都是直接从Collection继承而来的单列子集合,另外,java的集合框架中也提供了另一种特殊的集合接口:双列集合:Map

Map集合是由键值对结构组成,通常由一个唯一键对应一个值,集合中存储的元素键不允许重复,但是值可以重复,Map集合是一个键值对集合的顶层接口,常见的实现类主要有以下:

  • HashMap
  • TreeMap
  • LinkeHashMap
  • ConcurrentHashMap

虽然Map集合是一个键值对结构,但是实际内部存储的每一个元素都是一个Entry对象,而Entry内部包含两个属性,一个是Key,另一个是Value

Map常见方法:

  • clear() 清除Map集合中的所有元素
  • containsKey(Object key) 判断集合中是否包含指定的键
  • containsValue(Object value) 判断集合中是否包含指定的值
  • entrySet() 返回当前Map集合中Entry的Set集合
  • get(Object key) 根据键获取值
  • put(Object k,Object v) 向集合中添加元素(键值对)
  • keySet() 获取键的Set集合
  • remove(Object key) 根据键删除指定的元素
  • size() 返回该Map集合中元素的个数
  • values() 返回Map集合中所有的值集合(Collection)

HashMap

HashMap是Map中最常用的一个实现类,内部实现是基于数组+链表(JDK1.8之前;JDK1.8之后改为使用数组+链表+红黑树实现);元素的存储按照键值对的方式,存储顺序根据键的hashCode(包括equals)计算之后存储
HashMap的初始容量是16默认的加载因子是0.75(降低hash碰撞的概率),HashMap的扩容方式为原来的2倍;实现原理:

  • 1.8之前使用的是数组和链表实现,默认情况下通过计算元素的hash值,然后和16取余(实际: hash & (length-1)),再根据计算结果将元素(Map.Entry)存储对应的数组中,如果该位置已经存在元素,则此时引入链表,采用头插法将最新的元素插入到链表头部
  • JDK1.8之后使用数组+链表+红黑树(平衡排序二叉树)实现,红黑树的加入有特定前提
    • 数组的长度必须超过64
    • 链表深度必须大于8


HashMap的使用:

//创建一个基于HashMap的Map接口实现对象
Map map = new HashMap();
map.put("a", "admin");
map.put("r", "rose");
map.put("k", "kaven");
map.put("m", "mulan");
map.put("n", "novar");
map.put("x", "xiaoming");
//集合中存储重复的键时会覆盖之前存储的元素
map.put("a", "rose");
map.put("y", "rose");
map.put(14, "14");
map.put(30,"300000");
map.put(46,"46");System.out.println(map);
//根据键获取值
System.out.println(map.get("k"));
System.out.println("a".hashCode() % 16);
System.out.println("r".hashCode() % 16);
System.out.println("k".hashCode() % 16);
System.out.println(("m".hashCode() & 15) + "--" +("m".hashCode() % 16));
System.out.println("n".hashCode() % 16);
System.out.println("x".hashCode() % 16);
System.out.println(new Integer(14).hashCode() % 16);
System.out.println(new Integer(30).hashCode() % 16);
System.out.println(new Integer(46).hashCode() % 16);
//判断map集合中是否包含指定的键
System.out.println(map.containsKey("a"));//
//判断map集合中是否包含指定的值
System.out.println(map.containsValue("rose"));//获取Map集合中所有的Entry元素的Set集合
Set<Map.Entry> set = map.entrySet();
for (Entry e : set) {System.out.println(e.getKey()+"/"+e.getValue());
}Map map2 = new HashMap();
map2.put("100", "hellowrold");
map2.put(true, "true");
map2.put(3.14, "314");
map2.put('c', "cccaaa");
map2.put(50, "hellowrold");//
//获取Map的键集
Set set = map2.keySet();
System.out.println(set);
//根据键移除指定元素
Object obj = map.remove('c');
System.out.println(obj);System.out.println(map2);//获取Map的值集
System.out.println(map2.values());

TreeMap

Map集合另外针对于排序的需求还有一个TreeMap的实现类,该类内部基于红黑树(平衡排序二叉树)实现;内部的元素存储顺序,由键对应的类型实现Comparable接口后,通过重写comparaTo方法实现;TreeMap的使用需要满足以下两个条件:

  • key的类型必须一致
  • key对应的类必须实现Comparable接口

TreeMap不允许空键出现

Map map = new TreeMap();
map.put("hello", "helloworld");
map.put("rose", "helloworld");
map.put("jack", "helloworld");
map.put("softeem", "helloworld");
map.put("admin", "helloworld");System.out.println(map);

对于以上代码,TreeMap会使用键对应的类型中的comparaTo方法来完成对于元素的排序存储

对于复杂类型的key,使用方式:

public class Student implements Comparable<Student>{private int sno;private String sname;private Date birth;private double score;//构造器//setter/getter//toString@Overridepublic int compareTo(Student s) {return (int)(this.score - s.score);}}

测试:

Map map = new TreeMap();
map.put(new Student(104,"孙悟空",new Date(),65), "helloworld");
map.put(new Student(103,"猪八戒",new Date(),75), "helloworld");
map.put(new Student(101,"沙和尚",new Date(),55), "helloworld");
map.put(new Student(105,"唐僧",new Date(),45), "helloworld");
map.put(new Student(106,"小白龙",new Date(),55), "helloworld");
map.put(new Student(109,"白骨精",new Date(),77), "123");Set set = map.keySet();
for (Object obj : set) {System.out.println(obj);
}

结果:

Student [sno=105, sname=唐僧, birth=Wed Nov 25 15:46:24 CST 2020, score=45.0]
Student [sno=101, sname=沙和尚, birth=Wed Nov 25 15:46:24 CST 2020, score=55.0]
Student [sno=104, sname=孙悟空, birth=Wed Nov 25 15:46:24 CST 2020, score=65.0]
Student [sno=103, sname=猪八戒, birth=Wed Nov 25 15:46:24 CST 2020, score=75.0]
Student [sno=109, sname=白骨精, birth=Wed Nov 25 15:46:24 CST 2020, score=77.0]

根据以上结果得知,TreeMap中去除重复的原则是根据key类型中实现的comparaTo方法来实现,如果该方法返回值为0,则认为比较的两个对象重复,则将参数对象舍弃

Hashtable

Hashtable也是键值对结构的集合解决方案,从jdk1.0之后就已经存在,从老式的集合类java.util.Dictionary继承而来初始长度是11(HashMap是16),Hashtable是线程安全实现(HashMap是线程不安全的实现);Hashtable不允许空键值出现(HashMap允许)

LinkedHashMap

LinkedHashMap是基于链表的HashMap实现,本身也是从HashMap继承而来,通过链表实现内部元素的存储顺序保持与添加顺序一致

赵大超的学习周志(五)相关推荐

  1. 赵大超的学习周志(八)

    赵大超的学习周志(八) 本周是Java学习的第八周,主要是对前端知识的学习,其中学习的内容包括H5和CSS,具体学习了H5中的各种标签元素,CSS中的使用方式,最后是对网页的设计和布局的学习,综合运用 ...

  2. 赵大超的学习周志(十)

    赵大超的学习周志(十) 本周是Java学习的第十周,主要是对Javascript的进一步学习和对jQuery的学习,其中包括进一步学习的BOM,JSON字符串,Ajax基础,jQuery入门基础,选择 ...

  3. 赵大超的学习周志(二)

    赵大超的学习周志(二) 本周是Java基础学习的第二周,学习内容包括对数组的复习和强化学习,对面向对象编程的初步学习,学习了类和对象,方法的相关使用知识,着重了解了面向对象的封装和继承两个属性,初步形 ...

  4. 赵大超的学习周志(六)

    赵大超的学习周志(六) 本周是Java学习的第六周,主要是对数据库的学习,其中包括对数据库的基本了解,MySQL的了解和使用,SQL语句的学习,对常用的sql数据类型的学习,对查询语句的学习和掌握是重 ...

  5. 赵大超的学习周志(七)

    赵大超的学习周志(七) 本周是Java学习的第七周,主要是对JDBC的学习,其中包括对JDBC的概述,JDBC的六大步骤,,基本的CRUD,简易的DBUtils封装,Statement与Prepare ...

  6. 赵大超的学习周志(四)

    赵大超的学习周志(四) 本周是Java基础学习的第四周,主要是对异常进行了学习,最主要的是对各种常用类的学习,最后还学习了对正则表达式的使用.异常部分主要包括系统异常和自定义异常:常用类的学习包括了B ...

  7. 学习周志(8.21)

    本周开始了C++语言的学习,下面是C++基础语法学习内容的一些整理:命名空间.输入输出.带默认值的函数.带占位参数的函数.函数重载.C++引用.new与delete. 1.命名空间: 命名空间用于解决 ...

  8. python周志_Python学习周志—第一周(入门知识)

    变量和简单数据类型 使用方法修改字符串 title() 首字母大写 upper() 字母大写 lower() 字母小写 split() 通过指定分隔符对字符串进行切片 加号(+)来合并字符串 使用制表 ...

  9. Python学习周志—第一周(入门知识)

    变量和简单数据类型 使用方法修改字符串 title() 首字母大写 upper() 字母大写 lower() 字母小写 split() 通过指定分隔符对字符串进行切片 加号(+)来合并字符串 使用制表 ...

最新文章

  1. lookup函数和vlookup_5个实用案例告诉你,为什么说Lookup函数比vlookup更简单
  2. fx-4500科学计算机用法,应用CASIOfx-4500PA计算器计算LC50的方法
  3. windows下pycharm连接vagrant的python环境
  4. 互联网1分钟 |1224
  5. YBTOJ:伞兵空降(二分图匹配)
  6. 到2025年将保持不变的热门流行技术
  7. 用css实现模仿火狐社区的一个提示框
  8. Coding the Matrix Week 0 作业
  9. 计算机页面排版的笔记,爱记笔记却懒得排版?这款笔记 App 为你准备了最实用的经典模板:格子笔记...
  10. C语言中程序设计题 计算机二级考试
  11. 如何刷新微信服务器小程序版本,微信小程序线上更新版本流程及如何运用
  12. python拼多多推广多店爬虫
  13. OCR识别通过某瓣人机验证
  14. 初识Android 制作一个简单的记账本
  15. win7局域网计算机 慢,Win7系统局域网访问文件速度缓慢怎么办
  16. v2rayN断网修复
  17. html5怎样兼容ie浏览器版本,HTML5 兼容IE浏览器
  18. Maven虐我千百遍,我待Maven如初恋!
  19. matlab实验——信号和噪声产生及其功率谱分析
  20. Zookeeper-开源客户端 之 Curator

热门文章

  1. linux系统模块卸载顺序,Linux系统下以模块方式安装卸载文件系统
  2. 中专是不是学计算机就只要学理科,中专计算机是理科?
  3. [享学Eureka] 四、Eureka配置之:EurekaClientConfig客户端配置
  4. 硬盘 不属于Rom RAM
  5. CPS/CPA自动结算系统
  6. 浏览器占满整个屏幕_如何实现div布满整个浏览器,全屏
  7. 10个专业汽车摄影lr预设
  8. crm系统是什么很棒ec实力_用友CRM系统与EC哪个更好?
  9. 【Unity3DRPG入门学习笔记第二卷】Build Level 熟悉基本工具
  10. C#文件操作 File(静态类)