精要分析,两大集合框架Map和Collection

2019-09-24 12:28 来源:未知

两大框架图解

图片 1
图片 2
图片 3
图片 4

Java基础抓好之集合篇(模块回想、精要解析),java精要

 

千里之行,始于足下。把人家的成为温馨,再把温馨的享受给旁人,那也是三回晋级的进程。本文的指标是以一篇小说从总体把握集结类别又不失一些细节上的完成,高手路过。

Collection接口

由第一张图,咱们能够领略,Collection接口的子接口有三种,分别是List接口,Set接口和Queue接口

会集的功能与性情

Java是一门面向对象语言,数据多了用对象封装存储(比方,人有姓名、年龄、性别等数据音讯,我们就悬空三个Person对象来封装存款和储蓄),对象多了又用什么来存款和储蓄吗?集结,集结正是用来积攒对象的。

 

会集的特征就是适用于积存对象何况能够储存不一样类别的靶子,群集的长短是可变的。

 

List接口

允许有双重的因素,成分根据增加的相继举办排序

  1. 接口方法

    • void add(int index,Objext o) 在集合的指定位置插入元素
    • Object get(int index) 返回集合中某个指定位置的元素
    • int indexOf 返回第一次出现该元素的索引,如果不包含此元素,返回-1
    • int lastIndexOf 返回最后一次出现该元素的索引,如果不包含此元素,返回-1
    • Object remove(int index) 移除集合某个索引的元素
    • Object set(int index,Object o) 用指定的元素替换集合中某个指定下标的数据元素
  2. 接口完成类的采用

    • ArrayList
      增加产量方法:
      addFirst
      getFirst
      removeFirst
      addLast
      getLast
      removeLast

      特色:在蕴藏形式上是使用数组举办顺序存款和储蓄

        List list = new ArrayList();  List<泛型> list = new ArrayList<>();
      
    • LinkedList

      本性:在存款和储蓄格局上是选择链表举行链式存款和储蓄

        LinkedList<> list = new LinkedList<>();
      

PS:由于ArrayList是使用数组进行仓库储存的,所以添日元素也许是去除成分时,要求批量运动元素,所以品质很糟糕。但查询元素的时候,能够透过下标直接开展拜会,所以遍历元素或私行走访成分的时候效能高。
而LinkedList与ArrayList相反

晤面框架图

聚拢既然能储存不相同品种的的指标,那么集中类别中必然有例外档案的次序的器皿,集结中首要有List、Set、Map二种容器,每个容器的数据结构都分裂。集合类其他类、接口很多,方便纪念,我们将上边那几个相对轻巧的汇集框架图分为从5个模块来上学:

1.Collection集合

2.Map集合

3.晤面遍历

4.集聚比较

5.集合工具类

 

 

先对图做一下分析:

l 点线框表示接口

l 达成框表示具体的类

l 带有空心箭头的点线表示三个切实可行的类完结了八个接口

l 实心箭头表示某一个类能够更改箭头所指向的类

l 常用的容器用藏蓝粗线表示

 

Set接口

差异意有双重的成分,成分未有各种

  1. 接口方法

    add clear contains remove
    和事先的List大致,这里就相当的少说

  2. 接口达成类的运用

    • HashSet

      下边包车型地铁图纸很显明,展现了并未有再度成分的准绳
      图片 5

      一般选择的话照旧选取泛型使用

        Set<Book> books = new HashSet<>();
      
    • TreeSet

      由事先介绍的第四张图可以看到,TreeSet既承接了Set接口,也一连了SortedSet接口

      图片 6

      从未选拔泛型,暗许使用的是String类型,String类达成了Comparable接口,默许是按字典排序,不过图中明显未有兑现排序?不知道。。

      小编利用马耳他语初阶,本事兑现排序

      图片 7

    • Set集结遍历
      //Iterator
      Iterator iterator = set.iterator();
      while (iterator.hasNext{
      System.out.println(iterator.next;
      }
      //foreach
      for (String s:set) {
      System.out.println;
      }

      ### Queue接口

非常少使用。。

Collection集合

Map接口

使用键值对(key value)进行数据存储,key与value是一种映射关系
  1. 接口方法
    • Object put(Object key,Object value) 将二个键值对存到Map中
    • Object get(Object key) 由key获得value
    • Object remove(Object key) 删除该键值对
    • Set keyset() 再次来到当前包罗当前map的享有key的Set群集
    • Collection values() 再次回到当前带有当前map的持有value的Collection集合
    • boolean containsKey(Object key) 是还是不是带有有些key
    • boolean containsValue(Object Value) 是不是包罗有些Value
    • int size() 重回当前map群集键值对的个数
  2. 接口达成类的使用

    • HashMap的使用

      Map<String,String> map = new HashMap<>();
      Map<Integer,String> map = new HashMap<>();

    PS: 一般在初阶证明键值对的项目,要是在背后评释的话,十分大大概会报错

    • TreeMap的使用

      Map<String,String> map = new TreeMap<>();

    与事先的TreeSet一样,TreeMap也是贯彻了SortedMap借口,带有排序,默许是遵照key的数值自然排序

Collection接口

Collection是二个接口,是惊人抽象出来的集聚,饱含了聚众的基本操作:增添、删除、清空、遍历、是不是为空、获取大小等等。定义如下:

public interface Collection<E> extends Iterable<E> {}

Collection接口下第一有八个子接口:List和Set。

List接口

List是Collection的四个子接口,List中的成分是严守原地的,可以另行,有目录。

概念如下:

public interface List<E> extends Collection<E> {}

 

 

List是持续于Collection接口,它自然就包蕴了Collection中的全体函数接口,由于List有谈得来的性状(素是有序的,能够重新,有目录),因而List也可能有友好特有的有的操作,如上大青框框中的。List特有的操作首借使富含索引的操作和List本身的迭代器(如上海体育场合)。List接口的常用完毕类有ArrayList和LinkedList。

 

ArrayList

ArrayList是List接口的二个切实可行的落到实处类。ArrayList的平底数据结构是数组结构,也正是贰个动态数组。ArrayList的风味是随便询问速度快、增加和删除慢、线程不安全。ArrayList和Vector的分别是:Vector是线程安全的(synchronized完毕)。定义如下:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{}

l ArrayList 承接AbstractList,AbstractList是对部分国有操作的再次抽象,收取部分特色操作,如基于目录操作成分,生产迭代器等。

l ArrayList 完毕了RandmoAccess接口,即提供了自由寻访功效,能够透过元素的目录飞快获得成分对象。

l ArrayList 完成了Cloneable接口,即覆盖了函数clone(),能被克隆。

l ArrayList 完结java.io.Serializable接口,那意味ArrayList接济类别化,能透过连串化去传输。

 

ArrayList源码剖判总计(源码略,提议先全部会认知识再张开源码对着看):

 

l 能够经过构造函数钦命ArrayList的体积大小,若不点名则暗中认可是10。

l 增添新成分时,体量不足以容纳全体要素时,会另行创造一个新的能够容纳全体因素的数组,把旧数组中的成分拷贝到新的数组中并赶回新的数组。增量具体看源码。

l 增多的新因素增添到数组末尾。

l 查找、删除成分运用equals方法相比较对象。

l ArrayList的克隆函数,正是将全部成分克隆到二个数组中。

l ArrayList的类别化,即透过java.io.ObjectOutputStream将ArrayList的长度和每贰个因素写到输出流中,或然通过java.io.ObjectInputStream从输入流中读出长度和每叁个成分到四个数组中。

LinkedList

LinkedList是List接口的一个有血有肉的贯彻类。LinkedList底层数据结构是双向的链表结构,能够算作宾馆可能队列来使用。LinkedList的特点是增加和删除速度快捷,顺序查询功能较高,随机询问稍慢。定义如下:

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{} 

l LinkedList 是后续AbstractSequentialList,AbstractSequentialList是AbstractList的一个子类。

l LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。

l 同ArrayList,LinkedList一样支撑克隆和体系化。

 

LinkedList 源码深入分析计算(源码略,提议先全体会认知识再打开源码对着看):

 

l LinkedList的面目是多少个双向链表,各有一个头节点和尾节点,每二个节点皆有个数据域、三个针对性上二个节点的指针域、四个针对上下一个节点的指针域。

l 添比索素时,将成分增多到双向链表的末端。

l 查找、删除成分时,使用equals方法相比较对象。

l 依据目录查找成分时,若索引值index < 双向链表长度的约得其半,则从表头未来查找,不然从表尾往前找。

l LinkedList的仿造和种类化原理同ArrayList。

l LinkedList达成了Deque,Deque接口定义了在双端队列两端访谈成分的点子,每一个格局都存在两种样式:一种是在操作退步时抛出拾叁分,另一种是再次来到贰个奇特值(null 或 false)。

l LinkedList有谈得来特有的迭代器ListIterator。

l LinkedList空中楼阁扩容增量的难题。

List应用比方

LinkedList达成仓库和队列

LinkedList能够算作仓库和队列使用,因为达成了Deque接口,Deque接口提供了有个别了出栈入栈和出队入队的格局。

图片 8class MyQueueStack { private LinkedList link; MyQueueStack() { link = new LinkedList(); } public void add(Object obj) { link.addFirst(obj); } public Object remove() { //return link.removeLast();//队列 return link.removeFirst();//栈 } public boolean isNull() { if(!link.isEmpty()) { return false; } return true; } } public class LinkedListQueueStack { public static void main(String[] args) { MyQueueStack q = new MyQueueStack(); q.add("001"); q.add("002"); q.add("003"); while(!q.isNull()) System.out.println(q.remove()); } } 队列运营结果: 001 002 003 栈运维结果: 003 002 001 View Code

ArrayList保障唯一性

List中的元素是足以重复的,能够透过重写equals方法实现独一性。下边是ArrayList完毕要素去重(依附equals)的一个事例。

 

图片 9class Teacher { private String name; private String age; Teacher(String name,String age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } @Override public boolean equals(Object obj) { if(!(obj instanceof Teacher)) { return false; } Teacher p = (Teacher)obj; System.out.println("调用equals比较" + p.name + "与" + this.name); return p.name.equals(this.name) && p.age.equals(this.age); } } public class ArrayListDuplicate { public static void main(String[] args) { ArrayList al = new ArrayList(); al.add(new Teacher("zhangsan","20")); al.add(new Teacher("lingsi","21")); al.add(new Teacher("wangwu","22")); al.add(new Teacher("wangwu","22")); print("-----------原始ArrayList----------"); Iterator it = al.iterator(); while(it.hasNext()) { Teacher obj = (Teacher)it.next(); print(obj.getName() + "-" + obj.getAge()); } print("-----------删除重复成分----------"); ArrayList al2 = removeSameObj(al); Iterator it2 = al2.iterator(); while(it2.hasNext()) { Teacher obj = (Teacher)it2.next(); print(obj.getName() + "-" + obj.getAge()); } print("-----------删除lingsi成分----------"); al2.remove(new Teacher("lingsi","21")); Iterator it3 = al2.iterator(); while(it3.hasNext()) { Teacher obj = (Teacher)it3.next(); print(obj.getName() + "-" + obj.getAge()); } } public static ArrayList removeSameObj(ArrayList al) { ArrayList newAl = new ArrayList(); Iterator it = al.iterator(); while(it.hasNext()) { Object obj = it.next(); if(!newAl.contains(obj)) { newAl.add(obj); } } return newAl; } public static void print(Object obj) { System.out.println(obj); } } 运行结果: -----------原始ArrayList---------- zhangsan-20 lingsi-21 wangwu-22 wangwu-22 -----------删除重复成分---------- 调用equals相比较zhangsan与lingsi 调用equals相比zhangsan与wangwu 调用equals比较lingsi与wangwu 调用equals比较zhangsan与wangwu 调用equals比较lingsi与wangwu 调用equals相比wangwu与wangwu zhangsan-20 lingsi-21 wangwu-22 -----------删除lingsi成分---------- 调用equals比较zhangsan与lingsi 调用equals相比较lingsi与lingsi zhangsan-20 wangwu-22 View Code

从运维结果中得以阅览,调用list的contains方法和remove方法时,调用了equals方法开展比较(List集合中判定成分是不是等于依附的是equals方法)

 

Set接口

Set是Collection的贰个子接口,Set中的成分是冬日的,不可以重复。定义如下:

public interface Set<E> extends Collection<E> {}

Set是一而再于Collection接口,它自然就隐含了Collection中的全体函数接口。Set接口的常用达成类有HashSet和TreeSet。实际上HashSet是透过HashMap实现的,TreeSet是因此TreeMap达成的。在此只轻易列举它们的部分特征,能够一贯看下边包车型大巴HashMap和TreeMap的深入分析,明白了HashMap和TreeMap,也就掌握了HashSet和TreeSet。

HashSet

HashSet是Set接口的一个切实的完结类。其特征是因素是严节的(抽出顺序和存入顺序不自然同样),不可以重复。定义如下:

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{}

l HashSet承接AbstractSet,AbstractSet抽象了equals()、hashCode()、removeAll()四个点子。

l HashSet完成了Cloneable,Serializable接口以便帮忙克隆和种类化。

l HashSet保险元素独一性信赖equals()方法和hashCode()方法。

 

TreeSet

TreeSet是Set接口的二个现实的兑现类。其天性是因素是雷打不动的,不可能另行。定义如下:

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
{}

l TreeSet承袭AbstractSet,AbstractSet抽象了equals()、hashCode()、removeAll()两个法子。

l TreeMap完结了NavigableMap接口,支持一多级的导航方法,比如再次回到有序的key集结。

l TreeSet达成了Cloneable,Serializable接口以便支持克隆和体系化。

l TreeSet保障成分独一性依赖Comparator接口和Comparable接口。

Map集合

Map接口

分歧于List和Set,集合种类中的Map是“双列集结”,存储的是内容是键值对(key-value),Map集结的风味是无法包括重复的键,每三个键最多能映射多少个值。Map接口抽象出了大旨的增加和删除改查操作。定义如下:

public interface Map<K,V> {}

驷不如舌格局

/**添加**/
V put(K key, V value);
void putAll(Map<? extends K, ? extends V> m);

/**删除**/
void clear();
V remove(Object key);

/**判断**/
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);

/**获取**/
int size();
V get(Object key);
Collection<V> values();
Set<K> keySet();
Set<Map.Entry<K, V>> entrySet();

Map接口的要害完成类有HashMap和TreeMap。

HashMap

HashMap是Map接口的一个兑现类,它存款和储蓄的剧情是键值对(key-value)。HashMap的平底是哈希表数据结构,允许存款和储蓄null的键和值,同时HashMap是线程不安全的。HashMap与HashTable的差别是:HashTable不得以储存null的键和值,HashTable是线程安全的(synchronized完毕)。

 

哈希表的定义:给定表M,存在函数f(key),对自由给定的机要字值key,代入函数后若能得到包涵该重大字的笔录在表中的地方,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。通过把关键字值key映射到哈希表中的二个地点来做客记录,以加快查找的速度。

 

HashMap定义如下:

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
{}

l HashMap承袭AbstractMap,AbstractMap抽象了Map会集的片段基本操作。

l HashMap完结了Cloneable,Serializable接口以便支持克隆和类别化。

 

HashMap源码解析总括(源码略,建议先全体认知再张开源码对着看):

 

l HashMap的多少个关键成员:table, DEFAULT_INITIAL_CAPACITY ,MAXIMUM_CAPACITY ,

size, threshold, loadFactor, modCount。

(1)table是一个Entry[]数组类型,Map.Entry是三个Map接口里的三个里面接口。而Entry实际上就是八个单向链表,也称为HashMap的“链式存款和储蓄法”。HashMap的键值对正是积累在Entry对象中(三个Entry对象包括四个key、一个value、key对应的hash和针对性下一个Entry的靶子)。

(2)DEFAULT_INITIAL_CAPACITY是默许的始发容积是16。

(3)MAXIMUM_CAPACITY, 最大体积(开头化体量超过这么些值时将被那么些值替换)。

(4)size是HashMap的深浅,保存的键值对的数目。

(5)threshold是HashMap的阈值,用于剖断是还是不是供给调节HashMap的体积。threshold的值="容积*加载因子",当HashMap中蕴藏数据的数码达到threshold时,就供给将HashMap实行rehash 操作(即重新建构内部数据结构)是容积*2。

(6)loadFactor便是加载因子。

(7)modCount是记录HashMap被退换的次数。

 

l get(Object key)。先总结key的hash,遵照hash计算索引,遵照目录在table数组中查找寻相应的Entry,重回Entry中的value。

l put(K key, V value)。若key为null,则开创一个key为null的Entry对象并积存到table[0]中。不然总计其hash以及索引i,创立四个键值对和哈希值分别为key、value、hash的Entry对象并蕴藏到table[i]中并将Entry对象增多到链表中。须要细心的是,假如该hash已经存在Entry链表中,则用新的value取代旧的value并赶回旧的value。

l  putAll(Map<? extends K, ? extends V> m)。当当前实际体积小于供给的体量,则将体积*2。调用put()方法各种加多到HashMap中。

l remove(Object key)。总括key的hash以及索引i,依照目录在table数组中追寻出相应的Entry,从Entry链表删除相应的Entry节点,时期会比较hash和key(equals判定)来推断是或不是是要删减的节点。

l clear()。把每三个table[i]设置为null。

l Entry类中重写了equals()方法和hashCode()来判断三个Entry是不是等于。

l containsKey(Object key)。相比hash和key(equals推断)来推断是不是是包罗该key。

 

HashMap举例

通过keyset遍历

图片 10public class HashMapTest { public static void main(String[] args) { HashMap<String,String> map = new HashMap<String,String>(); map.put("001", "zhangsan1"); map.put("002", "zhangsan2"); map.put("003", "zhangsan3"); map.put("004", "zhangsan4"); Set<String> keySet = map.keySet(); Iterator<String> it = keySet.iterator(); while(it.hasNext()) { String obj = (String)it.next(); System.out.println(obj + "-" + map.get(obj)); } } } 运维结果: 004-zhangsan4 001-zhangsan1 002-zhangsan2 003-zhangsan3 View Code

通过**entrySet**遍历

图片 11public class HashMapTest { public static void main(String[] args) { HashMap<String,String> map = new HashMap<String,String>(); map.put("001", "zhangsan1"); map.put("002", "zhangsan2"); map.put("003", "zhangsan3"); map.put("004", "zhangsan4"); Set<Entry<String, String>> se = map.entrySet(); Iterator<Entry<String, String>> it = se.iterator(); while(it.hasNext()) { Entry<String, String> en = (Entry<String, String>)it.next(); System.out.println(en.getKey() + "-" + en.getValue()); } } } 运营结果: 004-zhangsan4 001-zhangsan1 002-zhangsan2 003-zhangsan3 View Code

TreeMap

TreeMap是Map接口的三个达成类,由此它存储的也是键值对(key-value)。TreeMap的底层数据结构是二叉树(红黑树),其性状是能够对成分进行排序,TreeMap是线程不安全的。定义如下:

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{}

l TreeMap承袭AbstractMap,AbstractMap抽象了Map集合的局地基本操作。

l TreeMap达成了NavigableMap接口,援助一种类的导航方法,比方再次来到有序的key集结。

l TreeMap完成了Cloneable,塞里alizable接口以便援救克隆和类别化。

 

TreeMap源码深入分析计算(源码略,提出先全部会认知识再展开源码对着看):

 

l TreeMap的多少个重视成员:root, size, comparator。

(1)root是红黑树的根节点,它是Entry类型,Entry是红黑数的节点,它含有了红黑数的6个基本组成成分:key(键)、value(值)、left(左孩子)、right(右孩子)、parent(父节点)、color(颜色)。Entry节点依据key举办排序,Entry节点富含的剧情为value。

(2)comparator是相比较器,使红黑树的节点有所相比性,用来给TreeMap排序。红黑数排序时,依据Entry中的key实行排序,Entry中的key相当的大小是基于相比较器comparator来开展判定的。

(3)size是红黑树节点的个数。

 

l TreeMap(Comparator<? super K> comparator)。带相比较器的构造函数能够在TreeMap外界自定义TreeMap成分(红黑树节点)的对比器。

l get(Object key)。若相比较器comparator不为空(即因此构造函数外界传入的),则透过Comparator接口的compare()方法从根节点伊始和key每个比较直到找寻极其的节点。若比较器为空,则接纳Comparable接口的compareTo()相比查找。

l put(K key, V value)。若根节点root为空,则基于key-value创制两个Entry对象插入到根节点。不然在红黑树中找到找到(key, value)的插入地方。查找插入地点依旧若比较器comparator不为空则通过Comparator接口的compare()方法相比查找,不然通过Comparable接口的compareTo()方法相比查找。进程比较复杂。

l putAll(Map<? extends K, ? extends V> map)。调用AbstractMap中的putAll(),AbstractMap中的putAll()又会调用到TreeMap的put()。

l remove(Object key)。先依据key查寻找相应的Entry,从红黑树中删除相应的Entry节点。

l clear()。clear把根节点设置为null就可以。

l containsKey(Object key)。剖断是不是是包涵该key的因素,查找方法同get()。

 

TreeMap举例

图片 12public class TreeMapTest { public static void main(String[] args) { System.out.println("---TreeMap默许按key升序排序---"); TreeMap<Integer,String> map = new TreeMap<Integer,String>(); map.put(200,"sha"); map.put(300,"can"); map.put(100,"pek"); map.put(400,"szx"); Set<Entry<Integer,String>> se = map.entrySet(); Iterator<Entry<Integer,String>> it = se.iterator(); while(it.hasNext()) { Entry<Integer,String> en = (Entry<Integer,String>)it.next(); System.out.println(en.getKey() + "-" + en.getValue()); } System.out.println("---TreeMap使用自定义比较器降序排序---"); TreeMap<Integer,String> map2 = new TreeMap<Integer,String>(new CityNumComparator()); map2.put(200,"sha"); map2.put(300,"can"); map2.put(100,"pek"); map2.put(400,"szx"); Set<Entry<Integer,String>> se2 = map2.entrySet(); Iterator<Entry<Integer,String>> it2 = se2.iterator(); while(it2.hasNext()) { Entry<Integer,String> en = (Entry<Integer,String>)it2.next(); System.out.println(en.getKey()

  • "-" + en.getValue()); } } } class CityNumComparator implements Comparator { @Override public int compare(Object o1, Object o2) { if(!(o1 instanceof Integer) || !(o2 instanceof Integer)) { throw new RuntimeException("不可相比的对象"); } Integer num1 = (Integer)o1; Integer num2 = (Integer)o2; if(num1 < num2) { return 1; } if(num1 > num2) { return -1; } return 0; //Integer类型自己已经自有比较性,可能 //return num2.compareTo(num1); } } 运维结果: ---TreeMap暗中同意按key升序排序--- 100-pek 200-sha 300-can 400-szx ---TreeMap使用自定义比较器降序排序--- 400-szx 300-can 200-sha 100-pek View Code

有鉴于此,要想奉公守法本身的措施对TreeMap举行排序,能够自定义比较青眼写compare()方法重写本人的可比逻辑。

集结遍历

迭代器的设计原理

在上头List和Map的剖判和比方中,已经涉嫌迭代器了。因为种种容器的平底数据接口差别,所以迭代的不二诀要也不相同,不过也是有叁只的有些,把那个共同的有的重新抽象,Iterator接口就是迭代器的顶层抽象。

 

List集合中有温馨有意的迭代器ListIterator,ListIterator接口是Iterator接口的子接口。达成类ArrayList和LinkedList中有迭代器的有血有肉落实(内部类)。把迭代器设计在集中的内部,那样,迭代器就能够轻便的访谈会集的积极分子了。

private class ListItr extends Itr implements ListIterator<E>{}

而在HashMap和TreeMap的遍历中,大家平日将Map的键存到Set集结中,Set属于List的子接口,当然也持续了List特有的迭代器,通过迭代key来获取value。另一种艺术是将Map中的映射关系Entry收取存款和储蓄到Set集结,通过迭代每三个映射Entry关系获取Entry中的key和value。可以说,Map是借List的迭代器完成了对本身的遍历。

集合遍历效能计算

l ArrayList是数组结构,ArrayList常用遍历有for循环(索引访问)、加强for循环、迭代器迭代。在那之中按索引访谈成效最高,其次是增高for循环,使用迭代器的功用最低。

l LinkedList是链表结构,常用遍历也可能有for循环(索引访谈)、加强for循环、迭代器迭代。提出实际不是采取专擅访问的艺术去遍历LinkedList,而选择每种遍历的不二秘技。

l HashMap和TreeMap的遍历中,转换为set,借List的迭代器达成对自己的遍历。

晤面相比

Comparator与Comparable

在TreeMap的深入分析和比方中,大家提到了TreeMap中的成分排序比较选取的是Comparator接口的compare()方法和Comparable接口的compareTo()。当运算本人不享有相比较性只怕有所的相比性不满足大家的急需时,我们就足以运用Comparator接口只怕Comparable接口来重写大家需求的可比逻辑。Comparator接口和Comparable接口实现相比较的非常重要不一样是:Comparator 是在成分公司完毕的排序,那是一种政策格局,便是不更换元素自个儿,而用八个国策对象(自定义相比较器)来改动相比行为。而Comparable接口则需求修改要相比的要素,让要素具有比较性,在要素内部重新修改比较行为。看上边包车型地铁四个列子。

让要素具备相比性

图片 13//完成Comparable接口强制让Passenger对象具备可比性 class Passenger implements Comparable { private String name; private int age; Passenger(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 int compareTo(Object obj) { if(!(obj instanceof Passenger)) { return -1; } Passenger p = (Passenger)obj; System.out.println("调用compareTo比较"+ p.name + "与" + this.name); if(this.age> p.age) { return 1; } if(this.age == p.age) { return this.name.compareTo(p.name); } return -1; } } public class TreeSetTest { public static void main(String[] args) { TreeSet ts = new TreeSet(); print("-----------添港成分到TreeSet----------"); ts.add(new Passenger("zhangsan",20)); ts.add(new Passenger("lingsi",21)); ts.add(new Passenger("wangwu",22)); ts.add(new Passenger("wangwu",22)); Iterator it = ts.iterator(); while(it.hasNext()) { Passenger obj = (Passenger)it.next(); print(obj.getName() + "-" + obj.getAge()); } } public static void print(Object obj) { System.out.println(obj); } } 运维结果: -----------添欧成分到TreeSet---------- 调用compareTo相比zhangsan与zhangsan 调用compareTo相比较zhangsan与lingsi 调用compareTo比较zhangsan与wangwu 调用compareTo相比lingsi与wangwu 调用compareTo比较lingsi与wangwu 调用compareTo相比较wangwu与wangwu zhangsan-20 lingsi-21 wangwu-22 View Code

 

地点的例证中,Passenger本人并不享有相比性,可是通过改变Passenger,让其落到实处了Comparable 接口重写了compareTo()方法让其基于年龄有所相比性。

自定义比较器

图片 14public class TreeSetTest2 { public static void main(String[] args) { TreeSet ts = new TreeSet(new MyComparator()); print("-----------添欧元素到TreeSet----------"); ts.add(new Passenger("zhangsan",20)); ts.add(new Passenger("lingsi",21)); ts.add(new Passenger("wangwu",22)); ts.add(new Passenger("chenliu",23)); Iterator it = ts.iterator(); while(it.hasNext()) { Passenger obj = (Passenger)it.next(); print(obj.getName() + "-" + obj.getAge()); } } public static void print(Object obj) { System.out.println(obj); } } class MyComparator implements Comparator { @Override public int compare(Object o1, Object o2) { if(!(o1 instanceof Passenger) || !(o2 instanceof Passenger)) { throw new RuntimeException("不可比较的对象"); } Passenger p1 = (Passenger)o1; Passenger p2 = (Passenger)o2; System.out.println("调用compare相比"+ p1.getName() + "与" + p2.getName()); if(p1.getAge() > p2.getAge()) { return 1; } if(p1.getAge() < p2.getAge()) { return -1; } return 0; } } 运转结果: -----------添英镑素到TreeSet---------- 调用compare相比zhangsan与zhangsan 调用compare比较lingsi与zhangsan 调用compare比较wangwu与zhangsan 调用compare相比较wangwu与lingsi 调用compare相比较chenliu与lingsi 调用compare相比较chenliu与wangwu zhangsan-20 lingsi-21 wangwu-22 View Code

从地点的事例能够看到,Passenger本人并不具有比较性,大家也从不更换Passenger,而是在外界自定义多少个相比较器,传入TreeSet中,使得TreeSet中蕴藏的Passenger具备了相比性。

聚拢工具类

Collections

Collections是一个工具类,提供了操作集结的常用方法:

 

<!--排序, 对list中元素按升序进行排序,list中的所有元素都必须实现 Comparable 接口-->
void sort(List<T> list)

<!--混排,打乱list中元素的顺序-->
void shuffle(List<?> list)

<!--反转,反转list中元素的顺序-->
void reverse(List<?> list)

<!--使用指定元素替换指定列表中的所有元素-->
void fill(List<? super T> list, T obj)

<!-- 将源list中的元素拷贝到目标list-->
void copy(List<? super T> dest, List<? extends T> src)

<!-- 返回集合中最小的元素-->
T min(Collection<? extends T> coll)

<!-- 返回集合中最大的元素-->
T max(Collection<? extends T> coll)

Collections举例

图片 15public class CollectionsTest { public static void main(String[] args) { ArrayList al = new ArrayList(); al.add("zhangsan"); al.add("lisi"); al.add("wangwu"); System.out.println("集结未排序前"); System.out.println(al); System.out.println("使用Collections.sort()方法自然排序"); Collections.sort(al); System.out.println(al); System.out.println("使用Comparator按长度自定义排序"); Collections.sort(al,new StringLengthComparator()); System.out.println(al); System.out.println("al中最长的成分"); System.out.println(Collections.max(al,new StringLengthComparator())); System.out.println("已排序的前提下,wangwu成分下标索引"); System.out.println(Collections.binarySearch(al, "wangwu")); System.out.println("逆序"); Collections.reverse(al); System.out.println(al); } } class StringLengthComparator implements Comparator<String> { @Override public int compare(String o1, String o2) { if(o1.length() > o2.length()) return 1; if(o1.length() < o2.length()) return -1; return 0; } } 运转结果: 集合未排序前 [zhangsan, lisi, wangwu] 使用Collections.sort()方法自然排序 [lisi, wangwu, zhangsan] 使用Comparator按长度自定义排序 [lisi, wangwu, zhangsan] al中最长的因素 zhangsan 已排序的前提下,wangwu成分下标索引 1 逆序 [zhangsan, wangwu, lisi] View Code

Arrays

Arrays也是贰个工具类,提供了操作数组以及在数组和集纳之间转移的某个常用方法。

/**可以对各种类型的数组进行排序**/
void sort(Object[] a)

/** 数组变集合**/
<T> List<T> asList(T... a)

/** 数组转成字符串**/
String toString(Object[] a)

Arrays举例

图片 16public class ArraysTest { public static void main(String[] args) { String[] array = new String[]{"abc","def","hig"}; System.out.println(Arrays.toString(array)); List<String> list = Arrays.asList(array); System.out.println(list.contains("def")); //list.add("lmn");//UnsupportedOperationException int[] array2 = new int[]{1,2,3}; List<int[]> list2 = Arrays.asList(array2); System.out.println(list2); Integer[] array3 = new Integer[]{1,2,3}; List<Integer> list3 = Arrays.asList(array3); System.out.println(list3); } } 运营结果: [abc, def, hig] true [[[email protected]] [1, 2, 3] View Code

亟需注意的是,将数组产生集结后,不能够应用集合的扩大照旧去除方法,因而数组的长度是定点的,使用这一个主意将会报UnsupportedOperationException至极。从上边的例证也足以看来,如若数组中的元素都是目的,那么调换到会集时,数组中的成分就径直转变到集结中的成分;假若数组中的成分是着力项目,那么任何数组将作为群集的因素存在。

小结

实际假使精晓了汇聚体系各样首要达成类底层的数据结构类型,依照数据结构的风味,就能够联想到该集结有啥样特色,也很轻便明白它们主要方法上的完结进度。小说首要介绍了常用的接口和贯彻类,还会有众多没涉及,通过汇集框架图分模块回想,全体把握,再依赖需求扩充其它没涉及的剧情。

 

千里之行,始于足下。把人家的产生投机,再把团结的享受给旁人,那也是一遍提...

TAG标签:
版权声明:本文由990888藏宝阁发布于编程算法,转载请注明出处:精要分析,两大集合框架Map和Collection