首先声明下自己写博客是为了让更新记住的东西,总结下 ,本人是名刚入坑的程序媛,希望各位大佬加以评论不对之处
纯属自己总结 不断更新。
Java中的集合类
说起集合 首先就想到了数组 数组和集合有什么区别呢?
数组是存储同一数据类型的多个元素的容器,数组的好处是,他有下标索引
当数组声明的时候就被定义了长度,数组的效率高,但是数组是定长的
数组的声明方式有俩种 一种是静态声明:给出初始值,由系统决定长度
int [] arr = {1,2,3};
int arr [] = {1,2,3};
一种是动态声明:给出长度 系统给出默认值
int[] arr = new int[3];
只给出了长度,没有往里面附初值 ,但是系统默认会给出初值
java的内存分配
1:栈存储局部变量 ,局部变量在方法定义中或方法声明上定义的变量,数据使用完毕就消失 数组里的数据
2:堆存储所有new出来的,每一个new出来的东西都有地址,每一个变量都有默认值,数据使用完毕后,在垃圾回收器空闲的时候回收 存放引用对象名称
3:常见操作 遍历 最值 常常用到计数器 在声明计数器的时候要注意是在外面声明 在就是注意数组越界 数组越界(Array IndexOutofBoundsException)
如何对数组初始化呢?
所谓初始化就是为数组开辟内存空间,并为每个数组元素赋予值
注意:数组有一个专门的属性 length();用于获取数组的长度
正题来了 集合和数组的区别?
数组:既可以生成引用的数据类型,也可以存基本类型,数组效率高,但是数组定长,长度也不是不可以改变,但是一旦改了就相当于生成了新的数组对象。
集合:(容器类)不是定长的可以操作数量可变,类型不同的一组数据,所有的java集合都在java.util包中,但只能存储引用类型的对象,不能存放基本类型的对象
java中的集合框架
框架:类库的集合。
集合框架:用来表示和操作的统一的架构,包含了实现集合的接口与类。
集合又称为容器(containers),简单的来说集合框架就是一个对象,可以将具有相同性质的多个元素汇聚成一个整体。集合被用于存储、获取操纵和传输聚合的数据----存放数据的容器。
集合框架的核心接口为Collection、 List、 Set 和 Map.
1. Collection集合接口
Collection是一组各自独立的元素,通常拥有相同的套用规则。Set 、List由它派生。
基本操作:
方法 | 方法作用 |
boolean add(Object obj) | 将指定对象obj新增至集合内,增加成功传回true,否则传回false |
boolean addAll(Collection c) | 将指定集合c内所有元素新增至集合内,增加成功传回true,否则传回false |
viod clear() | 将集合内所有元素清空 |
boolean isEmpty() | 检查集合内是否没有任何元素,如果是传回true,否则传回false |
Iterator iterator() | 将集合内的元素信息转存成Iterator对象 |
boolean remove(Object obj) | 将指定元素obj从集合内移除,成功移除传回true,否则传回false |
int size() | 将集合内的元素总数传回 |
Object[] toArray() | 将集合内的元素转存到数组后传回该数组 |
containsAll()方法:查找当前集合是否包含了另外一个集合的所有元素,即另外一个元素是否是当前集合的子集。
addAll()方法:将另外一个集合中的所有元素添加到当前集合中,类似于“并”操作。
clear()方法:删除当前集合中的所有元素。
removeAll()方法:类似于clear()方法,但是删除的是集合的一个子集。
retainAll()方法:类似于removeAll()方法,从当前集合中删除不属于子集的元素,即“交集运算”。
Iterator接口方法:
方法 | 方法说明 |
void add(Object obj) | 将Obj插入列表中的一个元素前,该元素在下一次调用next()方法时被返回 |
boolean hasNext() | 如果存在下一个元素,则返回true,否则返回false |
boolean hasPrevious() | 如果存在前一个元素,则返回true,否则返回false |
Object next() | 返回下一个元素,如不存在,引发一个NoSuchElementException异常 |
int nextIndex() | 返回下一个元素的下表,如果不存在下一个元素,则返回列表的大小 |
Object previous() | 返回前一个元素,如不存在,引发一个NoSuchElementException异常 |
void remove() | 从列表中删除当前元素 |
void set(Object obj) | 将obj赋给当前元素。即上一次调用next()方法或previousfangfa后返回的元素 |
Collection实现类:
类名 | 类的说明 |
AbstractCollection | 实现大多数Collection接口 |
AbstractList | 扩展AbstractCollection并实现大多数List接口 |
AbstractSequentialList | 为了被类集使用而扩展AbstractList,该类集是连续而不是用随机方式访问其元素 |
LinkedList | 通过扩展AbstractSequentialList来实现连接表 |
ArrayList | 通过扩展AbstractList来实现动态数组 |
AbstractSet | 扩展AbstractCollection并实现大多数AbstractSet |
HashSet | 为了使用散列表而扩展AbstractSet |
TreeSet | 实现存储在树中的一个集合,扩展扩展AbstractSet |
JDK 不提供Collection 接口的任何直接实现:它提供更具体的子接口(如 Set 和 List)实现Collection 接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
所有通用的 Collection 实现类(通常通过它的一个子接口间接实现 Collection)应该提供两个“标准”构造方法:一个是 void(无参数)构造方法,用于创建空 collection;另一个是带有 Collection 类型单参数的构造方法,用于创建一个具有与其参数相同元素新的 collection。实际上,后者允许用户复制任何 collection,以生成所需实现类型的一个等效 collection。尽管无法强制执行此约定(因为接口不能包含构造方法),但是 Java 平台库中所有通用的 Collection 实现都遵从它。
1 package demo;
2
3 import java.util.*;
4
5 /**
6 * 集合框架的简单测试
7 * Created by luts on 2015/12/5.
8 */
9 public class test {
10 public static void main(String[] args) throws Exception{
11 Collection country = new HashSet(); //set是无序的、没有重复元素的集合
12 country.add("China");
13 country.add("Canada");
14 country.add("Italy");
15 country.add("Japan");
16 country.add("China"); //重复插入一个元素
17
18 System.out.println("size = " + country.size());
19 for (Iterator it = country.iterator(); it.hasNext();)
20 System.out.println(it.next());
21
22 System.out.println();
23
24 Collection countryNew = new ArrayList(); //List元素有序,可以添加重复的元素
25 countryNew.add("China");
26 countryNew.add("Canada");
27 countryNew.add("Italy");
28 countryNew.add("Japan");
29 countryNew.add("China"); //重复插入一个元素
30 System.out.println("size = " + countryNew.size());
31 for (Iterator it = countryNew.iterator(); it.hasNext();)
32 System.out.println(it.next());
33 }
34 }
结果:
size = 4 Canada China Japan Italy size = 5 China Canada Italy Japan China
Java集合类collections
就像有专门的java.util.Arrays来处理数组,Java中对集合也有java.util.Collections来处理。
第一组方法主要返回集合的各种数据:
Collections.checkedCollection / checkedList / checkedMap / checkedSet / checkedSortedMap / checkedSortedSet:
检查要添加的元素的类型并返回结果。任何尝试添加非法类型的变量都会抛出一个ClassCastException异常。这个功能可以防止在运行的时候出错。
Collections.emptyList / emptyMap / emptySet :返回一个固定的空集合,不能添加任何元素。
Collections.singleton / singletonList / singletonMap:返回一个只有一个入口的 set/list/map 集合。
Collections.synchronizedCollection / synchronizedList / synchronizedMap / synchronizedSet / synchronizedSortedMap / synchronizedSortedSet:获得集合的线程安全版本(多线程操作时开销低但不高效,而且不支持类似put或update这样的复合操作)
Collections.unmodifiableCollection / unmodifiableList / unmodifiableMap / unmodifiableSet / unmodifiableSortedMap / unmodifiableSortedSet:返回一个不可变的集合。当一个不可变对象中包含集合的时候,可以使用此方法。
第二组方法中,其中有一些方法因为某些原因没有加入到集合中:
Collections.addAll: 添加一些元素或者一个数组的内容到集合中。
Collections.binarySearch: 和数组的Arrays.binarySearch功能相同。
Collections.disjoint: 检查两个集合是不是没有相同的元素。
Collections.fill: 用一个指定的值代替集合中的所有元素。
Collections.frequency: 集合中有多少元素是和给定元素相同的。
Collections.indexOfSubList / lastIndexOfSubList:和String.indexOf(String) / lastIndexOf(String)方法类似——找出给定的List中第一个出现或者最后一个出现的子表。
Collections.max / min: 找出基于自然顺序或者比较器排序的集合中,最大的或者最小的元素。
Collections.replaceAll: 将集合中的某一元素替换成另一个元素。
Collections.reverse: 颠倒排列元素在集合中的顺序。如果你要在排序之后使用这个方法的话,在列表排序时,最好使用Collections.reverseOrder 比较器。
Collections.rotate:根据给定的距离旋转元素。
Collections.shuffle:随机排放List集合中的节点,可以给定你自己的生成器——例如 :java.util.Random / java.util.ThreadLocalRandom or java.security.SecureRandom。
Collections.sort:将集合按照自然顺序或者给定的顺序排序。
Collections.swap:交换集合中两个元素的位置(多数开发者都是自己实现这个操作的)。
2. Set接口
Set类似于数学中的集合的概念,是无序的、没有重复元素的集合。也就是说Set的构造函数有一个约束条件:传入的Collection参数不能包含重复的元素。常用具体实现有HashSet和TreeSet类。
Set方法:
2.1 HashSet类
HashSet类是对AbstractSet类的扩展。它创建了一个类集。该类集使用散列表进行存储,而散列表则通过使用称之为散列法的机制来存储信息。在散列中,一个关键字的信息内容被用来确定唯一的一个值,称为散列码。而散列码则被用来当作与关键字相连的数据的存储下标。
HashSet类的构造方法:
填充比必须介于0.0与1.0之间。它决定在散列集合向上调整大小之前,有多少能被充满。具体地说,就是当元素的个数大于散列集合容量乘以它的填充比时,散列集合会被扩大。
注意:散列集合并不能确定其元素的排列顺序。
HashSet类的主要方法:
方法 | 功能描述 |
public boolean add(Object o) | 向集合添加指定元素 |
public void clear() | 清空集合中所有元素 |
public boolean contains(Object o) | 判断集合是否包含指定元素 |
public boolean isEmpty() | 判断集合是否还有元素。如果集合不包含任何元素,则返回true |
public Iterator iterator() | 返回对此集合中元素进行迭代的迭代器 |
public boolean remove(Object o) | 删除集合中的元素 |
public int size() | 返回此集合中的元素的个数 |
public Object[] toArray | 将集合中的元素放到数组中,并返回该数组 |
Set.contains(E e)的时候,先调用从Object继承而来的hashCode方法,然后在调用equals()方法,连个方法都返回真的时候,才认定Set包含某个元素。jvm运行时,给每个对象分配唯一一个标志身份的标志hanshcode。Object的hashCode()方法在默认情况下,判断哈希码是不是相同.即如同equals默认情况下比较的是二者是不是同一个内存快。Set集的contains方法,内部就是先调用hashCode再调用equals()方法。很多情况要结合实际对hashCode、equals方法进行改写.
2.2 TreeSet类
TreeSet为使用树来进行存储的Set接口提供了一个工具。对象按升序进行存储,这方便我们对其进行访问和检索。在存储了大量的需要进行快速检索的排序信息的情况下,TreeSet是一个很好的选择。
TreeSet类的构造方法:
TreeSet类中有几个特殊的方法:
方法 | 功能描述 |
public E first() | 返回有序集合中第一个元素,即最小的那个元素 |
public E last() | 返回有序集合中最后一个元素,即最大的那个元素 |
public SortedSet subSet(E fromElement,E toElement) | 返回有序集合从fromElement(包括)到toElement(不包括)的元素 |
3. List 列表
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。和Set不同,List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
indexOf()方法返回元素第一次出现的索引位置,会调用equals()方法。lastindexOf()方法返回元素最后一次出现的索引位置。如果元素在List最后不存在,返回-1.
3.1 ArrayList
ArrayList类是对AbstractList类的扩展。ArrayList支持可随需要而增长的动态数组。在Java中,标准数组是定长的。它们被创建之后,就不能被加长或缩短,也就意味着开发者必须先知道数组可以容纳多少元素。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
ArrayList有三种构造方法:
ArrayList类的主要方法:
方法 | 功能描述 |
public boolean add(E o) | 将指定的元素追加到列表的最后 |
public void add(int index,E element) | 将参数element表示的元素插入此列表中参数index表示指定位置中 |
public boolean addAll(Collection c) | 将Collection中所有元素追加到此列表的尾部 |
public void clear() | 删除列表中的所有元素 |
public boolean contains(Object elem) | 判断此列表是否包含参数elem表示的指定元素 |
public get(int index) | 返回列表中指定位置上的元素 |
public boolean isEmpty() | 判断此列表中有没有元素 |
public remove(int index) | 删除列表中指定位置上的元素 |
public set(int index, E element) | 用参数element表示指定的元素代替列表中指定位置上的元素。 |
public int size() | 返回列表中的元素数 |
public Object[] toArray() | 返回一个包含列表中所有元素的数组 |
public T[] toArray(T[] a) | 返回一个包含列表中所有元素的数组 |
void trimToSize() | 将容量调整为该列表的当前大小 |
3.2 LinkedList类
LinkedList实现了List接口,允许null元素。它提供了一个链接列表的数据结构。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
LinkedList类有两种构造方法:
除了它继承的方法之外,LinkedList类本身还定义了一些有用的方法:
3.3 Vector类
Vector类实现动态数组,这与ArrayList相似,但两者不同的是:Vector类是同步的,并且它包含了一些不属于类集框架的方法。
Vector类的构造方法:
所有的矢量开始都有一个原始的容量。在这个原始容量达到之后,下次再存储时,矢量会自动为那个对象分配空间。通过分配超过需要的内存,矢量减小了可能产生的分配的次数,节约了时间。
注意:由Vector创建的Iterator,虽然和ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。
Vetor提供了用于增加元素的方法:
方法 | 方法描述 |
public void addElement( Object obj ) | 将指定的组件添加到该向量的末尾,并将其大小增加1 |
public void addElement( int index,Object obj ) | 在向量的指定位置插入指定的元素obj,该位置及以后的元素位置后移 |
public void insertElementAt( Object obj,int index ) | 将指定对象作为此向量中的组件插入到指定的index处 |
3.4 Stack类
Stack是Vector的一个子类,它实现标准的后进先出堆栈。Stack仅仅定义了创建空堆栈的默认构造方法。
Stack类包括了Vector类定义的所有方法,同时增加了几种它自己定的方法:
方法 | 功能描述 |
public E push(Object item) | 将元素引用压入栈顶 |
public E pop() | 删除栈顶元素。栈为空则会抛出EmptyStackException异常 |
public E peek() | 取得栈顶元素但不删除它。如果栈为空则会抛出EmptyStackException异常 |
public boolean empty() | 判断堆栈是否为空 |
public int search(Object o) | 返回Object对象在栈中所处的位置。其中栈顶元素位置为1,以后依次递增1。如果对象不在栈中则返回-1 |
在栈的操作中,先压入栈的元素在栈的最底部,删除元素是从栈顶开始的。也就是最后压入栈的元素将会被先删除掉。
4. Map
Map没有继承Collection接口,映射(map)是一个存储关键字和值的关联,或者说是“关键字/值”对的对象,即给定一个关键字,可以得到它的值。关键字和值都是对象,关键字必须是唯一的,但值是可以被复制的。
映射接口定义了映射的特性和本质。支持映射的三大接口:
Map接口映射唯一关键字到值。关键字是以后用于检索值的对象。给定一个关键字和一个值,可以存储这个值到一个Map对象中。当这个值被存储以后,就可以使用它的关键字来检索它。Map.Entry接口使得可以操作映射的输入。而SortMap接口扩展了Map,它确保了各项关键字按升序排列。
Java转实现映射接口的类:
类名 | 类的描述 |
AbstractMap | 实现大多数的Map接口 |
HashMap | 将AbstractMap扩展到使用散列表 |
TreeMap | 将AbstractMap扩展到使用树 |
4.1 Hashtable类
Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。它与HashMap相似,但Hashtable是同步的。使用Hashtable时,指定一个对象作为关键字,同时指定与该关键字相关联的值。接着该关键字被散列,把得到的散列值作为存储在表中的值的下标。
Hashtable的构造方法:
添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。
Hashtable通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大。
由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。
如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。
4.2 HashMap类
HashMap类使用散列表实现Map接口。HashMap是非同步的,并且允许null,即null value和null key。但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。
HashMap类的构造方法:
HashMap类的主要方法:
方法 | 方法说明 |
public void clear() | 删除映射中所有映射关系 |
public boolean containsKey(Object key) | 判断HashMap中是否包指定的键的映射关系,如果包含则返回true |
public boolean containsValue(Object value) | 判断HashMap中是否包指定的键值的映射关系 |
public V get(Object key) | 返回参数key键在该映射中所映射的值 |
public boolean isEmpty() | 判断HashMap中是否包含键-值映射关系,如果不包含则返回true |
public V put(K key, V value) | 在映射中放入指定值与指定键 |
public void putAll(Map m) | 将指定映射的所有映射关系复制到此映射中 |
public int size() | 返回映射中键-值映射关系的数目 |
public V remove(Object key) | 删除映射中存在该键的映射关系 |
* HashMap实现Map并扩展AbstractMap。同HashSet一样,HashMap也不保证它的元素的顺序。
* 在向HashMap中添加元素时,不但要将元素添加,还要为每个元素设置一个Hash码。Hash码不只可以为数字,同样它也可以为字符串。
* containsValue()方法注意equals的重写
4.3 TreeMap类
TreeMap类通过使用树实现Map接口。TreeMap提供了按排序顺序存储关键字/值对的有效手段,同时允许快速检索。不像散列映射,树映射保证它的元素按照关键字升序排序。
TreeMap的构造方法:
TreeMap实现SortedMap并且扩展AbstractMap。本身并没有定义其他方法。
TreeMap的主要方法:
方法 | 方法说明 |
clear() | 从此TreeMap中删除所有映射关系 |
clone() | 返回TreeMap实例的浅表复制 |
comparator() | 返回用于对此映射进行排序的比较器,如果此映射使用它的键的自然顺序,则返回null |
containsKey(Objectkey) | 如果此映射包含对于指定的键的映射关系,则返回true |
containsValue(Objectvalue) | 如果此映射把一个或多个键映射到指定值,则返回true |
entrySet() | 返回此映射所包含的映射关系的set视图 |
firstKey() | 返回有序映射中当前第一个键 |
get(Objectkey) | 返回此映射中映射到指定键的值 |
headMap(KtoKey) | 返回此映射的部分视图,其键严格小于toKey |
keySet() | 返回此映射中所包含的键的Set视图 |
lastKey() | 返回有序映射中当前最后一个键 |
来自慕课网的例子:Course课程类:
1 /**
2 * Created by Luts on 2015/12/5.
3 */
4 public class Course {
5 private String id;
6 private String name;
7 public Course(String id, String name){
8 this.id = id;
9 this.name = name;
10 }
11
12 public Course(){}
13
14 public String getId() {
15 return id;
16 }
17
18 public void setId(String id) {
19 this.id = id;
20 }
21
22 public String getName() {
23 return name;
24 }
25
26 public void setName(String name) {
27 this.name = name;
28 }
29 }
学生类:
1 import java.util.*;
2
3 /**
4 * Created by Luts on 2015/12/5.
5 */
6 public class Student {
7 private String id;
8 private String name;
9 private Set<Course> courses;
10
11 public Student(String id, String name){
12 this.id = id;
13 this.name = name;
14 this.courses = new HashSet<Course>();
15 }
16
17 public String getId() {
18 return id;
19 }
20
21 public void setId(String id) {
22 this.id = id;
23 }
24
25 public String getName() {
26 return name;
27 }
28
29 public void setName(String name) {
30 this.name = name;
31 }
32
33 public Set<Course> getCourses() {
34 return courses;
35 }
36
37 public void setCourses(Set<Course> courses) {
38 this.courses = courses;
39 }
40
41 }
测试类:
1 import javax.swing.text.html.parser.Entity;
2 import java.util.HashMap;
3 import java.util.Map;
4 import java.util.Scanner;
5 import java.util.Set;
6 import java.util.Map.*;
7
8 /**
9 * Created by Luts on 2015/12/5.
10 */
11 public class MapTest {
12
13 //创建Map的学生类型
14 public Map<String, Student> students;
15
16 //初始化学生类型
17 public MapTest(){
18 this.students = new HashMap<String, Student>();
19 }
20
21
22 public void testPut(){
23 Scanner input = new Scanner(System.in);
24 int i = 0;
25 while (i < 3){
26 System.out.println("输入学生ID");
27 String ID = input.next();
28 Student st = students.get(ID);
29 if (st == null){
30 System.out.println("输入学生姓名");
31 String name = input.next();
32 Student newStudent = new Student(ID, name);
33 students.put(ID, newStudent);
34 System.out.println("新添加学生:" + students.get(ID).getName());
35 i++;
36 }else {
37 System.out.println("该学生ID已被占用");
38 continue;
39 }
40 }
41 }
42
43 public void testKeySet(){
44 Set<String> keySet = students.keySet(); //通过keySet方法返回Map值所有“键”的set集合
45
46 //取得students容量
47 System.out.println("总共有:"+students.size() +"个学生");
48
49 //遍历keySet,取得键对应的值
50 for (String stuID : keySet){
51 Student st = students.get(stuID);
52 if (st != null){
53 System.out.println("学生:" + st.getName());
54 }
55 }
56
57 }
58
59
60 public void testRemove(){
61 Scanner input = new Scanner(System.in);
62 while (true){
63 System.out.println("输入要删除的学生ID");
64 String ID = input.next();
65 Student st = students.get(ID);
66 if (st == null){
67 System.out.println("该学生ID不存在");
68 continue;
69 }
70 System.out.println("成功删除学生:" + students.get(ID).getName());
71 break;
72 }
73 }
74
75 //通过entrySet方法遍历Maop
76 public void testEntrySet(){
77 Set<Entry<String, Student>>entrySet = students.entrySet();
78 for (Entry<String, Student>entry : entrySet){
79 System.out.println("取得键:" + entry.getKey());
80 System.out.println("对应的值为:" + entry.getValue().getName());
81 }
82 }
83
84 public void testModify() {
85 // 提示输入要修改的学生ID
86 System.out.println("请输入要修改的学生ID:");
87 // 创建一个Scanner对象,去获取从键盘上输入的学生ID字符串
88 Scanner input = new Scanner(System.in);
89 while (true) {
90 // 取得从键盘输入的学生ID
91 String stuID = input.next();
92 // 从students中查找该学生ID对应的学生对象
93 Student student = students.get(stuID);
94 if (student == null) {
95 System.out.println("该ID不存在!请重新输入!");
96 continue;
97 }
98 // 提示当前对应的学生对象的姓名
99 System.out.println("当前该学生ID,所对应的学生为:" + student.getName());
100 // 提示输入新的学生姓名,来修改已有的映射
101 System.out.println("请输入新的学生姓名:");
102 String name = input.next();
103 Student newStudent = new Student(stuID, name);
104 students.put(stuID, newStudent);
105 System.out.println("修改成功!");
106 break;
107 }
108 }
109
110
111
112 public static void main(String[] args){
113 MapTest mt = new MapTest();
114 mt.testPut();
115 mt.testKeySet();
116 mt.testRemove();
117 //mt.testEntrySet();
118 // mt.testModify();
119 // mt.testEntrySet();
120
121 }
122 }
5. 比较方法
Comparator接口
TreeSet和TreeMap都按排序顺序存储元素。然而,精确定义到底采用哪种“排序顺序”则是比较方法。在默认情况下,Java采用的是“自然排序”的顺序存储它们的元素,例如A在B的前面,2在3的前面,等等。如果需要用到其他的方法对元素进行排序,可以在构造集合或者映射时,指定一个Comparator对象。
Comparator接口定义了两种方法:compare()和equals()。
compare()方法:
equals()方法:
Comparable接口
此接口强行对实现它的每个类的对象进行整体排序。此排序被称为该类的自然排序 ,类的 compareTo 方法被称为它的自然比较方法 。实现此接口的对象列表(和数组)可以通过 Collections.sort (和 Arrays.sort )进行自动排序。
int compareTo(T obj) 比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
Comparator与Comparable的区别
Comparator位于包java.util下,而Comparable位于包java.lang下,Comparable接口将比较代码嵌入自身类中,而后者在一个独立的类中实现比较。 如果类的设计师没有考虑到Compare的问题而没有实现Comparable接口,可以通过 Comparator来实现比较算法进行排序,并且为了使用不同的排序标准做准备,比如:升序、降序。
关于比较器,更多参阅:
6.集合类性能效率总结
接口 | 实现类 | 保持插入顺序 | 可重复 | 排序 | 使用说明 |
List | ArrayList | Y | Y | N | 长于随机访问元素;但插入、删除元素较慢(数组特性)。 |
LinkedList | Y | Y | N | 插入、删除元素较快,但随即访问较慢(链表特性)。 | |
Set | HashSet | N | N | N | 使用散列,最快的获取元素方法。 |
TreeSet | N | N | Y | 将元素存储在红-黑树数据结构中。默认为升序。 | |
LinkedHashSet | Y | N | N | 使用散列,同时使用链表来维护元素的插入顺序。 | |
Map | HashMap | N | N | N | 使用散列,提供最快的查找技术。 |
TreeMap | N | N | Y | 默认按照比较结果的升序保存键。 | |
LinkedHashMap | Y | N | N | 按照插入顺序保存键,同时使用散列提高查找速度。 |
① 如果涉及到堆栈,队列等操作,应该考虑用List。如果要进行大量的随机访问,应使用ArrayList;如果经常进行插入与删除操作,用使用LinkedList。
② HashMap设计用来快速访问;而TreeMap保持“键”始终处于排序状态,所以没有HashMap快。LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问能力。
③ Set不接受重复元素。HashSet提供最快的查询速度,而TreeSet保持元素处于排序状态。LinkedHashSet以插入顺序保存元素。
④ 对哈希表的操作,作为key的对象要正确重写equals和hashCode方法。
⑤ 尽量返回接口而非实际的类型(针对抽象编程),如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。
⑥ 程序中不应该使用过时的Vector\Hashtable\Stack。
同步性
Vector是同步的。这个类中的一些方法保证了Vector中的对象是线程安全的。而ArrayList则是异步的,因此ArrayList中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销。
数据增长
从内部实现机制来讲ArrayList和Vector都是使用数组(Array)来控制集合中的对象。当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据那么使用Vector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。
使用模式
在ArrayList和Vector中,从一个指定的位置(通过索引)查找数据或是在集合的末尾增加、移除一个元素所花费的时间是一样的,这个时间我们用O(1)表示。但是,如果在集合的其他位置增加或移除元素那么花费的时间会呈线形增长:O(n-i),其中n代表集合中元素的个数,i代表元素增加或移除元素的索引位置。
LinkList集合类在增加或移除集合中任何位置的元素所花费的时间都是一样的: O(1),但它在索引一个元素的使用时比较慢: O(i),其中i是索引的位置.