【Java】【集合】

时间:2023-03-09 22:15:04
【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可以实现.  (应用场景:购物车等需要顺序的)

代码实例:

  1. package com.alibaba.sample.petstore.web.store.module.screen;
  2. import java.util.HashMap;
  3. import java.util.Iterator;
  4. import java.util.LinkedHashMap;
  5. import java.util.Map;
  6. import java.util.Map.Entry;
  7. import java.util.TreeMap;
  8. import javax.servlet.http.HttpServletResponse;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. public class ViewCart {
  11. @Autowired
  12. private HttpServletResponse response;
  13. public void execute() throws Exception {
  14. this.useHashMap();
  15. this.useTreeMap();
  16. this.useLikedHashMap();
  17. }
  18. public void useHashMap() throws Exception {
  19. response.getWriter().println("------无序(随机输出)------");
  20. Map<String, String> map = new HashMap<String, String>();
  21. map.put("1", "Level 1");
  22. map.put("2", "Level 2");
  23. map.put("3", "Level 3");
  24. map.put("a", "Level a");
  25. map.put("b", "Level b");
  26. map.put("c", "Level c");
  27. Iterator<Entry<String, String>> it = map.entrySet().iterator();
  28. while (it.hasNext()) {
  29. Entry<String, String> e = it.next();
  30. response.getWriter().println("Key: " + e.getKey() + ";   Value: "       + e.getValue());
  31. }
  32. }
  33. // 有序(默认排序,不能指定)
  34. public void useTreeMap() throws Exception {
  35. response.getWriter().println("------有序(但是按默认顺充,不能指定)------");
  36. Map<String, String> map = new TreeMap<String, String>();
  37. map.put("1", "Level 1");
  38. map.put("2", "Level 2");
  39. map.put("3", "Level 3");
  40. map.put("a", "Level a");
  41. map.put("b", "Level b");
  42. map.put("c", "Level c");
  43. Iterator<Entry<String, String>> it = map.entrySet().iterator();
  44. while (it.hasNext()) {
  45. Entry<String, String> e = it.next();
  46. response.getWriter().println("Key: " + e.getKey() + ";   Value: "       + e.getValue());
  47. }
  48. }
  49. public void useLikedHashMap() throws Exception {
  50. response.getWriter().println("------有序(根据输入的顺序输出)------");
  51. Map<String, String> map = new LinkedHashMap<String, String>();
  52. map.put("1", "Level 1");
  53. map.put("2", "Level 2");
  54. map.put("3", "Level 3");
  55. map.put("a", "Level a");
  56. map.put("b", "Level b");
  57. map.put("c", "Level c");
  58. Iterator<Entry<String, String>> it = map.entrySet().iterator();
  59. while (it.hasNext()) {
  60. Entry<String, String> e = it.next();
  61. response.getWriter().println("Key: " + e.getKey() + ";   Value: "       + e.getValue());
  62. }
  63. }
  64. }

返回结果:

  1. ------无序(随机输出)------
  2. Key: 3;   Value: Level 3
  3. Key: 2;   Value: Level 2
  4. Key: 1;   Value: Level 1
  5. Key: b;   Value: Level b
  6. Key: c;   Value: Level c
  7. Key: a;   Value: Level a
  8. ------有序(但是按默认顺充,不能指定)------
  9. Key: 1;   Value: Level 1
  10. Key: 2;   Value: Level 2
  11. Key: 3;   Value: Level 3
  12. Key: a;   Value: Level a
  13. Key: b;   Value: Level b
  14. Key: c;   Value: Level c
  15. ------有序(根据输入的顺序输出)------
  16. Key: 1;   Value: Level 1
  17. Key: 2;   Value: Level 2
  18. Key: 3;   Value: Level 3
  19. Key: a;   Value: Level a
  20. Key: b;   Value: Level b
  21. 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());
} }