即便是动态定义数老董度,集合就是用来存储对象的

在学Java开端,一说到存放东西,第二个想到的就是运用数组,使用数组,在数据的存取方面的却也挺便宜,其储存功能高访问快,可是它也饱受了有个别限量,比如说数组的尺寸以及数组的项目,当本身急需一组string类型数据的还要还要求Integer类型的话,就须要定义两遍,同时,数老董度也惨遭限制,尽管是动态定义数主任度,但是长度照旧须求固定在某两个限制内,不便宜也不灵敏。

Java基础加强之集合篇(模块记念、精要分析),java精要

 

千里之行,始于足下。把外人的变成温馨,再把温馨的分享给外人,那也是三回提高的长河。本文的目的是以一篇小说从全部把握集合连串又不失一些细节上的落实,高手路过。

     
 如若说我想要化解上面的那几个范围和不便于应该如何做吧?Java是还是不是提供了相应的消除方法。答案是毫无疑问的,那就是Java容器,java容器是javaAPI所提供的一名目繁多类的实例,用于在程序中存放对象,主要放在Java.util包中,其长度不受限制,类型不受限制,你在存放String类的时候还是能存放Integer类,两者不会争持。

集结的意义与风味

Java是一门面向对象语言,数据多了用对象封装存储(比如,人有真名、年龄、性别等数码音信,我们就悬空一个Person对象来封装存储),对象多了又用什么来储存吗?集合,集合就是用来囤积对象的。

 

汇合的天性就是适用于储存对象而且可以储存不一样门类的对象,集合的长度是可变的。

 

        容器API类图结果如下所示:

会见框架图

集结既然能储存差别种类的的目的,那么聚集种类中毫无疑问有例外类其余器皿,集合中根本有List、Set、Map三种容器,每个容器的数据结构都不雷同。集合系列的类、接口万分多,方便记念,大家将下边这些相对简单的联谊框架图分为从5个模块来学习:

1.Collection集合

2.Map集合

3.会合遍历

4.汇聚比较

5.集合工具类

 

 

先对图做一下分析:

l 点线框表示接口

l 已毕框表示具体的类

l 带有空心箭头的点线表示2个实际的类完成了七个接口

l 实心箭头表示某三个类能够扭转箭头所针对的类

l 常用的容器用古铜黑粗线表示

 

         图片 1

Collection集合

 

Collection接口

Collection是3个接口,是莫大抽象出来的集纳,包罗了汇集的基本操作:添加、删除、清空、遍历、是还是不是为空、获取大小等等。定义如下:

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

Collection接口下第壹,有两个子接口:List和Set。

Collection接口

       
Collection是最大旨的集纳接口,1个Collection代表一组Object,即Collection的成分。一些Collection允许同一的因素而另一部分相当。一些能排序而另一对卓绝。Java
SDK不提供第2手接轨自Collection的类,Java
SDK提供的类都以再三再四自Collection的“子接口”如List和Set。

 

举例:

 

  1. import java.util.*;  
  2. public class TestA{  
  3.     public static void main(String[] args)  
  4.     {  
  5.         Collection<String> lstcoll=new ArrayList<String>();  
  6.     lstcoll.add(“China”);  
  7.     lstcoll.add(new String(“ZD”));  
  8.       
  9.         System.out.println(“size=”+lstcoll.size());  
  10.     System.out.println(lstcoll);  
  11.     }  
  12. }  

结果:

 

       图片 2

List接口

List是Collection的二个子接口,List中的成分是雷打不动的,可以重复,有目录。

概念如下:

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

 

 

List是持续于Collection接口,它自然就包涵了Collection中的全体函数接口,由于List有谈得来的性状(素是有序的,可以再度,有目录),由此List也有协调有意的一对操作,如上藤黄框框中的。List特有的操作紧假若富含索引的操作和List本人的迭代器(如上图)。List接口的常用已毕类有ArrayList和LinkedList。

 

List接口

     
 List是一动不动的Collection,使用此接口可以准确的操纵每种成分插入的地点。用户可以运用索引(成分在List中的地点,类似于数组下标)来拜访List中的元素,相当于说它是有各类的,类似于Java的数组。和Set分化,List允许有一致的成分。J2SDK所提供的List容器类有ArrayList、LinkedList等。

实例:

 

  1. import java.util.*;  
  2. public class TestB{  
  3.     public static void main(String[] args)  
  4.     {  
  5.         List<String> l1=new LinkedList<String>();  
  6.         for(int i=0;i<=5;i++){  
  7.             l1.add(“a”+i);  
  8.         }  
  9.         System.out.println(l1);  
  10.         l1.add(3,”a100″);  
  11.         System.out.println(l1);  
  12.         l1.set(6,”a200″);  
  13.         System.out.println(l1);  
  14.         System.out.println((String)l1.get(2)+” “);  
  15.         l1.remove(1);  
  16.         System.out.println(l1);  
  17.     }  
  18. }  

运维结果:
         图片 3

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 添加新成分时,体积不足以容纳全体要素时,会再也创立1个新的可以容纳全部成分的数组,把旧数组中的成分拷贝到新的数组中并赶回新的数组。增量具体看源码。

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

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

l ArrayList的克隆函数,即是将总体要素克隆到二个数组中。

l ArrayList的连串化,即通过java.io.ObjectOutputStream将ArrayList的长短和每几个元素写到输出流中,只怕经过java.io.ObjectInputStream从输入流中读出长度和每贰个要素到二个数组中。

ArrayList

        ArrayList其实就约等于顺式存储,它包裹了1个数组
Object[],当实例化1个ArrayList时,3个数组也被实例化,当向ArrayList中丰盛对象时,数组的深浅也应和的更动。这样就带来以下有风味:
     
 神速随即访问,你能够跟着访问逐个成分而毫不考虑质量难题,通过调用get(i)方法来走访下标为i的数组成分。
     
 向里面添加对象速度慢,当你创立数组时并不或者显然其体积,所以当改变这几个数组时就务须在内存中做过多业务。
     
 操作其中目的的进程慢,当您要向数组中私行多少个要素中间添加对象时,数组必要活动拥有后边的对象。

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的2个子类。

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

l 同ArrayList,LinkedList同样协助克隆和体系化。

 

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

 

l LinkedList的真相是二个双向链表,各有多少个头节点和尾节点,每3个节点都有个数据域、一个针对性上一个节点的指针域、1个针对上下二个节点的指针域。

l 添比索素时,将成分添加到双向链表的前边。

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

l 依据目录查找成分时,若索引值index <
双向链表长度的四分之二,则从表头今后搜索,否则从表尾往前找。

l LinkedList的仿造和系列化原理同ArrayList。

l LinkedList达成了Deque,Deque接口定义了在双端队列两端访问元素的点子,每一个格局都留存二种样式:一种是在操作失利时抛出万分,另一种是回来3个优秀值(null
或 false)。

l LinkedList有友好有意的迭代器ListIterator。

l LinkedList不存在扩容增量的题材。

LinkedList

       
LinkedList相当于链式存储,它是经过节点直接互动连接来贯彻的。各个节点都蕴涵前三个节点的引用,后三个节点的引用和节点存储的值。当贰个新节点插入时,只需求修改其中保持先后关系的节点的引用即可,当删除记录时也一样。那样就带来以下有特点:
     
 操作其中目的的进程快,只须求转移连接,新的节点可以在内存中的任哪里方。
     
 不大概跟着访问,就算存在get()方法,不过这一个格局是由此遍历接点来恒定的,所以速度慢。

 

 

List应用举例

Set接口

     
Set是一种不含有重复的因素的Collection,即自由的七个成分e1和e2都有e1.equals(e2)=false,Set最多有三个null成分。
     
Set的构造函数有多个约束规范,传入的Collection参数不或许包涵重复的要素。

      Set容器类紧要有HashSet和TreeSet等。

LinkedList完毕堆栈和队列

LinkedList能够算作仓库和队列使用,因为完毕了Deque接口,Deque接口提供了有的了出栈入栈和出队入队的主意。

图片 4class
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

HashSet

       此类达成 Set 接口,由哈希表(实际上是二个 HashMap
实例)援助。它不保障 set
的迭代顺序;尤其是它不保证该各个恒久不变。此类允许采纳 null 成分。

举例:

 

  1. import java.util.*;  
  2. public class TestC{  
  3.     public static void main(String[] args)  
  4.     {  
  5.         Set <String> s=new HashSet<String>();  
  6.         s.add(“Hello”);  
  7.       
  8.     //相同成分  
  9.         s.add(“Hello”);  
  10.   
  11.         System.out.println(s);  
  12.     }  
  13. }  

结果:

        图片 5

ArrayList保证唯一性

List中的成分是足以重新的,可以透过重写equals方法已毕唯一性。上面是ArrayList达成要素去重(依照equals)的贰个例证。

 

图片 6class
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方法)

 

Map接口

       
值得注意的是Map没有继续Collection接口,Map接口是提供key到value的照耀。二个Map中不恐怕包括相同的key,各种key只好照射1个value。即是一一映射,Map接口提供3种集合的视图,Map的情节可以被看做一组key集合,一组value集合,可能一组key-value映射。

        Map接口的落到实处类紧假设总结HashMap和TreeMap等。

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。

HaspMap

         添加数据运用put(key,
value),取出数据拔取get(key),HashMap是允许null,即null value和null
key。可是将HashMap视为Collection时(values()方法可回到Collection),其迭代子操作时间支付和HashMap的容积成比例。因而,假诺迭代操作的属性十分关键的话,不要将HashMap的开端化容积设得过高,或然load
factor过低。

举例:

 

  1. import java.util.*;  
  2. public class TestD{  
  3.     public static void main(String[] args)  
  4.     {  
  5.         Map <String,String> M=new HashMap <String,String>();  
  6.         M.put(“one”,new String(“1”));  
  7.         M.put(“two”,new String(“2”));  
  8.         System.out.println(M);  
  9.     }  
  10. }  

结果:

      图片 7

 

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()方法。

 

总结

       Java容器实际上只有二种:Map , List,
Set;但逐个接口都有差其他完毕版本.它们的区分可以总结为由什么在暗自辅助它们.也等于说,你利用的接口是由什么的数据结构完成的.
List的选择:
       
 比如:ArrayList和LinkedList都落实了List接口.由此无论是采用哪2个,基本操作都平等.但ArrayList是由数组提供底层帮衬.而LinkedList是由双向链表落成的.所以,假诺要时时向List里插入或删除数据,LinkedList会相比较好.否则应当用速度更快的ArrayList。
Set的选择
         HashSet总是比TreeSet
质量要好.而后人存在的说辞就是它可以有限援救元素的排序状态.所以,即便须要3个排好序的Set时,才应该用TreeSet。
Map选择:
        同上,尽量挑选HashMap。

 

 

 

http://blog.csdn.net/dandanzmc/article/details/23447827

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集合的风味是不可以包括重复的键,每八个键最多能映射3个值。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是2个Map接口里的3个内部接口。而Entry实际上就是贰个单向链表,也称之为HashMap的“链式存储法”。HashMap的键值对就是储存在Entry对象中(一个Entry对象涵盖3个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遍历

图片 8public
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**遍历

图片 9public
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,Serializable接口以便援救克隆和连串化。

 

TreeMap源码分析总括(源码略,提出先全体认识再打开源码对着看):

 

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

(1)root是红黑树的根节点,它是Entry类型,Entry是红黑数的节点,它包括了红黑数的五个基本组成成分: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举例

图片 10public
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集合,通过迭代每2个映射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接口则须要修改要比较的要素,让要素具有相比较性,在要素内部重新修改比较行为。
看下边的多个列子。

让要素具有比较性

图片 11//已毕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()方法让其依据年龄有所对比性。

自定义相比较器

图片 12public
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是3个工具类,提供了操作集合的常用方法:

 

<!--排序, 对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举例

图片 13public
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也是1个工具类,提供了操作数组以及在数组和聚众之间转换的部分常用方法。

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

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

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

Arrays举例

图片 14public
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十分。从地方的例子也得以看看,若是数组中的成分都以目标,那么转换到集合时,数组中的成分就直接转换来集合中的成分;要是数组中的元素是基本类型,那么万事数组将用作集合的成分存在。

小结

实在借使通晓了汇集系列各种显要完成类底层的数据结构类型,依据数据结构的风味,就能联想到该集合有哪些特色,也很不难精通它们紧要措施上的贯彻进度。著作紧要介绍了常用的接口和兑现类,还有许多没涉及,通过集合框架图分模块纪念,全体把握,再按照必要扩张其它没涉及的始末。

 

http://www.bkjia.com/Javabc/1172626.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javabc/1172626.htmlTechArticleJava基础加强之集合篇(模块记忆、精要分析),java精要
千里之行,始于足下。把别人的变成本人,再把本人的分享给旁人,那也是一遍提…

相关文章