【Java】【集合】
【1. 】HashMap,LinkedHashMap,TreeMap对比
共同点:
HashMap,LinkedHashMap,TreeMap都属于Map;Map 主要用于存储键(key)值(value)对,根据键得到值,因此键不允许键重复,但允许值重复。
不同点:
1.HashMap里面存入的键值对在取出的时候是随机的,也是我们最常用的一个Map.它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。
2.TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
3. LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现. (应用场景:购物车等需要顺序的)
代码实例:
- package com.alibaba.sample.petstore.web.store.module.screen;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.LinkedHashMap;
- import java.util.Map;
- import java.util.Map.Entry;
- import java.util.TreeMap;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.beans.factory.annotation.Autowired;
- public class ViewCart {
- @Autowired
- private HttpServletResponse response;
- public void execute() throws Exception {
- this.useHashMap();
- this.useTreeMap();
- this.useLikedHashMap();
- }
- public void useHashMap() throws Exception {
- response.getWriter().println("------无序(随机输出)------");
- Map<String, String> map = new HashMap<String, String>();
- map.put("1", "Level 1");
- map.put("2", "Level 2");
- map.put("3", "Level 3");
- map.put("a", "Level a");
- map.put("b", "Level b");
- map.put("c", "Level c");
- Iterator<Entry<String, String>> it = map.entrySet().iterator();
- while (it.hasNext()) {
- Entry<String, String> e = it.next();
- response.getWriter().println("Key: " + e.getKey() + "; Value: " + e.getValue());
- }
- }
- // 有序(默认排序,不能指定)
- public void useTreeMap() throws Exception {
- response.getWriter().println("------有序(但是按默认顺充,不能指定)------");
- Map<String, String> map = new TreeMap<String, String>();
- map.put("1", "Level 1");
- map.put("2", "Level 2");
- map.put("3", "Level 3");
- map.put("a", "Level a");
- map.put("b", "Level b");
- map.put("c", "Level c");
- Iterator<Entry<String, String>> it = map.entrySet().iterator();
- while (it.hasNext()) {
- Entry<String, String> e = it.next();
- response.getWriter().println("Key: " + e.getKey() + "; Value: " + e.getValue());
- }
- }
- public void useLikedHashMap() throws Exception {
- response.getWriter().println("------有序(根据输入的顺序输出)------");
- Map<String, String> map = new LinkedHashMap<String, String>();
- map.put("1", "Level 1");
- map.put("2", "Level 2");
- map.put("3", "Level 3");
- map.put("a", "Level a");
- map.put("b", "Level b");
- map.put("c", "Level c");
- Iterator<Entry<String, String>> it = map.entrySet().iterator();
- while (it.hasNext()) {
- Entry<String, String> e = it.next();
- response.getWriter().println("Key: " + e.getKey() + "; Value: " + e.getValue());
- }
- }
- }
返回结果:
- ------无序(随机输出)------
- Key: 3; Value: Level 3
- Key: 2; Value: Level 2
- Key: 1; Value: Level 1
- Key: b; Value: Level b
- Key: c; Value: Level c
- Key: a; Value: Level a
- ------有序(但是按默认顺充,不能指定)------
- Key: 1; Value: Level 1
- Key: 2; Value: Level 2
- Key: 3; Value: Level 3
- Key: a; Value: Level a
- Key: b; Value: Level b
- Key: c; Value: Level c
- ------有序(根据输入的顺序输出)------
- Key: 1; Value: Level 1
- Key: 2; Value: Level 2
- Key: 3; Value: Level 3
- Key: a; Value: Level a
- Key: b; Value: Level b
- Key: c; Value: Level c
4.小结:php的数组就是用hashmap实现的,所以学过php对hashmap就很容易理解,linkedhashmap跟php的数组实现的功能很像.
【2. 】栗子
/*
栗子 集合
*/ import java.lang.reflect.Array;
import java.util.*; //定义一个员工类
class Clerk{
private String name;
private int age;
private float sal;
public Clerk(String name,int age,float sal){
this.name = name;
this.age = age;
this.sal = sal;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public float getSal() {
return sal;
} public void setSal(float sal) {
this.sal = sal;
} } //创建员工类
class Empp{
private String empNo;
private String name;
private float sal;
public Empp(String empNo,String name,float sal){
this.empNo = empNo;
this.name = name;
this.sal = sal;
} public String getEmpNo() {
return empNo;
} public void setEmpNo(String empNo) {
this.empNo = empNo;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public float getSal() {
return sal;
} public void setSal(float sal) {
this.sal = sal;
}
}
public class test_two { public static void main(String[] args) { /* //ArrayList 无同步性 线程不安全 可重复
ArrayList al = new ArrayList();
System.out.println("al大小:" + al.size());
Clerk clerk1 = new Clerk("宋江",50,1000);
Clerk clerk2 = new Clerk("吴用",45,1200);
Clerk clerk3 = new Clerk("林冲",35,1300);
al.add(clerk1);
al.add(clerk2);
al.add(clerk3);
//可不可以放入同样的对象?
al.add(clerk1);
//显示大小
System.out.println("al大小:" + al.size());
//遍历
for(int i=0;i<al.size();i++){
Clerk temp = (Clerk)al.get(i);
System.out.println("名字:" + temp.getName());
}
//如何从al中删除一个对象
al.remove(1);
System.out.println("======删除吴用=======");
//遍历
for(int i=0;i<al.size();i++){
Clerk temp = (Clerk)al.get(i);
System.out.println("名字: " + temp.getName());
}*/
/* 【结果】
al大小:0
al大小:4
名字:宋江
名字:吴用
名字:林冲
名字:宋江
======删除吴用=======
名字: 宋江
名字: 林冲
名字: 宋江 */ /* //LinkedList 后进先出
LinkedList ll = new LinkedList();
Empp emp1 = new Empp("sa01","aa",1.2f);
Empp emp2 = new Empp("sa02","bb",1.2f);
Empp emp3 = new Empp("sa03","cc",1.2f);
//addFirst标识把emp1加载(链表)队列的最前面
ll.addFirst(emp1);
ll.addFirst(emp2);
//addLast表示加载(链表)队列的后面
ll.addLast(emp3);
System.out.println("测试LinkedList集合类中的addFirst以及addLast方法");
for(int i=0;i<ll.size();i++){
System.out.println(((Empp)ll.get(i)).getName());
}
//remove
ll.remove(emp1);
System.out.println("测试LinkedList集合类中的remove方法");
for(int i=0;i<ll.size();i++){
System.out.println(((Empp)ll.get(i)).getName());
}
ll.removeAll(ll);
System.out.println("测试LinkedList集合类中的removeall方法");
for(int i=0;i<ll.size();i++){
System.out.println(((Empp)ll.get(i)).getName());
}*/
/* 【结果】
测试LinkedList集合类中的addFirst以及addLast方法
bb
aa
cc
测试LinkedList集合类中的remove方法
bb
cc
测试LinkedList集合类中的removeall方法 */ /* //Vector 线程安全 具有同步性
Vector vv = new Vector();
Empp emp1 = new Empp("1","aa",1.2f);
Empp emp2 = new Empp("2","bb",1.2f);
Empp emp3 = new Empp("3","cc",1.2f);
vv.add(emp1);
vv.add(emp2);
vv.add(emp3);
//遍历
for(int i=0;i<vv.size();i++){
Empp emp = (Empp)vv.get(i);
System.out.println(emp.getName());
}*/ /*
【结果】
aa
bb
cc */ /*
【比较】
1、同步性
Vector是线程同步的。这个类中的⼀些⽅法保证了Vector中的对象是线程安全的。⽽
ArrayList则是线程异步的,因此ArrayList中的对象并不是线程安全的。因为同步的要求会
影响执⾏的效率,所以如果你不需要线程安全的集合那么使⽤ArrayList是⼀个很好的选
择,这样可以避免由于同步带来的不必要的性能开销。
2、数据增⻓
从内部实现机制来讲ArrayList和Vector都是使⽤数组(Array)来控制集合中的对象。当你
向这两种类型中增加元素的时候,如果元素的数⽬超出了内部数组⽬前的⻓度它们都需要
扩展内部数组的⻓度, Vector缺省情况下⾃动增⻓原来⼀倍的数组⻓度, ArrayList是原来
的50%,所以最后你获得的这个集合所占的空间总是⽐你实际需要的要⼤。所以如果你要
在集合中保存⼤量的数据那么使⽤Vector有⼀些优势,因为你可以通过设置集合的初始化
⼤⼩来避免不必要的资源开销 */ //Map
/*
//HashMap
HashMap hm = new HashMap();
Empp emp1 = new Empp("s001","aa",3.4f);
Empp emp2 = new Empp("s002","bb",5.6f);
Empp emp3 = new Empp("s003","cc",1.2f);
//hm.put(null,null);//可以放空值
hm.put("s001",emp1);
hm.put("s002",emp2);
hm.put("s002",emp3);//不允许key重复,所以emp3会覆盖emp2
//如果要查找标号是s002
if(hm.containsKey("s002")){
System.out.println("有该员工");
Empp emp = (Empp)hm.get("s002");
System.out.println("名字" + emp.getName());
}else{
System.out.println("没该员工");
}
//遍历HashMap中所有key和value值
Iterator it = hm.keySet().iterator();
while(it.hasNext()){
String key = it.next().toString();
Empp emp = (Empp)hm.get(key);
System.out.println("名字: " + emp.getName());
System.out.println("工资: " + emp.getSal());
}
*/ //Hashtable同步性,线程安全
/* Hashtable ht = new Hashtable();
Empp emp4 = new Empp("s101","a1",2.2f);
Empp emp5 = new Empp("s102","a2",1.2f);
Empp emp6 = new Empp("s103","a3",4.2f);
ht.put("s101",emp4);
ht.put("s102",emp5);
ht.put("s103",emp6);
//遍历
for(Iterator it = ht.keySet().iterator();it.hasNext();){
String key = it.next().toString();
Empp emp = (Empp)ht.get(key);
System.out.println("名字: " + emp.getName() + "\t工资: " + emp.getSal()); }*/
/* 【比较】
1、历史原因
Hashtable是基于陈旧的Dictionary类的, HashMap是java 1.2引进的Map接⼝的⼀个实
现。
2、同步性
Hashtable是线程同步的。这个类中的⼀些⽅法保证了Hashtable中的对象是线程安全
的。⽽HashMap则是线程异步的,因此HashMap中的对象并不是线程安全的。因为同步的
要求会影响执⾏的效率,所以如果你不需要线程安全的集合那么使⽤HashMap是⼀个很好
的选择,这样可以避免由于同步带来的不必要的性能开销,从⽽提⾼效率。
3、值
HashMap可以让你将空值作为⼀个表的条⽬的key或value但是Hashtable是不能放⼊空值
的(null) 【如何选用集合类】
1、要求线程安全,使⽤Vector、 Hashtable
2、不要求线程安全,使⽤ArrayList,LinkedList,HashMap
3、要求key和value键值,则使⽤HashMap,Hashtable
4、数据量很⼤,⼜要线程安全,则使⽤Vector */ //Set HashSet类, TreeSet类
/* HashSet是基于HashMap实现的, HashSet底层采⽤HashMap来保存所有元素。
hashCode和equal()是HashMap⽤的,因为⽆需排序所以只需要关注定位和唯⼀性即可
hashCode是⽤来计算hash值的, hash值是⽤来确定hash表索引的
hash表中的⼀个索引存放的是⼀张链表,所以还要通过equal⽅法循环⽐较链上的每⼀个对
象才可以真正定位到键值对应的Entry
put时,如果hash表中没定定位到,就在链表前加⼀个Entry,如果定位到了,则更换Entry
中的value(值)并返回旧value(值)
覆写key的hashCode()和equal()时⼀定要注意,不要把它们和可变属性关联上,否则属性
变了之后hashCode会变, equal也会为false,这样在Map中就找不到它了⽽且这样的对象
因为找不到它所以得不到释放,这样就变成了⼀个⽆效引⽤(相当于内存泄漏) */ //HashSet /* HashSet<Empp> hs = new HashSet<Empp>();
Empp emp1 = new Empp("s001","aa",1.2f);
Empp emp2 = new Empp("s002","bb",1.6f);
Empp emp3 = new Empp("s003","cc",1.8f);
Empp emp4 = new Empp("s001","aa",1.2f);
hs.add(emp1);
hs.add(emp2);
hs.add(emp3);
hs.add(emp4);
hs.add(emp1);//重复的emp1,HashSet会自动去除
System.out.println("HashSet_size=" + hs.size());
System.out.println();
ArrayList<Empp> al = new ArrayList<Empp>();
Empp emp5 = new Empp("s004","dd",1.0f);
Empp emp6 = new Empp("s005","ee",2.5f);
al.add(emp5);
al.add(emp6);
hs.addAll(al);
System.out.println("HashSet_ArrayList_size=" + hs.size());
System.out.println();
//转换数组o[],遍历并输出HashSet中的元素
Object o[] = hs.toArray();
for(int i=0;i<o.length;i++){
System.out.println("工号: " + ((Empp)o[i]).getEmpNo() + "\t姓名: " + ((Empp)o[i]).getName() + "\t薪资: " + ((Empp)o[i]).getSal()); }*/ /*
【结果】
HashSet_size=4 HashSet_ArrayList_size=6 工号: s002 姓名: bb 薪资: 1.6
工号: s004 姓名: dd 薪资: 1.0
工号: s003 姓名: cc 薪资: 1.8
工号: s001 姓名: aa 薪资: 1.2
工号: s001 姓名: aa 薪资: 1.2
工号: s005 姓名: ee 薪资: 2.5 */ //TreeSet /*
TreeSet集合类是⼀个有序集合,它的元素按照升序排序,默认是⾃然顺序排列,也就是
说
TreeSet中的对象元素需要实现Comparable接⼝。 TreeSet与HashSet类⼀样没有get()⽅法
来获取列表中的元素,所以也只能通过迭代器⽅法来获取。
由于TreeMap需要排序, 所以需要⼀个Comparator为键值进⾏⼤⼩⽐较,当然也是⽤
Compar ato r定位的Compar ato r可以在创建Tr e eM ap时指定,这时排序时使⽤
Comparator.compare
如果创建时没有指定Comparator那么就会使⽤key.compareTo()⽅法,这就要求key必须实
现Comparable接⼝
TreeMap是使⽤Tree数据结构实现的,所以使⽤compare接⼝就可以完成定位了。
TreeSet是依靠TreeMap来实现的, TreeSet是⼀个有序集合,它的元素按照升序排列,默
认是按照⾃然顺序排列,也就是说TreeSet中的对象元素需要实现Comparable接⼝。
TreeSet类中跟HashSet类⼀要也没有get()⽅法来获取列表中的元素,所以也只能通过迭代
器的⽅法来获取 */
//传递一个比较器来实现你自己的排序方式
//TreeSet treeSet = new TreeSet(new StudentComparator());
/*
TreeSet treeSet = new TreeSet(new StudentComparator());
【结果】
根据StudentComparator类的compare方法实现排序:
根据StudentComparator类的compare方法实现排序:
根据StudentComparator类的compare方法实现排序:
根据StudentComparator类的compare方法实现排序:
根据StudentComparator类的compare方法实现排序:
根据StudentComparator类的compare方法实现排序:
num=301; name=张三; sal:1.2
num=101; name=王五; sal:3.0
num=101; name=穷一; sal:3.0
num=201; name=李二; sal:5.6
*/
//TreeSet treeSet = new TreeSet();
/*
TreeSet treeSet = new TreeSet();
【结果】
根据Student本类的compareTo方法实现排序:
根据Student本类的compareTo方法实现排序:
根据Student本类的compareTo方法实现排序:
根据Student本类的compareTo方法实现排序:
根据Student本类的compareTo方法实现排序:
根据Student本类的compareTo方法实现排序:
num=101; name=王五; sal:3.0
num=201; name=李二; sal:5.6
num=301; name=张三; sal:1.2
*/
//TreeSet treeSet = new TreeSet(new Student(201,"散散",1.1f));
/*
TreeSet treeSet = new TreeSet(new Student(201,"散散",1.1f));
并且此时把Student本类的CompareTo方法注释掉,并且不实现Comparator类
【结果】
根据Student本类的compare方法实现排序:
根据Student本类的compare方法实现排序:
根据Student本类的compare方法实现排序:
根据Student本类的compare方法实现排序:
根据Student本类的compare方法实现排序:
根据Student本类的compare方法实现排序:
num=201; name=lier; sal:5.6
num=101; name=qiongyi; sal:3.0
num=101; name=wangwu; sal:3.0
num=301; name=zhangsan; sal:1.2
*/
/*
treeSet.add(new Student(301,"zhangsan",1.2f));
treeSet.add(new Student(201,"lier",5.6f));
treeSet.add(new Student(101,"wangwu",3.0f));
treeSet.add(new Student(101,"qiongyi",3.0f));
Iterator it = treeSet.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
*/ /*
【比较】
HashSet 和 TreeSet
HashSet是基于hash算法实现的,性能优于TreeSet。通常使⽤HashSet,在我们需要对其中
元素排序的时候才使⽤TreeSet */ /*
【集合总结】
1. List Set 都是继承Collection接口
2. List :元素有放入顺序,可重复 不做排序和编辑
Set:元素无放入顺序,不可重复 使用自己背部的排序方法。但是,元素虽无放入顺序,但是顺序是
由该元素的HashCode决定的,其位置其实是固定的。
Map:同样对每个元素保存一份,但是基于“key”de .也有内置的排序,因而不关心元素添加的顺序。
如果添加元素的顺序对程序设计很重要,应该使用LinkedHashSet 或者 LinkedHashMap 3. List接口有三个实现类:ArrayList LinkedList Vector 。 Set 接口有两个实现类:HashSet (底层由HashMap实现),LinkedHashSet List的功能⽅法
实际上有两种List:⼀种是基本的ArrayList其优点在于随机访问元素,另⼀种是更强⼤
的LinkedList它并不是为快速随机访问设计的,⽽是具有⼀套更通⽤的⽅法。
List:次序是List最重要的特点:它保证维护元素特定的顺序。 List为Collection添加了许
多⽅法,使得能够向List中间插⼊与移除元素(这只推荐LinkedList使⽤)⼀个List可以⽣成
Listlterator,使⽤它可以从两个⽅向遍历List,也可以从List中间插⼊和移除元素。
ArrayList:由数组实现的List。允许对元素进⾏快速随机访问,但是向List中间插⼊与移
除元素的速率很慢。 Listlterator只应该⽤来由后向前遍历ArrayList。⽽不是⽤来插⼊和移
除元素。因为那⽐LinkedList开销要⼤很多。
LinkedList:对顺序访问进⾏了优化,向List中间插⼊与删除的开销并不⼤。随机访问则
相对较慢。 (使⽤ArrayList代替)还具有下列⽅法: addFirst(), addLast(), getFirst(),
getLast(), removeFirst()和removeLast()这些⽅法(没有在任何接⼝或基类中定义过)使得
LinkedList可以当作堆栈、队列和双向队列使⽤。
Set的功能⽅法
Set具有与Collection完全⼀样的接⼝,因此没有任何额外的功能,不象前⾯有两个不同
的List。实际上Set就是Collection,只是⾏为不同。 (这是继承与多态思想的典型应⽤:表
现不同的⾏为。 )Set不保存重复的元素(⾄于如何判断元素相同则较为负责)
Set:存⼊Set的每个元素都必须是唯⼀的,因为Set不保存重复元素。加⼊Set的元素必
需定义equals()⽅法以确保对象的唯⼀性。 Set与Collection有完全⼀样的接⼝。 Set接⼝不
保证维护元素的次序。
HashSet:为快速查找设计的Set。存⼊HashSet的对象必须定义hashCode()。
TreeSet:保存次序的Set,底层为树结构。使⽤它可以从Set中提取有序的序列。
LinkedHashSet:具有HashSet的查询速度,且内部使⽤链表维护元素的顺序(插⼊的次
序)。于是在使⽤迭代器遍历Set时,结果会按元素插⼊的次序显示。
Map的功能⽅法
⽅法put(Object key,Object value)添加⼀个"值"(想要得东⻄)和与"值"相关的"键"(key)(使
⽤它来查找)。⽅法get(Object key)返回与给定"键"相关联的"值"。可以⽤containsKey()和
containsValue()测试Map中是否包含某个"键"或"值"。标准的java类库中包含了⼏种不同的
Map: HashMap, TreeMap, LinkedHashMap, WeakHashMap, ldentityHashMap。它们都
有同样的基本接⼝Map,但是⾏为、效率、排序策略、保存对象的⽣命周期和判定"键"等价
的策略等各不相同。
执⾏效率是Map的⼀个⼤问题。看看get()要做哪些事,就会明⽩为什么在ArrayList中搜
索"键"是相当慢的。这正是HashMap提⾼速度的地⽅。 HashMap使⽤了特殊的值,称为"散
列码"(hash code),来取代对键的缓慢搜索。 "散列码"是"相对唯⼀"⽤以代表对象的int值,
它是通过将该对象的某些信息进⾏转换⽽⽣成的。所有java对象都能产⽣散列码,因为
hashCode()是定义在基类Object中的⽅法。
HashMap就是使⽤对象的hashCode()进⾏快速查询的。此⽅法能够显著提⾼性能。
Map:维护"键值对"的关联性,使你可通过"键"查找"值"
HashMap: Map基于散列表的实现。插⼊和查询"键值对"的开销是固定的。可以通过构
造器设置容量capacity和负载因⼦load factor,以调整容器的性能。
LinkedHashMap:类似于HashMap,但是迭代遍历它时,取得"键值对"的顺序是其插⼊
次序,或者是最近最少使(LRU)的次序。只能HashMap慢⼀点。⽽在迭代访问时发⽽更快,
因为它使⽤键表维护内部次序。
TreeMap:基于红⿊树数据结果的实现。查看"键"或"键值对"时,它们会被排序(次序由
Comparabel或Comparator决定)。 TreeMap的特点在于,你得到的结果是经过排序的。
TreeMap是唯⼀的带有subMap()⽅法的Map,它可以返回⼀个⼦树。
WeakHashMap:旨键(weak key)Map, Map中使⽤的对象也被允许释放:这是为解决特殊
问题设计的。如果没有map之外的引⽤指向某个"键",则此"键"可以被垃圾收集器回收。
ldentifyHashMap:使⽤==代替equals()对"键"作⽐较的hash map。专为解决特殊问题⽽
设计。
-------------------------------------------------------------------------------
Java中的Iterator(迭代器)的⽤法
java.util包中包含了⼀系列重要的集合类,集合类的根接⼝Collection。
Collection接⼝是所有集合类的根类型。它的⼀个主要的接⼝⽅法是:
boolean add(Object c)添加数据
add()⽅法将添加⼀个新元素。注意这个⽅法会返回⼀个boolean,但是返回值不是表示
添加成功与否。 Collection规定:如果⼀个集合拒绝添加这个元素,⽆论任何原因,都必
须抛出异常。这个返回值表示的意义是add()⽅法执⾏后,集合的内容是否改变了(就是元
素有⽆数量,位置等变化),这是由具体类实现的。即:如果⽅法出错,总会抛出异常;返
回值仅仅表示该⽅法执⾏后这个Collection的内容有⽆变化。
类似还有:
boolean addall(Collection c);添加所有数据
boolean remove(Object o);删除数据
boolean removeall(Collection c);删除所有数据
boolean remainall(Collection c);保持所有数据
Object[]toArray()⽅法很简单,把集合转换成数组返回。 Object[]toArray(Object[] a)⽅
法就有点复杂了,⾸先,返回的Object[]仍然是把集合的所有元素变成数组,但是类型和
参数a的类型是相同的。
如: String[] o=(String)c.toArray(new String[0]);
得到的o实际类型是String[]数组。
其次,如果参数a的⼤⼩装不下集合的所有元素,返回的将是⼀个新的数组。如果参数a
的⼤⼩能装下集合的所有元素,则返回的还是a,但a的内容⽤集合的元素来填充。尤其要
注意的是,如果a的⼤⼩⽐集合元素的个数还多, a后⾯的部分全部被置为null(空)。
最后⼀个最重要的⽅法是Iterator(),返回⼀个Iterator(迭代⼦),⽤于遍历集合的所有
元素。
⽤Iterator模式实现遍历集合
Iterator模式 是⽤于遍历集合类的标准访问⽅法。它可以把访问逻辑从不同类型的集合类
中抽象出来,从⽽避免向客户端暴露集合的内部结构。
例如,如果没有使⽤Iterator,遍历⼀个数组的⽅法是使⽤索引:
for(int i=0;i<array.size();i++){..get(i)...}
⽽访问⼀个链表(LinkedList)⼜必须使⽤while循环:
while((e=e.next())!=null){...e.data()...}
以上两种⽅法客户端都必须事先知道集合的内部结构,访问代码和集合本身是紧耦合,
⽆法将访问逻辑从集合类和客户端代码中分离出来,每⼀种集合对应⼀种遍历⽅法,客户
端代码⽆法复⽤。
更恐怖的是,如果以后需要把ArrayList更换为LinkedList,则原来的客户端代码必须全
部重写。
为解决以上问题, Iterator模式总是⽤同⼀种逻辑来遍历集合:
for(Iterator it=c.iterater();it.hasNext();){ ...}
奥秘在于客户端⾃身不维护遍历集合的"指针",所有的内部状态(如当前元素位置,是
否有下⼀个元素)都由Iterator来维护,⽽这个Iterator由集合类通过⼯⼚⽅法⽣成,因
此,它知道如何遍历整个集合。
客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前", "向后", "取当
前元素"的命令,就可以间接遍历整个集合。
⾸先看看java.util.Iterator接⼝的定义:
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
*/ } } class Student implements Comparator,Comparable{
private int num;//学号
private String name;//姓名
private float sal;//学费
public Student(int num,String name,float sal){
this.num = num;
this.name = name;
this.sal = sal;
}
//这是实现Comparable的方法
public int compareTo(Object o){
System.out.println("根据Student本类的compareTo方法实现排序: ");
Student st = (Student)o;
int result ;
result = num>st.num?1:(num==st.num?0:-1);
return result; } //这是实现Comparator的方法
public int compare(Object o1,Object o2){
System.out.println("根据Student本类的compare方法实现排序: ");
Student st1 = (Student)o1;
Student st2 = (Student)o2;
return st1.name.compareTo(st2.name);
} //重写toString (),否则打印出来的是Student@4ec4396a这种格式的
public String toString(){
return "num=" + num + "; name=" + name + "; sal:" + sal;
} public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public float getSal() {
return sal;
} public void setSal(float sal) {
this.sal = sal;
}
} class StudentComparator implements Comparator{ public int compare(Object o1,Object o2){
System.out.println("根据StudentComparator类的compare方法实现排序: ");
Student st1 = (Student)o1;
Student st2 = (Student)o2;
int result;
result = st1.getSal()>st2.getSal()?1:(st1.getSal()==st2.getSal()?0:-1);
if(result == 0){
result = st1.getName().compareTo(st2.getName());
}
return result; }
}
/*
【总结】
排序方法的使用顺序:
① new TreeSet(new StudentComparator()) 按照这里的参数
② new TreeSet() Student本类实现Comparable接口的compare方法,即使实现的接口的第一顺序是Comparator接口
③ new TreeSet(new Student()) 如果Student本类未实现Comparable接口的compare方法,则调用Student实现Comparator接口的comparaTo方法 * */
# 栗子 集合 补充
Person.java
import java.util.Arrays; public class Person implements Comparable<Person> {
String name;
int age;
public Person(String name,int age){
super();
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
} public int compareTo(Person p){
return this.age - p.getAge();
//return this.name.compareTo(p.getName());
} public static void main(String[] args){
Person[] people = new Person[]{new Person("xujian",20),new Person("wxue",2),new Person("yiewei",10)};
System.out.println("用Comparable按照年龄排序,排序前");
for(Person person:people){
System.out.print(person.getName() + ":" + person.getAge()); }
Arrays.sort(people);
System.out.println("\n排序后");
for(Person person:people){
System.out.print(person.getName() + ":" + person.getAge()); } Person[] people1 = new Person[]{new Person("xujian",20),new Person("wxue",2),new Person("yiewei",10)};
System.out.println("\n用Comparator按照名字排序了,\n排序前");
for(Person person:people1){
System.out.print(person.getName() + ":" + person.getAge()); }
Arrays.sort(people1,new PersonComparator());
System.out.println("\n排序后");
for(Person person:people1){
System.out.print(person.getName() + ":" + person.getAge()); } } }
/*
【结果】
用Comparable按照年龄排序,排序前
xujian:20wxue:2yiewei:10
排序后
wxue:2yiewei:10xujian:20
用Comparator按照名字排序了,
排序前
xujian:20wxue:2yiewei:10
排序后
wxue:2xujian:20yiewei:10
*/
/*
【比较】
三、Comparable和Comparator区别比较 Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。 Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。 两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。 */
PersonComparator.java
import java.util.Comparator; public class PersonComparator implements Comparator<Person> {
public int compare(Person o1,Person o2){
return o1.getName().compareTo(o2.getName());
} }
【Java】【集合】的更多相关文章
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- Scala集合和Java集合对应转换关系
作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 用Scala编码的时候,经常会遇到scala集合和Java集合互相转换的case,特意mark一 ...
- java集合你了解多少?
用了java集合这么久,还没有系统的研究过java的集合结构,今天亲自画了下类图,总算有所收获. 一.所有集合都实现了Iterable接口. Iterable接口中包含一个抽象方法:Iterator& ...
- 深入java集合学习1-集合框架浅析
前言 集合是一种数据结构,在编程中是非常重要的.好的程序就是好的数据结构+好的算法.java中为我们实现了曾经在大学学过的数据结构与算法中提到的一些数据结构.如顺序表,链表,栈和堆等.Java 集合框 ...
- Java集合框架List,Map,Set等全面介绍
Java集合框架的基本接口/类层次结构: java.util.Collection [I]+--java.util.List [I] +--java.util.ArrayList [C] +- ...
- Java集合框架练习-计算表达式的值
最近在看<算法>这本书,正好看到一个计算表达式的问题,于是就打算写一下,也正好熟悉一下Java集合框架的使用,大致测试了一下,没啥问题. import java.util.*; /* * ...
- 【集合框架】Java集合框架综述
一.前言 现笔者打算做关于Java集合框架的教程,具体是打算分析Java源码,因为平时在写程序的过程中用Java集合特别频繁,但是对于里面一些具体的原理还没有进行很好的梳理,所以拟从源码的角度去熟悉梳 ...
- Java 集合框架
Java集合框架大致可以分为五个部分:List列表,Set集合.Map映射.迭代器.工具类 List 接口通常表示一个列表(数组.队列.链表 栈),其中的元素 可以重复 的是:ArrayList 和L ...
- Java集合概述
容器,是用来装东西的,在Java里,东西就是对象,而装对象并不是把真正的对象放进去,而是指保存对象的引用.要注意对象的引用和对象的关系,下面的例子说明了对象和对象引用的关系. String str = ...
- 深入java集合系列文章
搞懂java的相关集合实现原理,对技术上有很大的提高,网上有一系列文章对java中的集合做了深入的分析, 先转载记录下 深入Java集合学习系列 Java 集合系列目录(Category) HashM ...
随机推荐
- Codeforce 835B - The number on the board (贪心)
Some natural number was written on the board. Its sum of digits was not less than k. But you were di ...
- Autel MaxiSys Elite Diagnostic Tool Common problem solving methods
1. updating MaxiFlash Elite to firmware 3.21? My maxisys communicate with the MaxiFlash J2534 but Ma ...
- zabbix 监控项(key)
Key 描述 返回值 参数 详细说明 agent.hostname 返回被监控端名称 字符串 - 返回配置文件中配置的被监控端的名称 agent.ping 检测被监控端是否存活 1 - 运行中 其他 ...
- EL和jstl(概念和使用方法)
概念: 1 . JSP 标签 是用来替换java代码的技术,容器遇到标签后会将其转换成java代码,jsp标签类似于开始标记.属性.结束标记.标签体. EL表达式是一套简单的运算规则,用于给jsp标 ...
- Golang中map的三种声明方式和简单实现增删改查
package main import ( "fmt" ) func main() { test3 := map[string]string{ "one": & ...
- Golang字符串函数认识(二)
package main import ( "fmt" "strings" ) func main(){ //返回字符在指定字符串中最后一次出现的位置 last ...
- bzoj1227 P2154 [SDOI2009]虔诚的墓主人
P2154 [SDOI2009]虔诚的墓主人 组合数学+离散化+树状数组 先看题,结合样例分析,易得每个墓地的虔诚度=C(正左几棵,k)*C(正右几棵,k)*C(正上几棵,k)*C(正下几棵,k),如 ...
- Delphi XE5 for Android (十一)
以下内容是根据Delphi的帮助文件进行试验的,主要测试Android下的消息提醒. 首先建立一个空白的Android工程,然后在窗体中加入一个TNotificationCenter控件,如下图: 再 ...
- Android Java层,Native层,Lib层打印Log简介【转】
本文转载自:https://blog.csdn.net/AndroidMage/article/details/52225068 说明: 这里我根据个人工作情况说明在各个层打印log.如有问题欢迎拍砖 ...
- MySQL 命令操作数据表
MySQL 命令操作数据表 1.查看表信息 desc hs_user_credit_info; 2.新增表字段 alter table hs_credit_order add search_relat ...