一、集合与数组
数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用。数组一旦定义,长度将不能再变化。
集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数情况下使用。
二、层次关系
三、几种常用的接口和类简介
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
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);
}*/
}
}