一、集合与数组
数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用。数组一旦定义,长度将不能再变化。
集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数情况下使用。
二、层次关系
三、几种常用的接口和类简介
1. Collection和Iterator接口
Set和List接口继承了Collection接口
在Collection接口中声明了适用于Set和List的通用方法:
boolean add(Object o) : 向集合中加入一个对象的引用;
void clear() : 删除集合中的所有对象引用,即不再持有这些对象的引用;
boolean contains(Object o) : 判断在集合中是否持有特定对象的引用;
boolean isEmpty() : 判断集合是否为空;
Iterator iterator() : 返回一个Iterator对象,可用它来遍历集合中的元素;
boolean remove(Object o) : 从集合中删除一个对象的引用;
int size() : 返回集合中元素的数目;
Object[] toArray() : 返回一个数组,该数组包含集合中的所有元素;
Iterator接口中的定义的方法可以帮我们去遍历集合中的元素。
Iterator接口隐藏底层集合的数据结构,向客户程序提供了遍历各种类型的集合的统一方法。Iterator接口中声明方法:
Set和List接口继承了Collection接口
在Collection接口中声明了适用于Set和List的通用方法:
boolean add(Object o) : 向集合中加入一个对象的引用;
void clear() : 删除集合中的所有对象引用,即不再持有这些对象的引用;
boolean contains(Object o) : 判断在集合中是否持有特定对象的引用;
boolean isEmpty() : 判断集合是否为空;
Iterator iterator() : 返回一个Iterator对象,可用它来遍历集合中的元素;
boolean remove(Object o) : 从集合中删除一个对象的引用;
int size() : 返回集合中元素的数目;
Object[] toArray() : 返回一个数组,该数组包含集合中的所有元素;
Iterator接口中的定义的方法可以帮我们去遍历集合中的元素。
Iterator接口隐藏底层集合的数据结构,向客户程序提供了遍历各种类型的集合的统一方法。Iterator接口中声明方法:
hasNext() : 判断集合中的元素是否遍历完毕,如没有,就返回true;
next() : 返回下一个元素;
//remove() : 从集合中删除上一个由next()方法返回的元素;
import java.util.*; public class Visitor { public static void print(Collection c) { Iterator it = c.iterator(); while(it.hasNext()) { Object element = it.next(); System.out.println(element); } } public static void main(String args[]) { Set set = new HashSet(); set.add("Tom"); set.add("Mary"); set.add("Jack"); print(set); List list = new ArrayList(); list.add("Linda"); list.add("Mary"); list.add("Rose"); print(list); Map map = new HashMap(); map.put("M","男"); map.put("F","女"); print(map.entrySet()); } }2. Set
最简单的一种集合,集合中的对象无序、不能重复。主要实现类包括:
. HashSet : 按照哈希算法来存取集合中的对象,存取速度比较快;
. LinkedHashSet: HashSet子类,不仅实现Hash算法,还实现链表数据结构,链表数据结构能提高插入和删除元素的性能;
. TreeSet : 实现SortedSet接口,具有排序功能;
一般用法:
Set集合中存放的是对象的引用,并且没有重复对象。
Set set = new HashSet();
String s1 = new String("hello");
String s2 = s1;
String s3 = new String("world");
set.add(s1);
set.add(s2);
set.add(s3);
System.out.println(set.size());
当一个新的对象加入到Set集合中时,
Set的add方法是如何判断这个对象是否已经存在于集合中的呢?
它遍历既存对象,
通过equals方法比较新对象和既存对象是否有相等的。
boolean isExist = false;
Iterator it = set.iterator();
while(it.hasNext()) {
String oldStr = it.next();
if(newStr.equals(oldStr)) {
isExists = true;
break;
}
}
举例:Set set = new HashSet();
String s1 = new String("hello");
String s2 = new String("hello");
set.add(s1);
set.add(s2);
System.out.println(set.size()); //集合中对象数目为1;
1) HashSet
按照哈希算法来存取集合中的对象, 存取速度比较快。当向集合中加入一个对象时,
HashSet会调用对象的hashCode()方法来获得哈希码,然后根据这个哈希码进一步计算出对象在集合中的存放位置。
在Object类中定义了hashCode()方法和equals()方法,Object类的equals()方法按照内存地址比较对象是否相等,
因此如果object.equals(object2)为true, 则表明object1变量和object2变量实际上引用同一个对象,
那么object1和object2的哈希码也肯定相同。为了保证HashSet能正常工作,
要求当两个对象用equals()方法比较的结果为true时,它们的哈希码也相等。
如果用户定义的Customer类覆盖了Object类的equals()方法,
但是没有覆盖Object类的hashCode()方法,就会导致当
customer1.equals(customer2)为true时,
而customer1和customer2的哈希码不一定一样,
这会使HashSet无法正常工作。
(先调用对象的hashCode()方法比较,
如果是true再调用equals方法比较,
如果还是true再认为俩个对象是同一个。
public class Customer {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public boolean equals(Object o) {
if(this==o) return true;
if(!(o instanceof Customer)) return false;
Customer other = (Customer)o;
if(this.name.equals(other.getName()) && this.age==other.getAge())
return true;
else
return false;
}
}
以下程序向HashSet中加入两个Customer对象。
Set set = new HashSet();
Customer customer1 = new Customer("Tom", 15);
Customer customer2 = new Customer("Tom", 15);
set.add(customer1);
set.add(customer2);
System.out.println(set.size()); //打印出 2
出现以上原因在于customer1和customer2的哈希码不一样, 因此为两为customer对象计算出不同的位置,于是把它们放到集中中的不同的地方。
应加入以下hashCode()方法:
public int hashCode() {
return this.age;
}
2) TreeSet
TreeSet实现了SortedSet接口,
能够对集合中的对象进行排序。
当TreeSet向集合中加入一个对象时,会把它插入到有序的对象序列中。那么TreeSet是如何对对象进行排序的呢?
TreeSet支持两种排序方式:自然排序和客户化排序。默认情况下TreeSet采用的是自然排序方式:
a. 自然排序
在JDK类库中, 有一部分类实现了Comparable接口,如Integer、Double和String等。Comparable接口有一个compareTo(Object o)方法,它返回整数类型。对于x.comapreTo(y), 如
返回0, 表明 x和y相等
返回值大于0, 表明 x>y
返回值小于0, 表明 x<y
**即:想表示出x比y大,让x.comapreTo(y)返回一个大于0的数字即可
TreeSet调用对象的compareTo()方法比较集合中对象的大小,然后进行【升序】排序,这种排序方式称为自然排序。
------------------------------------------------------------------------------------------------
JDK类库中实现了Comparable接口的一些类的排序方式:
Byte, Short, Integer, Long, Double, Float : 按数字大小排序;
Character : 按字符的Unicode值的数字大小排序;
String : 按字符串中字符的Unicode值排序;
------------------------------------------------------------------------------------------------
使用自然排序, TreeSet中只能加入相同类型对象,
且这些对象必须实现了Comparable接口。否则会抛出
ClassCastException异常。
当修改了对象的属性后,
TreeSet不会重新排序。最适合TreeSet排序的是不可变类
(它们的对象的属性不能修改)。
b. 客户化排序
除了自然排序外, TreeSet还支持客户化排序。java.util.Comparator接口提供了具体的排序方法, 它有一个
compare(Object x, Object y)方法,用于比较两个对象的大小, 当compare(x,y):
返回0, 表明 x和y相等
返回值大于0, 表明 x>y
返回值小于0, 表明 x<y
如果希望TreeSet按照Customer对象的name属性进行降序排列,
Set集合中存放的是对象的引用,并且没有重复对象。
Set set = new HashSet();
String s1 = new String("hello");
String s2 = s1;
String s3 = new String("world");
set.add(s1);
set.add(s2);
set.add(s3);
System.out.println(set.size());
当一个新的对象加入到Set集合中时,
Set的add方法是如何判断这个对象是否已经存在于集合中的呢?
它遍历既存对象,
通过equals方法比较新对象和既存对象是否有相等的。
boolean isExist = false;
Iterator it = set.iterator();
while(it.hasNext()) {
String oldStr = it.next();
if(newStr.equals(oldStr)) {
isExists = true;
break;
}
}
举例:Set set = new HashSet();
String s1 = new String("hello");
String s2 = new String("hello");
set.add(s1);
set.add(s2);
System.out.println(set.size()); //集合中对象数目为1;
1) HashSet
按照哈希算法来存取集合中的对象, 存取速度比较快。当向集合中加入一个对象时,
HashSet会调用对象的hashCode()方法来获得哈希码,然后根据这个哈希码进一步计算出对象在集合中的存放位置。
在Object类中定义了hashCode()方法和equals()方法,Object类的equals()方法按照内存地址比较对象是否相等,
因此如果object.equals(object2)为true, 则表明object1变量和object2变量实际上引用同一个对象,
那么object1和object2的哈希码也肯定相同。为了保证HashSet能正常工作,
要求当两个对象用equals()方法比较的结果为true时,它们的哈希码也相等。
如果用户定义的Customer类覆盖了Object类的equals()方法,
但是没有覆盖Object类的hashCode()方法,就会导致当
customer1.equals(customer2)为true时,
而customer1和customer2的哈希码不一定一样,
这会使HashSet无法正常工作。
(先调用对象的hashCode()方法比较,
如果是true再调用equals方法比较,
如果还是true再认为俩个对象是同一个。
public class Customer {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public boolean equals(Object o) {
if(this==o) return true;
if(!(o instanceof Customer)) return false;
Customer other = (Customer)o;
if(this.name.equals(other.getName()) && this.age==other.getAge())
return true;
else
return false;
}
}
以下程序向HashSet中加入两个Customer对象。
Set set = new HashSet();
Customer customer1 = new Customer("Tom", 15);
Customer customer2 = new Customer("Tom", 15);
set.add(customer1);
set.add(customer2);
System.out.println(set.size()); //打印出 2
出现以上原因在于customer1和customer2的哈希码不一样, 因此为两为customer对象计算出不同的位置,于是把它们放到集中中的不同的地方。
应加入以下hashCode()方法:
public int hashCode() {
return this.age;
}
2) TreeSet
TreeSet实现了SortedSet接口,
能够对集合中的对象进行排序。
当TreeSet向集合中加入一个对象时,会把它插入到有序的对象序列中。那么TreeSet是如何对对象进行排序的呢?
TreeSet支持两种排序方式:自然排序和客户化排序。默认情况下TreeSet采用的是自然排序方式:
a. 自然排序
在JDK类库中, 有一部分类实现了Comparable接口,如Integer、Double和String等。Comparable接口有一个compareTo(Object o)方法,它返回整数类型。对于x.comapreTo(y), 如
返回0, 表明 x和y相等
返回值大于0, 表明 x>y
返回值小于0, 表明 x<y
**即:想表示出x比y大,让x.comapreTo(y)返回一个大于0的数字即可
TreeSet调用对象的compareTo()方法比较集合中对象的大小,然后进行【升序】排序,这种排序方式称为自然排序。
------------------------------------------------------------------------------------------------
JDK类库中实现了Comparable接口的一些类的排序方式:
Byte, Short, Integer, Long, Double, Float : 按数字大小排序;
Character : 按字符的Unicode值的数字大小排序;
String : 按字符串中字符的Unicode值排序;
------------------------------------------------------------------------------------------------
使用自然排序, TreeSet中只能加入相同类型对象,
且这些对象必须实现了Comparable接口。否则会抛出
ClassCastException异常。
当修改了对象的属性后,
TreeSet不会重新排序。最适合TreeSet排序的是不可变类
(它们的对象的属性不能修改)。
b. 客户化排序
除了自然排序外, TreeSet还支持客户化排序。java.util.Comparator接口提供了具体的排序方法, 它有一个
compare(Object x, Object y)方法,用于比较两个对象的大小, 当compare(x,y):
返回0, 表明 x和y相等
返回值大于0, 表明 x>y
返回值小于0, 表明 x<y
如果希望TreeSet按照Customer对象的name属性进行降序排列,
可以先创建一个实现Comparator接口的类
CustomerComparator, 参见:
import java.util.*;
public class CustomerComparator implements Comparator {
public int compare(Object o1, Object o2) {
Customer c1 = (Customer)o1;
Customer c2 = (Customer)o2;
if(c1.getName().compareTo(c2.getName())>0) return -1;
if(c1.getName().compareTo(c2.getName())<0) return 1;
return 0;
}
CustomerComparator, 参见:
import java.util.*;
public class CustomerComparator implements Comparator {
public int compare(Object o1, Object o2) {
Customer c1 = (Customer)o1;
Customer c2 = (Customer)o2;
if(c1.getName().compareTo(c2.getName())>0) return -1;
if(c1.getName().compareTo(c2.getName())<0) return 1;
return 0;
}
public static void main(String[] args) {
Set set = new TreeSet(new CustomerComparator());
Customer customer1 = new Customer("Tom",15);
Customer customer3 = new Customer("Jack",16);
Customer customer2 = new Customer("Mike",26);
set.add(customer1);
set.add(customer2);
set.add(customer3);
Iterator it = set.iterator();
while(it.hasNext()) {
Customer customer = it.next();
System.out.println(customer.getName() + " " + customer.getAge());
}
}
}
打印输出:
Tom 15
Mike 26
Jack 16
3. List
主要特征是其元素以线性方式存储,集合中允许存放重复对象。主要实现类包括:
. ArrayList: 代表长度可变的数组。允许对元素进行快速的随机访问,但是向ArrayList中插入与删除元素的速度较慢;
. LinkedList: 在实现中采用链表结构。对顺序访问进行了优化,向List中插入和删除元素的速度较快,随机访问速度则相对较慢。
Vector: 是线程安全的集合
遍历方式:
a. list.get(i); //通过索引检索对象;
b. Iterator it = list.iterator();
it.next();
4. Map Key Value
HashMap 是线程不安全的集合。
HashTable是线程安全的集合。
TreeMap可以进行排序(对key进行排序)
Map是一种把键对象和值对象进行映射的集合,它的每一个元素都包含一对键对象和值对象。向Map集合中加入元素时,
必须提供一对键对象和值对象,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
map.put("2", "Tuesday");
map.put("3", "Wednsday");
map.put("4", "Thursday");
String day = map.get("2"); //day的值为"Tuesday"
Map集合中的键对象不允许重复,如以相同的键对象加入多个值对象,第一次加入的值对象将被覆盖。
对于值对象则没有唯一性的要求,可以将任意多个键对象映射到同一个值对象上。
map.put("1", "Mon");
map.put("1", "Monday"); //"1"此时对应"Monday"
map.put("one", "Monday"); //"one"此时对应"Monday"
Map有两种比较常见的实现:
1) HashMap
按哈希算法来存取键对象,有很好的存取性能,为了保证HashMap能正常工作,和HashSet一样,中 要求当两个键对象通过equals()方法比较为true时,这两个键对象的hashCode()方法返回的哈希码也一样。
2) TreeMap
实现了SortedMap接口,能对键对象进行排序。和TreeSet一样,TreeMap也支持自然排序和客户化排序两种方式。(排序按照的是KEY值)
Map map = new TreeMap();
map.put("1", "Monday");
map.put("3", "Wednsday");
map.put("4", "Thursday");
map.put("2", "Tuesday");
Set keys = map.keySet();
Iterator it = keys.iterator();
while(it.hasNext()) {
String key = (String)it.next();
String value= (String)map.get(key);
System.out.println(key + " " + value);
}
打印输出:
1 Monday
2 Tuesday
3 Wednsday
4 Thursday
四、主要实现类区别小结
Vector和ArrayList
1,vector是线程同步的,所以它也是线程安全的,而arraylist是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用arraylist效率比较高。
2,如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%。如果在集合中使用数据量比较大的数据,用vector有一定的优势。
3,如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,如果频繁的访问数据,这个时候使用vector和arraylist都可以。而如果移动一个指定位置会导致后面的元素都发生移动,这个时候就应该考虑到使用linklist,因为它移动一个指定位置的数据时其它元素不移动。
ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要涉及到数组元素移动等内存操作,所以索引数据快,插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快。
arraylist和linkedlist
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。
HashMap与TreeMap
1、 HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
2、在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。
两个map中的元素一样,但顺序不一样,导致hashCode()不一样。
同样做测试:
在HashMap中,同样的值的map,顺序不同,equals时,false;
而在treeMap中,同样的值的map,顺序不同,equals时,true,说明,treeMap在equals()时是整理了顺序了的。
HashTable与HashMap
1、同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的。
2、HashMap允许存在一个为null的key,多个为null的value 。
3、hashtable的key和value都不允许为null。
1,vector是线程同步的,所以它也是线程安全的,而arraylist是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用arraylist效率比较高。
2,如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%。如果在集合中使用数据量比较大的数据,用vector有一定的优势。
3,如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,如果频繁的访问数据,这个时候使用vector和arraylist都可以。而如果移动一个指定位置会导致后面的元素都发生移动,这个时候就应该考虑到使用linklist,因为它移动一个指定位置的数据时其它元素不移动。
ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要涉及到数组元素移动等内存操作,所以索引数据快,插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快。
arraylist和linkedlist
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。
HashMap与TreeMap
1、 HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
2、在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。
两个map中的元素一样,但顺序不一样,导致hashCode()不一样。
同样做测试:
在HashMap中,同样的值的map,顺序不同,equals时,false;
而在treeMap中,同样的值的map,顺序不同,equals时,true,说明,treeMap在equals()时是整理了顺序了的。
HashTable与HashMap
1、同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的。
2、HashMap允许存在一个为null的key,多个为null的value 。
3、hashtable的key和value都不允许为null。
ArrayList和LinkedList
ArrayList和LinkedList在用法上没有区别,但是在功能上还是有区别的。LinkedList经常用在增删操作较多而查询操作很少的情况下,ArrayList则相反。
ArrayList和LinkedList在用法上没有区别,但是在功能上还是有区别的。LinkedList经常用在增删操作较多而查询操作很少的情况下,ArrayList则相反。
五、Map集合
实现类:HashMap、Hashtable、LinkedHashMap和TreeMap
HashMap
HashMap是最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。因为键对象不可以重复,所以HashMap最多只允许一条记录的键为Null,允许多条记录的值为Null,是非同步的
Hashtable
Hashtable与HashMap类似,是HashMap的线程安全版,它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢,它继承自Dictionary类,不同的是它不允许记录的键或者值为null,同时效率较低。
ConcurrentHashMap
线程安全,并且锁分离。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
LinkedHashMap
LinkedHashMap保存了记录的插入顺序,在用Iteraor遍历LinkedHashMap时,先得到的记录肯定是先插入的,在遍历的时候会比HashMap慢,有HashMap的全部特性。
TreeMap
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。不允许key值为空,非同步的;
我的手机 2018/4/22 11:32:58
map的遍历
第一种:KeySet()
将Map中所有的键存入到set集合中。因为set具备迭代器。所有可以迭代方式取出所有的键,再根据get方法。获取每一个键对应的值。 keySet():迭代后只能通过get()取key 。
取到的结果会乱序,是因为取得数据行主键的时候,使用了HashMap.keySet()方法,而这个方法返回的Set结果,里面的数据是乱序排放的。
典型用法如下:
Map map = new HashMap();
map.put("key1","lisi1");
map.put("key2","lisi2");
map.put("key3","lisi3");
map.put("key4","lisi4");
//先获取map集合的所有键的set集合,keyset()
Iterator it = map.keySet().iterator();
//获取迭代器
while(it.hasNext()){
Object key = it.next();
System.out.println(map.get(key));
}
第二种:entrySet()
Set<Map.Entry<K,V>> entrySet() //返回此映射中包含的映射关系的 Set 视图。(一个关系就是一个键-值对),就是把(key-value)作为一个整体一对一对地存放到Set集合当中的。Map.Entry表示映射关系。entrySet():迭代后可以e.getKey(),e.getValue()两种方法来取key和value。返回的是Entry接口。
典型用法如下:
Map map = new HashMap();
map.put("key1","lisi1");
map.put("key2","lisi2");
map.put("key3","lisi3");
map.put("key4","lisi4");
//将map集合中的映射关系取出,存入到set集合
Iterator it = map.entrySet().iterator();
while(it.hasNext()){
Entry e =(Entry) it.next();
System.out.println("键"+e.getKey () + "的值为" + e.getValue());
}
推荐使用第二种方式,即entrySet()方法,效率较高。
对于keySet其实是遍历了2次,一次是转为iterator,一次就是从HashMap中取出key所对于的value。而entryset只是遍历了第一次,它把key和value都放到了entry中,所以快了。两种遍历的遍历时间相差还是很明显的。
实现类:HashMap、Hashtable、LinkedHashMap和TreeMap
HashMap
HashMap是最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。因为键对象不可以重复,所以HashMap最多只允许一条记录的键为Null,允许多条记录的值为Null,是非同步的
Hashtable
Hashtable与HashMap类似,是HashMap的线程安全版,它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢,它继承自Dictionary类,不同的是它不允许记录的键或者值为null,同时效率较低。
ConcurrentHashMap
线程安全,并且锁分离。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
LinkedHashMap
LinkedHashMap保存了记录的插入顺序,在用Iteraor遍历LinkedHashMap时,先得到的记录肯定是先插入的,在遍历的时候会比HashMap慢,有HashMap的全部特性。
TreeMap
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序(自然顺序),也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。不允许key值为空,非同步的;
我的手机 2018/4/22 11:32:58
map的遍历
第一种:KeySet()
将Map中所有的键存入到set集合中。因为set具备迭代器。所有可以迭代方式取出所有的键,再根据get方法。获取每一个键对应的值。 keySet():迭代后只能通过get()取key 。
取到的结果会乱序,是因为取得数据行主键的时候,使用了HashMap.keySet()方法,而这个方法返回的Set结果,里面的数据是乱序排放的。
典型用法如下:
Map map = new HashMap();
map.put("key1","lisi1");
map.put("key2","lisi2");
map.put("key3","lisi3");
map.put("key4","lisi4");
//先获取map集合的所有键的set集合,keyset()
Iterator it = map.keySet().iterator();
//获取迭代器
while(it.hasNext()){
Object key = it.next();
System.out.println(map.get(key));
}
第二种:entrySet()
Set<Map.Entry<K,V>> entrySet() //返回此映射中包含的映射关系的 Set 视图。(一个关系就是一个键-值对),就是把(key-value)作为一个整体一对一对地存放到Set集合当中的。Map.Entry表示映射关系。entrySet():迭代后可以e.getKey(),e.getValue()两种方法来取key和value。返回的是Entry接口。
典型用法如下:
Map map = new HashMap();
map.put("key1","lisi1");
map.put("key2","lisi2");
map.put("key3","lisi3");
map.put("key4","lisi4");
//将map集合中的映射关系取出,存入到set集合
Iterator it = map.entrySet().iterator();
while(it.hasNext()){
Entry e =(Entry) it.next();
System.out.println("键"+e.getKey () + "的值为" + e.getValue());
}
推荐使用第二种方式,即entrySet()方法,效率较高。
对于keySet其实是遍历了2次,一次是转为iterator,一次就是从HashMap中取出key所对于的value。而entryset只是遍历了第一次,它把key和value都放到了entry中,所以快了。两种遍历的遍历时间相差还是很明显的。
六、测试实例
1、Collection类
public class CollectionTest1 { public static void main(String[] args) { CollectionTest1 ct=new CollectionTest1(); //Collection c=new ArrayList<>(); /*List c=new ArrayList<>(); c.add("tom1"); c.add(1); c.add(2.0);*/ /*Set set=new HashSet<>(); set.add("tom1"); set.add(1); set.add(2.0);*/ /*Map map=new HashMap<>(); map.put("1", "tom1"); map.put(2, "tom2"); map.put("3", "tom3"); ct.print(map);*/ int[] array={1,22,1,4,12}; ct.print(array); } public void print(Collection c){ System.out.println("----collection"); Iterator it = c.iterator(); while (it.hasNext()) { Object o = it.next(); System.out.println(o); } //增强for循环 jdk1.5 //Object代表 遍历的数据类型 //o 代表 遍历出来的每一个元素 //c 代表目标资源 需要遍历的数据 //增强for循环的底层 是使用迭代器遍历的 /*for(Object o : c){ System.out.println(o); }*/ } public void print(List list){ System.out.println("----list"); /*Iterator it = list.iterator(); while (it.hasNext()) { Object o = it.next(); System.out.println(o); }*/ /*for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); }*/ /*for(Object o : list){ System.out.println(o); }*/ } public void print(Set set){ /*Iterator it = set.iterator(); while (it.hasNext()) { Object value = it.next(); System.out.println(value); }*/ //set不能使用下标遍历 /*for(int i=0;i<set.size();i++){ System.out.println(set.get(i)); }*/ /*for(Object o:set){ System.out.println(o); }*/ } public void print(Map map){ // keySet() entrySet() values() //Set set = map.entrySet(); //Entry key value /*for(Object o:set){ Entry entry=(Entry) o; Object key = entry.getKey(); Object value = entry.getValue(); System.out.println("key:"+key+"---value:"+value); }*/ /* Iterator it = set.iterator(); while (it.hasNext()) { Object o = it.next(); Entry entry=(Entry) o; Object key = entry.getKey(); Object value = entry.getValue(); System.out.println("key:"+key+"---value:"+value); }*/ //所有的key /* Set keySet = map.keySet(); for(Object key:keySet){ System.out.print("key:"+key); System.out.println("---value:"+map.get(key)); }*/ Collection c = map.values(); //打印map集合中的所有value值 for(Object value:c){ System.out.println(value); } } public void print(int[] array){ for(int arr:array){ System.out.println(arr); } } public void print(String[] array){ for(String arr:array){ System.out.println(arr); } } }
2、Map和Set
扫描二维码关注公众号,回复:
42467 查看本文章
public class MapTest { public static void main(String[] args) { //map集合存储的key不能相同,value值可以相同 //如果key值相同 那么以最后一次覆盖的值为准 Map map=new HashMap(); //key---value map.put(1, "tom"); //Entry<K, V> map.put("name", "zhangsan"); //Entry<K, V> map.put(2, "lisi");//Entry<K, V> map.put(3, "lisi");//Entry<K, V> //Entry对象的set集合 Entry里边放的是key 和 value /*Set entrySet = map.entrySet(); Iterator it = entrySet.iterator(); while (it.hasNext()) { //Entry Object o = it.next(); //每对map集合的数据 key value Map.Entry entry=(Map.Entry)o; Object key = entry.getKey(); Object value = entry.getValue(); System.out.println("key:"+key+"--"+"value:"+value); }*/ //所有key以set集合的形式返回 /*Set keySet = map.keySet(); Iterator it1 = keySet.iterator(); while (it1.hasNext()) { //key Object key = it1.next(); Object value = map.get(key); System.out.println("key:"+key+"--"+"value:"+value); }*/ //map集合所有的value值 /*Collection c = map.values(); Iterator it2 = c.iterator(); while (it2.hasNext()) { //value Object value = it2.next(); System.out.println("value:"+value); }*/ /* map.remove("name"); map.clear();*/ //map.equals(map1); //map.hashCode(); /* boolean res=map.containsKey(1); boolean res1=map.containsValue("tom"); boolean empty = map.isEmpty(); int num=map.size();*/ //map集合是没有下标的 这样遍历不行s /*for(int i=0;i<map.size();i++){ //i=0 map.get(i); }*/ /*Map map1=new HashMap<>(); map1.put("map1key1", "1"); map1.put("map1key2", "2"); map1.put("map1key3", "3"); map1.put("map1key4", "4"); map.putAll(map1);*/ Set keySet = map.keySet(); Iterator it1 = keySet.iterator(); while (it1.hasNext()) { //key Object key = it1.next(); Object value = map.get(key); System.out.println("key:"+key+"--"+"value:"+value); } } }
3.HashCode
public class HashcodeTest { public static void main(String[] args) { Student s1=new Student(20,"tom"); Student s2=new Student(20,"tom"); //hashcode哈希码不同的两个对象,一定是不同的对象 //hashcode相同的两个对象,不一定是同一个对象 System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); Set s=new HashSet<>(); s.add(s1); s.add(s2); Iterator it=s.iterator(); while(it.hasNext()){ Object next = it.next(); System.out.println(next); } /*String ss1=new String("tom"); String ss2=new String("tom"); Set set=new HashSet(); set.add(ss1); set.add(ss2); Iterator it=set.iterator(); while(it.hasNext()){ Object next = it.next(); System.out.println(next); }*/ } }