培训机构网站建设wordpress获取不同分类文章
培训机构网站建设,wordpress获取不同分类文章,荆州seo推广,做网站的成本费用1 JAVA集合概述 Java集合封装了一系列数据结构比如链表、二叉树、栈、队列等#xff0c;然后提供了针对这些数据结构的一系列算法比如查找、排序、替换#xff0c;使编程难度大大降低。#xff08;这句话有可能是非法…1 JAVA集合概述 Java集合封装了一系列数据结构比如链表、二叉树、栈、队列等然后提供了针对这些数据结构的一系列算法比如查找、排序、替换使编程难度大大降低。这句话有可能是非法的因为个人对算法目前不是太了解并不了解Java有没有实现哪些数据结构。但是说在这里想给那些畏难算法与数据结构这门课程的人一丝信心嫑以为非要懂算法和数据结构才能编程不懂这门课程编也能编程并不是所有的问题都要自己来实现一个数据结构。如果因为觉得编程一定要懂算法和数据结构进而对编程产生一种心理阴影没有信心那是很错误的你总需要先用一门语言来练练手然后才能去学习算法和数据结构。懂算法和数据结构会编程完全是那些所谓的专家来吓唬那些新手入门者的找一本语言介绍书好好练练编程并不是你想的那么难这样的话只需要利用提供的数据结构存储需要用的数据然后利用数据结构上提供的算法就可以对数据进行简单的处理。链表、二叉树、栈、队列在JAVA里面统称为集合就是把数据统统塞进这些集合里面这些集合的结构可能是不同的。Java集合将这些数据结构分成如下几类。 注意 这些集合类里面存储的数据都是指向堆内存对象的对象栈内存变量 区别 Java的集合类分为四种SetList、Map和Queue四种体系即MSQL设计者可以根据需要使用这四种体系里面的数据结构然后处理数据。 Map:代表有映射关系的集合也就是key-value这样的数据集合比如{001——张三002——李四} Set代表无序、不可重复的集合比如{1,2,3}。注意无序、不可重复 Queue代表一种队列集合的实现 List代表添加时候有序存储可重复的集合{1,1,2,3} 1.1 Java集合继承树 在处理数据时候经常处理到元素个数不确定数组长度是固定的初始化后就无法改变有关联的数据{001——张三002——李四}为了解决这些问题Java提供了集合类集合类负责保存、盛装这些数据因此集合类也被称为容器类所有的集合类都存放在java.util包中 集合类和数组的区别 数组可以保存基本数据类型或者对象但是集合类智能保存指向堆内存数据的栈内存对象变量不过很多书上会直接说集合类里面装的都是对象这样可能会好理解一些。 MSQL接口类的继承拓扑图 提供的四大接口类有如下继承结构的拓扑图Collection和Map是两个根类由这两个根类派生出一系列的接口类。 其中Collection派生SQLMap派生其他的接口类。MSQL(记法M-SQL像一种编程语言一样)MapSetQueue,List这四种集合类最常用的是SML(记法AI领域的一种语言)也就是SetMapList这三种接口类最常用实现是Set的HashSetMap的HashMapList的ArrayList也就是HHA(2HA2哈——啊哈)如下图的颜色重的标注出来是常用的 1.2 Collection和Iterator接口 1.2.1 Collection 接口 下面如果没有特别说明SQL并不指数据库语言SQL而是代表SetQueueList三个Collection的子接口类。 Collection接口下面定义了若干方法这些方法可以用于SQL三种集合接口类。注意集合接口模板类里面存储的是栈对象变量boolean add(Object o)该方法用于像一个集合接口类添加一个对象变量o指向的对象如果添加成功也就是集合类被改变成功返回true否则返回falseboolean addAll(Collection c):假设调用该接口的是集合接口类a调用该接口后会将集合接口类c的对象全部添加到集合接口类a中元素间用逗号隔开void clear():清空集合里面的所有元素使元素个数size为0boolean contains(Object o):检测集合里面是否含有对象元素o有true无falseboolean containsAll(Collection c):假定调用该接口的是集合a那么调用该接口后会检测集合a里面是否包含集合c的全部元素有true无falseboolean isEmpty()返回集合是否为空相当于int size()方法返回值为0和不为0的情况boolean remove(Object o)删除集合里面指定元素o删除成功返回true失败falseboolean removeAll(Collection c)假设调用该接口的是集合a调用该接口后会从集合a里面找出集合c里面没有的元素也就是找出差集如果删除了一个或一个以上的元素该方法返回trueboolean retainAll(Collection c):假设调用该接口的是集合a调用该接口后删除a中c没有的元素也就是把a编程a和c的交集如果操作成功返回trueint size()返回集合里面元素个数Object[] toArray()把集合转换成一个数组所有的集合元素变成对应的数组元素这样就可以用数组的方法来访问元素Iterator iterator():返回一个Iterator对象用于遍历集合里面的所有元素也就是一个迭代器,这个迭代器可以用于查询集合类元素利用System.out的println查询同样可以打印出集合的所有数据但是这样的查询是不可控制的也就是说要么查询出所有要么不查询使用迭代器可以根据需要进行查询。 1.2.2 Iterator接口 Iterator接口隐藏了Collection集合类的底层实现提供了若干方法对Collection集合类进行处理。方法 boolean hasNext():如果被迭代的集合仍然有元素没有被遍历迭代则返回true就是说如果集合里面迭代一次后剩余的元素不止一个则返回true。Object next()返回集合里下一个元素注意迭代器每次只返回一个不像println那样一次返回所有void remove():删除集合里上一次next方法返回的元素比如说如果等于某个值就可以删除这个元素这样就可以控制集合返回结果看一段代码 1 //创建一个集合2 Collection books new HashSet();3 books.add(轻量级J2EE企业应用实战);4 books.add(Struts2权威指南);5 books.add(基于J2EE的Ajax宝典);6 //获取books集合对应的迭代器7 Iterator it books.iterator();8 while(it.hasNext()){9 //it.next()方法返回的数据类型是Object类型需要强制类型转换
10 String book (String)it.next();//book代表的是每次返回的一个元素
11 // it.remove();//remove删除每次next方法返回的元素按照此循环如果每次返回后都进行删除那么最后就不返回任何一个结果因为返回一个删掉一个
12 //如果next方法返回的元素与Struts2权威指南一样则删除
13 // if(book.equals(Struts2权威指南)){
14 //
15 // it.remove();
16 // }
17 //对book变量赋值不会改变改变集合本身
18 // System.out.println(book);
19 //book 测试字符串;
20 }
21 System.out.println(books); 强烈注意 Iterator接口类仅用于遍历集合Iterator本身并不提供盛装对象的能力如果需要创建Iterator对象则必须与有一个可以被它迭代的集合没有集合的迭代器没有存在价值。也就是说Iterator必须依附于Collection对象有一个Iterator对象则必然有一个与之关联的Collection对象供其迭代。代码倒数第二行有一个book赋值代码但是输出集合books时候输出结果没有任何改变可以得到一个结论当使用Iterator对集合进行迭代输出时候Iterator并没有指向堆内存的集合而是把集合元素的值传给了迭代变量所以修改迭代变量的值对集合元素没有任何改变。 墙裂注意 1. 删除集合里面的元素只能通过迭代器的remove方法也就是it.remove()才可以删除集合里面的元素通过调用集合自身的方法来删除集合元素值也就是说books.remove(book)将会出错引发的异常是java.util.ConcurrentModificationException异常或者简单的说迭代过程中不能通过除了迭代器之外的方式来修改集合也就是说在迭代过程中只有迭代器有修改集合的权限其他方式包括集合本身都没有修改集合自身元素的权限。其实更本质的是集合类变量本身只是指向堆内存的数据迭代时候相当于堆内存的使用权交给了迭代器集合类本身当然没有修改权限迭代器采用的是快速失败机制一旦在迭代过程中检测到该集合已经被修改通常是其他线程修改程序立即引发ConcurrentModificationException异常而不是显示修改后的结果这样可以避免共享资源而引发的潜在问题。 第二for循环遍历集合元素 前面已经介绍了for循环有两种方是一种是标准的另一种是被很多书称之为foreach循环这种叫法很容易让人误解循环的关键字是foreach但其实依然是for这里我称之为第二for循环表示第二种for循环同样使用在用for循环迭代输出集合类“中”也不能修改集合元素。同样使用该种循环方式按照前面的语法for循环变量类型 循环变量集合类 代码如下: 1 //创建一个集合2 Collection lan new HashSet();3 //往集合里面装东西4 lan.add(Englis);5 lan.add(Chinese);6 lan.add(Castellano);7 lan.add(Deutsch);8 //使用第二for循环输出集合里面的元素9 for(Object lang:lan){
10 String lgu (String)lang;//集合里面存储的都是对象变量
11 System.out.print(lgu);
12 } 2 Set集合类 Set集合特点Set集合接口类的元素特征是无序、不重复 Set集合与Collection基本完全一样它没有提供任何额外的方法实际上Set就是Collection只是行为不同Set不允许重复元素。 Set不允许重复元素如果相同元素加入同一个Set集合中则会添加失败判断是否相同的标准是使用equals方法而不是方法所以比较严格。 例如 1 Set books new HashSet();
2 books.add(new String(English));
3 //再次添加一个不同的对象
4 books.add(new String(English)); 由于Set是一个集合类集合类里面应该装的是不同对象上述代码里面明显装的是不同对象但是Set集合判断是否是同一个对象的标准是equals方法所以不能添加有点怪怪的 上面介绍的是Set集合的通用知识因此完全适合后面介绍的HashSet、TreeSet、EnumSet三个实现类只是三个实现类各有特色。 2.1 HashSet——LinkedHashSet类 2.1.1 HashSet接口 HashSet是Set接口的典型实现大多数时候使用Set集合就是使用这个实现类HashSet按Hash算法存储集合中的元素因此具有很好的存取和查找性能。HashSet特点 1. 不能保证元素的排列顺序顺序有可能发送变化 2. HashSet不是同步的如果多个线程同时访问一个Set集合或者一个HashSet当2条或2条以上的线程同时修改了HashSet集合时必须通过代码来保证同步。 3. 集合元素值可以是null 当向HashSet集合中存入一个元素HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值然后根据hashCode值来决定该对象在HashSet中存储位置。如果有两个元素通过equals方法比较返回true但他们的hashCode()方法返回值不相等HashSet会把他们存储在不同位置也就可以添加成功。简单的说HashSet集合通过两个条件来判断是否存储要插入的元素。一个是通过equals判断元素值是否相等另一个是通过hashCode方法判断Hash值是否相等。只有两个都相等了才说明要插入的元素相等。 1 import java.util.*;2 /**3 * Description:4 * br/Copyright (C), 2005-2008, Yeeku.H.Lee5 * br/This program is protected by copyright laws.6 * br/Program Name:7 * br/Date:8 * author Yeeku.H.Lee kongyeeku163.com9 * version 1.0
10 */
11
12 //类A的equals方法总是返回true,但没有重写其hashCode()方法
13 class A{
14 public boolean equals(Object obj){
15 return true;
16 }
17 }
18 //类B的hashCode()方法总是返回1,但没有重写其equals()方法
19 class B{
20 public int hashCode(){
21 return 1;
22 }
23 }
24 //类C的hashCode()方法总是返回2,但没有重写其equals()方法
25 class C{
26 public int hashCode(){
27 return 2;
28 }
29 public boolean equals(Object obj){
30 return true;
31 }
32 }
33 public class TestHashSet{
34 public static void main(String[] args) {
35 HashSet books new HashSet();
36 //分别向books集合中添加2个A对象2个B对象2个C对象
37 books.add(new A());
38 books.add(new A());
39 books.add(new B());
40 books.add(new B());
41 books.add(new C());
42 books.add(new C());
43 System.out.println(books);
44 }
45 } 上面的程序中向books集合中添加了2个A对象、2个B对象、2个C对象其中C类重写了equals()方法总是返回truehashCode()方法总是返回2这将导致HashSet会把2个C对象当成同一个对象。运行上述可以得到[B1,B1,C2,A343,Akd33]需要注意的是 如果需要把一个对象放入HashSet中时如果重写该对象对应类的equals()方法也应该重写起hashCode()方法其规则是如果2个对象通过equals方法比较返回true这两个hashCode应该也相同这样就不会添加两个同样的对象。 如果两个对象通过equals方法返回true但是通过hashCode返回不同的那么将会将两个对象保存在不同位置从而都可以添加成功这样会违反Set集合的特征虽然可以添加成功。 如果equals方法返回false但hashCode值却是一样的这样更加极品。因为hash值一样HashSet试图把它们保存在同一个位置但实际不能这样做否认则将覆盖其中一个所以处理比较复杂而且HashSet访问元素根据hash值访问如果HashSet中包含元素有相同的hashCode值将导致性能下降。 HashSet的使用hashCode值去查询元素hashCode就相当于数组索引但为什么不使用数组呢因为数组元素索引是连续的并且长度固定无法自由增加数组长度。而HashSet访问元素可以先算出hashCode值然后去对应位置取出元素。 重写hashCode方法原则 当两个对象通过equals方法返回true时对象的hashCode应该也要相等 对象中用作equals比较标准的熟悉都应该用来计算hashCode值 重写hashCode()方式 第一步 对象内每个有意义的熟悉f即每个用作equals()比较标准的属性计算出一个int类型的hashCode值计算方法如下 不同类型属性取得hashCode值方式 属性类型 计算方式 boolean hashCode(f?0:1); 整数类型(byte,short,char,int) hashCode(int)f; long hashCode(int)(f^(f32)) float hashCodeFloat.floatToIntBits(f) double long l Double.doubleTolongBits(f); hashCode (int)(l^(l32)); 普通引用类型 hashCode f.hashCode();第二步 用第一步计算出来的对象的多个hashCode值组合计算出一个最终的hashCode作为对象的hashCode值返回return f2.hashCode() (int)f2;为了避免直接相加产生的偶然相等(两个对象的f1、f2不等但他们的和刚好相等。例如62433)可以通过为各属性乘以一个质数再相加return f1.hashCode()*17 (int)f2*13;当向HashSet中添加可变对象时必须十分小心如果修改HashSet集合中的对象有可能导致该对象与集合中其他对象相等从而导致HashSet无法准确访问对象。也就是说添加时候会做出检查修改时候是不会检查元素之间是否相同的。所以如果修改导致了与其他对象相等那么HashSet无法准确访问该对象。 2.1.2 LinkedHashSet接口 HashSet还有一个子类LinkedHashSet集合LinkedHashSet集合也是根据元素hashCode值来决定元素的存储位置但它同时使用链表维护元素次序这样时元素看起来以插入的顺序保存的也就是说当遍历LinkedHashSet集合元素时HashSet将会按元素添加顺序来访问集合里的元素。LinkedHashSet需要维护元素的插入顺序因此性能略低于HashSet性能但迭代输出时候性能将会很好。 注意LinkedHashSet集合特点是有序的并且顺序和添加时候顺序一致。 2.2 SortedSet——TreeSet接口 TreeSet是SortedSet接口的唯一实现正如SortedSet名字所述TreeSet可以确保元素处于排序状态。TreeSet提供了如下方法 方法 Comparator comparator():返回当前Set使用的Comparator或者null表示自然方式排序Object first():返回集合中的第一个元素Object last():返回集合中的最后一个元素Object lower(Object e):返回集合中与e相比的最大元素e不一定是TreeSet里面的元素也就是下确界Object higher(Object e):返回集合中与e相比的最小元素也就是上确界e不一定是TreeSet里面的元素 SortedSet subSet(fromElement,toElement):返回此Set的子集合范围从fromElement(包含)到toElement(不包含) SortedSet headSettoElement:返回此Set的子集由小于toElement的元素组成SortedSet tailSet(fromElement):返回此Set的子集由大于等于fromElement的元素组成 总的来说TreeSet提供了访问第一个最后一个上确界、下确界前一个后一个以及截取子TreeSet的方法 区别 同样是提供了排序的存储LinkedHashSet与TreeSet是有本质区别的。LinkedHashSet的顺序是插入元素时候的顺序TreeSet提供的是元素值的顺序 TreeSet支持两种排序方法自然排序和定制排序默认是自然排序 2.2.1 自然排序 TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系然后集合元素按照升序排列这种方式就是自然排序。 Java提供了一个Comparable接口该接口定义一个compareTo(Object obj)方法该方法返回一个整数值实现该接口的类必须实现该方法实现了该接口的类的对象就可以比较大小。当一个对象调用该方法与另一个对象进行比较例如obj1.compareTo(obj2)如果该方法返回0则表示这两个对象相等如果返回一个正整数则表明obj1大于obj2如果返回是一个负整数则表示obj1小于obj2。 Java的一些常用类已经实现了Comparable接口并提供了比较大小的标准。下面是实现了Comparable接口的常用类。 BigDecimal、BigInteger以及所有数值型对应的包装类按它们对应的数值大小进行比较 Character按字符的UNICODE值进行比较 Booleantrue对应的包装类实例大于false对应的包装类实例 String按字符串字符的UNICODE值进行比较 Date、Time后面的时间、日期比前面的时间、日期大。 如果试图把一个对象添加进TreeSet时该对象的类必须实现Comparable接口否则程序抛出异常。另外在实现compareTo(Object obj)方法时需要将被比较对象obj强制类型转换成相同类型因为只有相同类的实例才会比较大小。比如日期和字符串就不能直接比较。 对TreeSet集合而言判断两个对象不相等的标准是两个对象通过equals方法比较false或通过compareTo(Object obj)比较没有返回0——即使两个对象是同一个对象。 类似地当需要把一个对象放入TreeSet中时重写该对象对应类的equals()方法时应该保证该方法与compareTo(Object obj)方法有一致的结果其规则是如果两个对象通过equals方法比较返回true时这两个对象通过compareTo(Object obj)方法比较返回0. 如果两个对象通过equals方法返回true但是通过compareTo(Object obj)返回不同的那么将会将两个对象保存在不同位置从而都可以添加成功这样会违反Set集合的特征虽然可以添加成功。 如果equals方法返回false但compareTo(Object obj)值却是一样的这样更加极品。因为比较相等TreeSet试图把它们保存在同一个位置但实际不能这样做否认则将覆盖其中一个所以处理比较复杂。 如果向TreeSet中添加一个可变对象后并且后面程序修改了该可变 对象的属性导致它与其他对象的大小顺序发生了改变但TreeSet不会再次调整它们的顺序甚至可能导致TreeSet中保存这两个对象它们通过equals方法比较返回true通过compareTo(Object obj)方法比较返回0. 2.2.2 定制排序 可以对TreeSet集合类进行自定义排序比如降序。可以使用Comparator接口帮助该接口里面有一个int compare(T o1,T o2)方法用于比较o1和o2大小比较原理痛compareTo()一样。 如果实现定制排序需要在创建TreeSet集合对象时提供一个Comparator对象与该TreeSet集合关联由该Comparator对象负责集合元素的排序逻辑。 2.3 EnumSet类 EnumSet是一个专为枚举类设计的集合类EnumSet中所有值都必须是指定枚举类型的枚举值该枚举类型在创建EnumSet时显式或隐式地指定。EnumSet集合元素也是有序的EnumSet以枚举值在Enum类定义顺序来决定集合元素的顺序。也就是不以元素值大小决定根据添加顺序决定。 EnumSet在内部以为向量的形式存储这种存储形式紧凑、高效占用内存小。 EnumSet集合不允许加入null元素如果插入null元素将抛出空指针异常。如果只是测试是否出现null元素或删除null元素都不会抛出异常只是删除操作将返回false因为没有任何null元素被删除。 EnumSet类没有暴露任何构造器来创建该类的实例程序应该通过它提供的static方法来创建EnumSet对象。它提供了如下常用static方法来创建EnumSet对象。 2.3.1 EnumSet创建方法 static EnumSet allOf(Class elementType):创建一个包含指定枚举类里所有枚举值的EnumSet集合 static EnumSet complementOf(EnumSet s):假设调用该方法的是EnumSet a调用后的新EnumSet的集合元素是as结果放在a中 static EnumSet copyOf(Collection c):使用一个普通集合来创建EnumSet集合 static EnumSet copyOf(EnumSet s):创建一个与指定EnumSet具有相同元素类型、相同集合元素的EnumSet static EnumSet noneOf(Class elementType):创建一个元素类型为指定枚举类型的空EnumSet static EnumSet of(E first,E...rest):创建一个包含一个或多个枚举值的EnumSet传入的多个枚举值必须属于同一个枚举类。 static EnumSet range(E from ,E to):创建包含从from枚举值到to枚举值范围内所有枚举值的EnumSet集合 注意 EnumSet复制另一个EnumSet集合中所有元素创建新的EnumSet或复制另一个Collection集合中所有元素来创建新的EnumSet当复制Collection集合中所有元素创建新的EnumSet时要求Collection集合中所有元素必须是同一个枚举类型的枚举值 HashSet和TreeSet是Set的两个典型实现那如何选择HashSet和TreeSet呢HashSet的性能总是比TreeSet好特别是最常用的添加、查询元素等操作因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只有当需要一个保持排序的Set时才应该使用TreeSet否则都应该使用HashSet HashSet还有一个子类LinkedHashSet对于普通插入、删除操作LinkedHashSet比HashSet要略慢一点这是有维护链表所带来的额外开销不过有了链表遍历LinkedHashSet会更快 EnumSet是所有Set实现类中性能最好的但它只能保存同一个枚举类的枚举值作为集合元素。 必须指出的是Set的三个实现类HashSet、TreeSet和EnumSet都是线程不安全的如果有多条线程同时访问一个Set集合并且有超过一条线程修改了该Set集合则必须手动保证该Set集合的同步性。通常可以通过Collections工具类synchronizedSortedSet方法来包装该Set集合。次操作最好在创建时进行以防止对Set集合的意外非同步访问。 3.Queue集合类 3.1概述 Queue用于模拟了队列这种数据结构队列是指先进先出(FIFO)的容器。队列的头部保存在队列中时间最长的元素队列的尾部保存在队列中时间最短的元素。 3.2队列 队列是一种特殊的线性表它只允许在表的前端front进行删除操作而在表的后端rear进行插入操作。进行插入操作的端称为队尾进行删除操作的端称为队头。队列中没有元素时称为空队列。 在队列这种数据结构中最先插入的元素将是最先被删除的元素反之最后插入的元素将是最后被删除的元素因此队列又称为“先进先出”FIFO—first in first out的线性表。 队列空的条件frontrear 队列满的条件 rear MAXSIZE 队列不允许随机访问队列中的元素。 3.3 Queue接口定义的方法 void add(Object e)将制定元素加入此队列的尾部。 Object element()获取队列头部的元素但是不删除该元素。 boolean offer(Object e):将指定元素加入此队列的尾部。当使用有容量限制的队列时此方法通常比add(Object e)方法更好。 Object peek()获取队列头部的元素但是不删除该元素如果此队列为空则返回null Object poll()获取队列头部的元素并删除该元素如果队列为空则返回为null Object remove()获取队列头部的元素并删除该元素。 3.4 Queue的实现类 Queue有两个常用的实现类LinkedList和PriorityQueue下面介绍着两个类。 3.4.1 LinkedList实现类 LinkedList类是一个奇怪的类它是List接口的实现类——这意味着它是一个List集合可以根据索引来随机访问集合中的元素。除此之外LinkedList还实现了Deque接口Deque接口是Queue接口的子接口它代表一个双向队列Deque有如下方法。void addFirst(Object e)将制定元素插入该双向队列的开头void addLast(Object e):将制定元素插入该双向队列的末尾Iterator descendingIterator()返回以该双向队列对应的迭代器该迭代器将以逆向顺序来迭代队列中的元素。Object getFirst()获取、但不删除双向队列的第一个元素Object getLast()获取、但不删除双向队列的最后一个元素boolean offerFirst(Object e)将指定的元素插入该双向队列的开头boolean offerLast(Object e):将指定的元素插入该双向队列的末尾Object poolFirst()获取、并删除该双向队列的第一个元素如果此双向队列为空则返回nullObject poolLast()获取、并删除该双向队列的最后一个元素如果此双向队列为空则返回nullObject peekFirst()获取、但不删除该双向队列的第一个元素如果此双向队列为空则返回nullObject peekLast()获取、但不删除该双向队列的最后一个元素如果此双向队列为空则返回nullObject pop()pop出该双向队列所表示的栈中第一个元素void push(Object e)将一个元素push进该双向队列所表示的栈中(即该双向队列的头部)Object removeFirst()获取并删除该双向队列的第一个元素Object removeFirstOccurrence(Object o)删除该双向队列的第一次出现元素oremoveLast()获取并删除该双向队列的最后一个元素removeLastOccurrence(Object o)删除该双向队列的最后一次出现的元素o LinkedList不仅可以当成双向队列使用也可以当成栈(但其实不是栈)使用因为该类里面有pop和push两个方法除此之外LinkedList实现了List接口所以被当成List使用。 LinkedList有上述方法让它可以当做双向队列、栈和List集合用。LinkedList是个相当强大的集合类。 LinkedList与ArrayList、Vector的实现机制完全不同ArrayList、Vector内部以数组形式保存集合中的元素因此随机访问集合元素上性能较好,而LinkedList以链表形式保存集合所以随机访问集合元素较差但插入、删除元素时性能出色。 通常编程时候无需理会ArrayList和LinkedList性能差异只需要知道LinkedList集合不仅提供了List功能还有双向队列及栈功能在一些性能比较敏感的地方可能需要慎重选择哪个List实现。下面是三者性能差异 类别 实现机制 随机访问排名 迭代排名 插入排名 删除排名 数组 连续内存区保存元素 1 不支持 不支持 不支持 ArrayList 内部以数组保存元素 2 2 2 2 Vector 内部以数组保存元素 3 3 3 3 LinkedList 内部以链表保存元素 4 1 1 1 从上表看出因为数组以一块连续内存区保存所有数组元素所以数组在随机访问时性能最好。所有内部数组作为底层实现的集合在随机访问时也有较好的性能而内部以链表作为底层实现的集合在插入、删除操作时有很好的性能以链表作为底层实现的集合也比数组作为底层实现的集合性能好。 1 package chapter3excercise;2 3 import java.util.*;4 5 public class TestPerformance {6 public static void main(String[] args){7 //创建一个字符串数组8 String[] test1 new String[200000];9 //动态初始化数组
10 for(int i 0;i test1.length;i){
11 test1[i] String.valueOf(i);
12 }
13 ArrayList al new ArrayList();
14 for(int i 0;i test1.length;i){
15 al.add(test1[i]);
16 }
17 LinkedList ll new LinkedList();
18 for(int i 0;i test1.length;i){
19 ll.add(test1[i]);
20 }
21 long start System.currentTimeMillis();
22 for(Iterator it al.iterator();it.hasNext();){
23 it.next();
24 }
25 System.out.println(迭代ArrayList元素所需要的时间
26 (System.currentTimeMillis() - start));
27 start System.currentTimeMillis();
28 for(Iterator it ll.iterator();it.hasNext();){
29 it.next();
30 }
31 System.out.println(迭代LinkedList元素所需要的时间
32 (System.currentTimeMillis() - start));
33 }
34 } 多次运行上面程序会发现迭代ArrayList集合的时间略大于迭代LinkedList集合的时间。因此关于使用List集合有如下建议 如果需要遍历List集合元素对于ArrayList、Vector集合则应该使用随机访问方法(get)来遍历集合元素这样性能更好。对于LinkedList集合则应该采用迭代器来遍历集合元素 如果需要经常执行插入、删除操作来改变List集合的大小则应该使用LinkedList集合而不是ArrayList。使用ArrayList、Vector集合将需要经常重新分配内部数组的大小其时间开销常常是使用LinkedList时时间开销的几十倍效果很差。 如果有多条线程需要同时访问List集合中元素可以考虑使用Vector这个同步实现。 3.4.2 PriorityQueue实现类 PriorityQueue是一个比较标准的队列实现类之所以说它是比较标准的队列实现而不是绝对标准的队列实现是因为PriorityQueue保存队列元素的顺序并不是按加入队列的顺序而是按队列元素的大小进行重新排序。因此因此当调用peek方法或者poll方法来取出队列中的元素时并不是取出最先进入队列的元素而是取出队列最小的元素。从这个意义上看,PriorityQueue已经违反了队列的最基本的规则先进先出。 PriorityQueue不允许插入null元素它还需要对队列元素进行排序队列元素有两种排序方式自然排序采用自然顺序的PriorityQueue集合中的元素必须实现了Comparable接口而且应该是同一类的多个实例否则可能导致ClassCastException异常定制排序创建PriorityQueue队列时传入一个Comparator对象该对象负责对队列中所有元素排序采用定制排序时不要求队列元素实现Comparable接口PriorityQueue队列对元素的要求与前面TreeSet对元素的要求基本一致可以参考TreeSet处理 4.List接口和ListIterator接口 List作为Collection接口的子接口可以使用Collection接口里的全部方法而且List是有序集合因此List集合里面增加了一些根据索引来操作集合元素的方法 void add(int index,Object element)将元素element插入在List集合index处 boolean addAll(int index,Collection c):将集合c的所有元素都插入在List集合index处 Object get(int index):返回集合index索引处的元素 int indexOf(Object o):返回对象o在List集合中出现的位置索引 int lastIndexOf(Object o):返回对象o在List集合中最后一次出现的位置索引 Object remove(int index):删除并返回index索引处的元素 Object set(int index ,Object element):将index索引处的元素替换成element对象返回新元素 List subList(int fromIndex,int toIndex):返回从索引fromIndex(包含)到索引toIndex(不包含)处所有集合元素的子集合。 所有List实现类都可以调用这些方法实现对集合元素的操作相对于Set集合List可以根据索引来插入、替换和删除集合元素。 与Set只提供了一个iterator()方法不同List还额外提供了一个listIterator()方法该方法返回一个ListIterator对象ListIterator接口继承了Iterator接口提供了专门操作List的方法。 ListIterator接口在Iterator接口基础上增加了如下方法 boolean hasPrevious():返回该迭代器关联的集合是否还有上一个元素 Object previous()返回该迭代器的上一个元素 void add()在指定位置插入一个元素 拿ListIterator与普通Iterator进行对比容易发现ListIterator增加了向前迭代的功能(Iterator只能向后迭代),而且ListIterator还可以通过add方法向List集合添加元素(Iterator只能删除元素)。 正向迭代是从正向迭代输出元素反向迭代是从反向迭代输出元素。 4.1 ArrayList和Vector实现类 ArrayList和Vector是List的两个典型实现类完全支持List接口的全部功能。 ArrayList和Vector类是基于数组实现的List类所以ArrayList和Vector类封装了一个动态再分配的Object[]数组。每个ArrayList或Vector对象有一个capacity属性这个capacity表示它们所封装的Object[]数组长度。当想ArrayList或Vector中添加元素时其capacity会自动增加。 通常无需关心ArrayList或Vector的capacity属性但如果想ArrayList集合或Vector集合中添加大量元素时可以使用ensureCapacity方法一次性增加capacity可以减少增加分配次数提高性能。 如果开始就知道ArrayList集合或Vector集合需要保存多少个元素可以创建时候就指定capacity大小。如果不指定则capacity属性默认值为10 此外ArrayList和Vector集合提供了两个方法操作capacity属性。 void ensureCapacity(int minCapacity)将ArrayList或Vector集合中的capacity增加minCapacity void trimToSize()调整ArrayList或Vector集合的capacity为列表当前大小。程序可调用该方法来减少ArrayList或Vector集合对象存储空间 ArrayList或Vector在用法上几乎完全相同但Vector是一个古老的集合最开始Java没有提供系统的集合框架所以Vector提供了一些方法名很长的方法。 ArrayList开始就作为List的主要实现类因此没有那些方法名很长的方法实际上Vector有很多缺点通常尽量少用Vector实现类。 ArrayList和Vector的显著区别是ArrayList是线程不安全的当多线程访问同一个ArrayList集合时如果超过一条修改了ArrayList集合则需要手动保证集合的同步性而Vector集合是线程安全的无需保证集合的同步性。Vector性能低于ArrayList性能。 Vector还提供了Stack子类用于模拟栈这种数据结构栈通常是后进先出进栈出栈的都是Object所以取出栈里的元素需要做类型转换。 Object peek()返回栈的第一个元素但并不将该元素pop出栈 Object pop():返回栈的第一个元素并将该元素pop出栈 void push(Object item):将一个元素push进栈最后一个进栈的元素总是位于栈顶。 数组的工具类Arrays里面提供了asList(Object...a)方法该方法可以把一个数组或指定个数的对象转换成一个List集合这个List集合既不是ArrayList实现类也不是Vector实现类的实例而是Arrays的内部类ArrayList的实例 Arrays.ArrayList是一个固定长度的List集合程序只能遍历访问该集合里的元素不可增加、删除集合里的元素。 5.Map集合 5.1 Map集合特点 Map用于保存具有映射关系的数据因此Map集合保存着两组值一组值用于保存Map里的key另外一组值用于保存Map里的valuekey和value都可以是任何引用类型的数据。Map的key不允许重复即同一个Map对象的任何两个key通过equals方法比较总是返回false。key和value之间存在单向一对一关系即通过指定的key总能找到唯一的、确定的value。从Map中取出数据时只要给出指定的key就可以取出对应的value。也就是说Map保存的元素是键值对。如果把Map里的key放在一起看它们就组成了一个Set集合(key是没有顺序key与key之间不能重复)事实上Map确实包含了一个keySet()方法用于返回Map所有key组成的Set集合。 不仅如此Map里key集合和Set集合里元素的存储形式也很像Map子类和Set子类在名字上也几乎相似。Set接口下有HashSet、LinkedHashSet、SortedSet(接口)、TreeSet、EnumSet等实现类和子接口而Map接口下则有HashMap、LinkedHashMap、SortedMap(接口)、TreeMap、EnumMap等实现类和子接口。正如名字暗示Map的实现类和子接口中key集存储形式和对应的Set集合存储形式完全相同。如果把Map所有的value放在一起看它们非常类似于一个List元素与元素之间可以重复每个元素通过索引来查找只是Map中的索引不再使用整数值而是另一个对象来作为索引。如果需要从List集合取出元素需要提供该元素的数字索引如果需要从Map中取出元素需要提供该元素的key索引因此Map也被称为字典或关联数组。 5.2 Map接口方法 Map中包括一个内部实现类Entry。该类封装了一个key-value对Entry包含三个方法 Object getKey():返回该Entry里包含的key值 Object getValue()返回Entry里面包含的value值 Object setValue(V value)设置该Entry里包含的value值并返回新设置的value值 可以把Map理解成一个特殊的Set只是该Set里包含的集合元素是Entry类对象而不是普通对象 5.3Map接口的内部实现类 Map中包括一个内部实现类Entry。该类封装了一个key-value对Entry包含三个方法 Object getKey():返回该Entry里包含的key值 Object getValue()返回Entry里面包含的value值 Object setValue(V value)设置该Entry里包含的value值并返回新设置的value值 可以把Map理解成一个特殊的Set只是该Set里包含的集合元素是Entry类对象而不是普通对象 5.4 HashMap和Hashtable HashMap和Hashtable是Map接口的典型实现类它们之间的关系类似于ArrayList和Vector关系Hashtable是个古老的Map实现类它有两个繁琐的方法elements()和keys()现在基本不用了。 Hashtable和HashMap的区别 Hashtable是一个线程安全的Map实现但HashMap是线程不安全的实现所以HashMap比Hashtable性能好但多线程访问Map对象时Hashtable实现类更好 Hashtable不允许使用null作为key和table如果把null值放进Hashtable中将会引发NullPointerException异常但HashMap可以使用null作为key或value但由于key不能重复所以HashMap里最多只有一项key-value对的key为null但可以有无数多项key-value对的value为null。key类似Set集合的所以无序、禁止重复key而value类似List所以可以重复顺序和key是对应的。 代码 1 package chapter7;2 3 import java.util.HashMap;4 5 public class NullInHashMapTest {6 public static void main(String[] args){7 HashMap hm new HashMap();8 //将两个key值为null的放在key-value键值对中9 hm.put(null, null);
10 hm.put(null, null);
11 //将一个value值为null的放入key-value键值对中
12 hm.put(a, null);
13 System.out.println(hm);
14 }
15 }
16
17 输出结果{nullnull, anull} 根据输出结果可以看出HashMap重写了toString()方法实际所有Map实现类都重写了toString()方法调用Map对象的toString()方法总是返回如下格式字符串 {key1value1,key2value2} Hashtable从类名上就可以看出是一个古老的类命名甚至都没有遵守Java的命名规范每个类的单词首字母大写。后来也没有改成HashTable否则将有大量程序需要改写。尽量少用Hashtable类即使需要创建线程安全的Map实现类可以通过Collections工具类把HashMap变成线程安全的无须使用Hashtable实现类。 为了成功在HashMap、Hashtable中存储、获取对象用作key的对象必须实现hashCode方法和equals方法。HashMap、Hashtable判断两个key相等的标准也是key通过equals方法返回true两个key的hashCode相等。判断value相等的标准是equals返回true即可不需要hashCode判断。 1 package chapter7;2 3 import java.util.Hashtable;4 5 //定义类A该类根据A对象的count属性来判断两个对象是否相等计算hashCode值6 //只要两个A对象的count相等则它们通过equals比较也相等其hashCode值也相等7 8 class AA{9 int count;
10 public AA(int count){
11 this.count count;
12 }
13 public boolean equals(Object obj){
14 if (obj this){
15 return true;
16 }
17 if(obj!null obj.getClass() AA.class){
18 AA a (AA)obj;
19 if(this.count a.count){
20 return true;
21 }
22
23 }
24 return false;
25 }
26 public int hashCode(){
27 return this.count;
28 }
29 }
30 //定义类BB对象与任何对象通过equals方法比较都相等
31 class BB{
32 public boolean equals(Object obj){
33 return true;
34 }
35 }
36 public class HashtableTest {
37 public static void main(String[] args){
38 Hashtable ht new Hashtable();
39 ht.put(new AA(60000),English);
40 ht.put(new AA(87653),Castellano);
41 ht.put(new AA(1232),new B());
42 System.out.println(ht);
43 //只要两个对象通过equals比较返回trueHashtable就认为它们是相等的value。
44 //因为Hashtable中有一个B对象它与任何对象通过equals比较都相等所以下面输出true。
45 System.out.println(ht.containsValue(测试字符串));
46 //只要两个A对象的count属性相等它们通过equals比较返回true且hashCode相等
47 //Hashtable即认为它们是相同的key所以下面输出true。
48 System.out.println(ht.containsKey(new AA(87653)));
49 //下面语句可以删除最后一个key-value对
50 ht.remove(new AA(1232));
51 for(Object key:ht.keySet()){
52 System.out.print(key ----);
53 System.out.print(ht.get(key) \n);
54 }
55 }
56 } 程序最后展示了如何遍历Map中的全部key-value对调用Map对象的keySet方法返回全部key组成的Set对象通过遍历Set的元素(就是Map的全部key)就可以遍历Map中的所有键值对。 与HashSet类似的是尽量不要使用可变对象作为HashMap、Hashtable的key如果确实需要使用可变对象作为HashMap、Hashtable的key则尽量不要在程序中修改作为key的可变对象。 HashSet有一个子类是LinkedHashSetHashMap则有一个子类LinkedHashMapLinkedHashMap也使用双向链表来维护key-value对的次序该链表定义了迭代次序迭代顺序与插入顺序时候保持一致。 LinkedHashMap可以避免需要对HashMap、Hashtable里的key-value对进行排序(只要插入key-value对时保持顺序即可)。同时可以避免使用TreeMap所增加的成本。LinkedHashMap需要维护元素的插入顺序因此性能略低于HashMap的性能但在迭代访问Map里的全部元素时将有很好的性能因为它以链表来维护内部顺序。下面程序示范了LinkedHashMap的功能迭代输出LinkedHashMap的元素时将会按添加key-value对相同顺序输出。 Properties类 Properties类是Hashtable类的子类该文件处理属性文件(ini文件就是一种属性文件)。Properties类可以把Map对象和属性文件关联起来从而把Map对象中的key-value对写入属性文件也可以把属性文件中的属性名属性值加载到Map对象中。由于属性文件里的属性名、属性值只能是字符串类型所以Properties里的key、value都是字符串类型该类提供了如下三个方法来修改Properties里的key、value值。 方法 String getProperty(String key):获取Properties中指定属性名对应的属性值类似于Map的get(Object key)方法 String getProperty(String key,String defaultValue):该方法与前一个方法基本类似该方法多一个功能如果Properties中不存在指定key时该方法返回默认值 Object setProperty(String key,String value):设置属性值类似Hashtable的put方法 除此之外它还提供了两个读、写属性文件的方法 void load(InputStream inStream):从属性文件(以输入流表示)中加载属性名属性值把加载到的属性名属性值对追加到Properties里(由于Properties是Hashtable的子类它不保证key-value对之间的次序)。 void store(OutputStream out,String comments):将Properties中的key-value对写入指定属性文件(以输出流表示)。 5.5 SortedMap和TreeMap 正如Set接口派生出了SortedSet子接口SortedSet接口有一个TreeSet实现类Map接口也派生了一个SortedMap子接口SortedMap也有一个TreeMap实现类。 与TreeSet类似的是TreeMap也是基于红黑树对TreeMap中所有key进行排序从而保证TreeMap中的键值对处于有序状态。类似也有两种排序方式。 排序方式 自然排序TreeMap的所有key必须实现Comparable接口而且所有key应该是同一个类对象否则抛出ClassCastException异常 定制排序创建TreeMap时传入一个Comparator对象该对象负责对TreeMap中所有key进行排序采用定制排序时不要求Map的key实现Comparable接口 类似地TreeSet中判断两个元素相等的标准TreeMap中判断两个key相等的标准也是两个key通过equals比较返回true而通过compareTo方法返回0TreeMap即认为这两个key是相等的。 如果想使用自定义的类作为TreeMap的key且想让TreeMap工作良好重写该类的equals方法和compareTo方法时应该有一致的返回结果即两个key通过equals方法比较返回true时通过compareTo方法返回0否则处理会有性能问题具体可以参考TreeSet。 TreeMap方法 与TreeSet类似的是TreeMap提供了系列根据key顺序访问Map中key-value对方法。 Map.Entry firstEntry():返回该Map中最小key所对应的键值对如果该Map为空则返回null Object firstKey():返回该Map中的最小key值如果Map为空则返回null Map.Entry lastEntry()返回该Map中最大key所对应的key-value对如果该Map为空或不存在这样的key-value则返回null Object lastKey()返回该Map中的最大key值如果Map为空或不存在这样的key都返回null Map.Entry higherEntry(Object key):返回该Map中key的上确界对应的键值对 Object higherKey(Object key)返回key的上确界 Map.Entry lowerEntry(Object key):返回该Map中key的下确界对应的键值对 Object lowerKey(Object key)返回key的下确界 NavigableMap subMap(Object fromKey,boolean fromInclusive,Object toKey,boolean toInclusive):返回该Map的子Map其key的范围从fromKey(是否包括取决于第二个参数) 到toKey(是否包括取决于第四个参数) NavigableMap tailMap(Object fromKey,boolean inclusive):返回该Map的子Map其key的范围从fromKey(是否包括取决于第二个参数) NavigableMap headMap(Object toKey,boolean inclusive):返回该Map的子Map其key的范围小于toKey(是否包括取决于第二个参数) SortedMap subMap(Object fromKey,Object toKey)返回该Map的子Map其key的范围从fromKey(包括)到toKey(不包括) SortedMap tailMap(Object fromKey):返回该Map的子Map其key的范围从fromKey(不包括) SortedMap headMap(Object toKey):返回该Map的子Map其key的范围小于toKey(不包括) 上面的看起来方法挺多也就是第一个、前一个、后一个、最后一个键值对方法并提供了截取子TreeMap的方法 5.6 WeakHashMap实现类 WeakHashMap与HashMap用法基本类似但与HashMap区别在于HashMap的key保留对实际对象的强引用这意味着只要该HashMap对象不被销毁该HashMap对象所有key所引用的对象不会被垃圾回收HashMap也不会自动删除这些key所对应的key-value对象但WeakHashMap的key只保留对实际对象的弱引用这意味着如果该HashMap对象所有key所引用的对象没有被其他强引用变量所引用key所引用的对象可能被垃圾回收HashMap有可能自动删除这些key所对应的key-value对象 WeakHashMap中的每个key对象保存了实际对象的弱引用因此当垃圾回收了该key所对应的实际对象之后WeakHashMap会自动删除key-value对。 1 package chapter7;2 3 import java.util.*;4 5 public class TestWeakHashMap {6 public static void main(String[] args){7 //添加一个集合并添加匿名对象(无变量引用)8 WeakHashMap whm new WeakHashMap();9 whm.put(new String(English), 80);
10 whm.put(new String(Chemistry), 80);
11 whm.put(new String(Java), 80);
12 System.out.println(whm);
13 //添加一个有变量引用的对象
14 whm.put(Deutsch, 99);
15 System.out.println(垃圾回收前 whm);
16 //通知系统进行垃圾回收
17 System.gc();
18 //输出垃圾回收后的结果
19 System.out.println(垃圾回收后: whm);
20 //对比HashMap垃圾处理机制
21 HashMap hm new HashMap();
22 hm.put(new String(English), 80);
23 hm.put(new String(Chemistry), 80);
24 hm.put(new String(Java), 80);
25 System.out.println(hm);
26 //添加一个有变量引用的对象
27 hm.put(Deutsch, 99);
28 System.out.println(垃圾回收前 hm);
29 //通知系统进行垃圾回收
30 System.gc();
31 //输出垃圾回收后的结果
32 System.out.println(垃圾回收后: hm);
33
34 }
35 }
36 执行结果如下
37 {Java80, English80, Chemistry80}
38 垃圾回收前{Java80, English80, Deutsch99, Chemistry80}
39 垃圾回收后:{Deutsch99}
40 {Chemistry80, Java80, English80}
41 垃圾回收前{Chemistry80, Deutsch99, Java80, English80}
42 垃圾回收后:{Chemistry80, Deutsch99, Java80, English80} 5.7 IdentityHashMap实现类 这个Map实现类的实现机制与HashMap基本相似但它在处理两个key相等时比较独特在IdentityHashMap中当且仅当两个key严格相等(key1key2)时IdentityHashMap才认为两个key相等对于普通HashMap而言只要key1和key2通过equals方法比较返回true且hashCode值相同即可。 IdentityHashMap是一个特殊的Map实现它有意违反Map的通常规范在IdentityHashMap中当且仅当两个key严格相等(key1key2)时IdentityHashMap才认为两个key相等 IndetityHashMap提供了与HashMap基本类似的方法null作为key和value不保证键值对之间的顺序。 1 package chapter7;2 3 import java.util.*;4 /**5 * Description:6 * br/Copyright (C), 2005-2008, Yeeku.H.Lee7 * br/This program is protected by copyright laws.8 * br/Program Name:9 * br/Date:
10 * author Yeeku.H.Lee kongyeeku163.com
11 * version 1.0
12 */
13 public class TestIdentityHashMap{
14 public static void main(String[] args){
15 IdentityHashMap ihm new IdentityHashMap();
16 //下面两行代码将会向IdentityHashMap对象中添加2个key-value对
17 ihm.put(new String(语文) , 89);
18 ihm.put(new String(语文) , 78);
19 ihm.put(java , 93);
20 ihm.put(java , 98);
21 System.out.println(ihm);
22 }
23 } 注意最后添加的两个key为java的键值对是一样的因为java采用的缓存机制对于同一个字符串不新建新的对象来浪费内存 5.8 EnumMap集合类 EnumMap是一个与枚举类一起使用的Map实现EnumMap中所有key都必须是单个枚举类的枚举值。创建EnumMap时必须显式或隐式指定它对应的枚举类。EnumMap在内部以数组形式保存所以这种实现形式非常紧凑、高效。 EnumMap根据key的定义时顺序来维护键值对的次序当使用keySet()、entrySet()、values()等方法来遍历EnumMap时即可看到这种顺序与插入时候顺序是一致的。 EnumMap不允许使用null昨晚key值但允许使用null作为value如果试图使用null作为key将抛出NullPointerException异常如果只是查询是否包含值为null的key或者删除使用删除值为null的key都不会抛出异常。 与创建普通Map有区别的是创建EnumMap时必须指定一个枚举类从将该EnumMap和指定枚举类关联起来。 对于Map的常用实现类而言HashMap和Hashtable的效率大致相同因为实现机制几乎完全一样但通常HashMap通常比Hashtable快一点因为Hashtable额外实现同步操作。 TreeMap通常比HashMap、Hashtable要慢(尤其是插入、删除键值对时候更慢)因为TreeMap需要额外的红黑树操作来维护key之间的次序但是用TreeMap有一个好处TreeMap中的键值对总是有序的无序专门进行排序操作。当TreeMap被填充后可以调用keySet()取得key组成的Set然后是用toArray()生成key的数组接下来是用Arrays的binarySearch()方法在已排序的数组中快速地查询对象。当然通常只有在某些情况下无法使用HashMap的时候才这么做因为HashMap正是为快速查询而设计的通常使用Map时候首选HashMap除非需要一个总是排好序的Map时才使用TreeMap。 LinkedHashMap比HashMap慢一点因为它需要维护链表来保持Map中key的顺序。IndentityHashMap性能没有特别出色之处EnumMap性能最好但它只能使用同一个枚举类的枚举值作为key。 5.9 HashSet和HashMap的性能选择 对于HashSet及其子类而言它们采用hash算法来决定集合中元素的存储位置并通过hash算法来增加集合容积的大小对于HashMap、Hashtable及其子类而言它们采用hash算法来决定Map中key的存储并通过hash算法来增加key Set容积的大小Hash表里可以存储元素的位置被称为桶(bucket),通常情况下单个桶里存储一个元素此时有最好的性能:hash算法可以根据hashCode值计算出桶的存储位置接着从桶中取出元素但hash表的状态为open当发送hash冲突时候单个桶会存储多个元素这些元素以链表形式存储必须按顺序搜索。如下图 因为HashSet、HashMap、Hashtable都是用hash算法来决定其元素(对HashMap则是key)的存储因此HashSet、HashMap的hash表包含如下属性 Hash表属性 容量(capacity):hash表中桶的数量 初始化容量(initial capacity)创建hash表时桶的数量。HashMap和HashSet都允许在构造器中指定初始化容量 尺寸(size)当前hash表中记录的数量 负载因子(load factor)负载因子等于size/capacity。负载因子为0表示空的hash表0.5 表示半满的hash表以此类推轻负载的hash表具有冲突少、适宜插入与查询的特点(但是使用Iterator迭代元素时候会变慢) 除此之外hash表里还有一个负载极限负载极限在[0,1]的数值负载极限决定了hash表中的最大填满程度。当hash表中的负载因子到达指定的负载极限时hash表会自动成倍地增加容量(桶的数量)并将原有的对象重新分配放入新的桶内也被称为rehashing HashSet与HashMap、Hashtable的构造器允许指定一个负载极限HashSet与HashMap、Hashtable默认的负载极限为0.75 表明当该hash表被填到3/4 时hash表会发生rehashing 默认负载极限值0.75 是时间和空间成本上的一种折中较高的负载极限可以降低hash表所占用的内存空间但会增加查询数据的时间开销而查询是最频繁的操作较低的负载极限会增加查询数据性能但会增加hash表所占用的内存空间。通常无须改变HashSet和HashMap的负载极限值。通常不需要将初始化容量设置太高。 5.10 操作集合工具类Collections Java提供了一个操作Set、List和Map等集合的工具类Collections该工具类提供了大量方法对集合元素进行排序、查询和修改等操作还提供了将集合对象设置为不可变、对集合对象实现同步控制等方法。 5.10.1 排序操作 Collections提供了如下几个方法对List集合元素进行排序 static void reverse(List list):反转指定List集合中元素的顺序 static void shuffle(List list):对List集合元素进行随机排序(shuffle方法模拟了洗牌动作) static void sort(List list)根据元素的自然顺序对指定List集合的元素按升序进行排序 static void sort(List list,Comparator c):根据指定Comparator产生的顺序对List集合的元素进行排序 static void swap(List list,int i,int j)将指定List集合中i处元素和j处元素进行交换 static void rotate(List list,int distance)将指定集合中i处元素和list.length-i-1 处的元素进行交换 5.10.2查找替换操作 Collections还提供了如下用于查找、替换集合元素的常用方法 static int binarySearch(List list,Object key):使用二分搜索法搜索指定List集合以获得指定对象在List集合中的索引如果要该方法可以正常工作必须保证List中的元素已经处于有序状态 static Object max(Collection coll)根据元素的自然顺序返回给定集合中的最大元素 static Object max(Collection coll,Comparator comp)根据指定Comparator产生的顺序返回给定集合的最大元素 static Object min(Collection coll)根据元素的自然顺序返回给定集合中的最小元素 static Object min(Collection coll,Comparator comp)根据指定Comparator产生的顺序返回给定集合的最小元素 static void fill(List list,Object obj)使用指定元素obj替换指定List集合中的所有元素 static int frequency(Collection c,Object o)返回指定集合中等于指定对象的元素数量 static int indexOfSubList(List source,List target)返回子List对象在母List对象中第一次出现的位置索引如果母List中没有这样的子List则返回-1 static int lastIndexOfSubList(List source,List target)返回子List对象在母List对象中最后一次出现的位置索引如果母List中没有这样的子List则返回-1 static boolean replaceAll(List list,Object oldVal,Object newVal):使用一个新值newVal替换List对象所有的旧值oldVal 5.10.3 同步控制 Collections类中提供了多个synchronizedXxx方法(Xxx代表集合类名称)该方法返回指定集合对象对应的同步对象从而可以解决多线程并发访问集合时的线程安全问题。 如前所述Java常用的集合框架中推荐使用的三个实现类HashSet、ArrayList和HashMap都是线程不安全的如果有多条线程访问它们而且有超过一条线程试图修改它们则可能出现错误。Collections提供了多个静态方法用于创建同步集合。 5.10.4 设置不可变集合 Collections提供了如下三类方法来返回一个不可变的集合Xxx代表集合类名称 emptyXxx()返回一个空的、不可变的集合对象此处的集合可以是List、Set、Map singleonXxx():返回一个只包含指定对象(只有一个或一项元素)的、不可变的集合对象此处的集合可以是List、Set、Map unmodifiableXxx返回指定集合对象的不可变视图。此处的集合可以是List、Set、Map 通过这样的方法就可以创建只读版本的集合对象不可修改 5.10.5 烦琐的Enumeration Enumeration接口是Iterator迭代器的古老版本目前都使用Iterator保留Enumeration主要是为了照顾那些古老的程序。 6.小结 本部分详细介绍了Java集合框架的相关知识。 本部分从Java集合框架体系开始讲起概述了Java集合框架的三个主要体系Set、List和Map简述集合在编程中的重要性。详细讲述了Set、Queue、List、Map接口及各实现类的详细用法深入分析了各实现类的机制差异给出选择集合实现类的原则最后给出了Collections工具类的基本用法。转载于:https://www.cnblogs.com/people/archive/2013/05/08/3067086.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/92390.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!