Java 集合
Collection<<interface>>
├List<<interface>>
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set<<interface>>
└HashSet
Map<<interface>>
├Hashtable
├HashMap
└WeakHashMap
1. Collection 和 Collections的区别
java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
java.util.Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作
class Demo {
public Demo() {}
public static void main(String[] args){
ArrayList c = new ArrayList();
for (int i = 0; i < 3; i++) {
c.add(new Integer(i));
}
c.add("11");
c.add("22");
c.add("33");
Iterator it = c.iterator();
System.out.println("排序前的输出:\n");
for (int i = 0; i < c.size(); i++) {
System.out.println("" + c.get(i));
}
Collections.shuffle(c, new Random());
System.out.println("排序后的输出:\n");
while (it.hasNext()) {
System.out.println("" + it.next());
}
}
}
2. HashMap和Hashtable的区别
Hashtable继承自Dictionary类, size()表示包含了多少元素;isEmpty()判断是否包含了元素;put(Object key, Object value)添加一个值;get(Object key)获得与某个键对应的值;而remove(Object Key)从列表中删除“键-值”对。还可以使用枚举技术:keys()产生对键的一个枚举(Enumeration);而elements()产生对所有值的一个枚举。这便是一个Dictionary(字典)的全部。
(1) 继承和实现区别
Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。
(2) 线程安全不同
HashTable的方法是同步的,HashMap是未同步,所以在多线程场合要手动同步HashMap。HashMap效率高
(3) 对null的处理不同
HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)。
HashTable 不允许null值,编译期不会检查,运行期会出现空指针异常。HashMap允许 null值是指可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。
(4) 方法不同 HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。
(5) HashTable使用Enumeration,HashMap使用Iterator。
(6) HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
HashTable测试
public static void main(String ar()[]) { Hashtable hash = new Hashtable(); hash.put("abc", "1"); hash.put("ddd", "1"); hash.put("asdf", "2"); // hash.put("asdfsad", null); NullPointerException Enumeration enumkey = hash.keys(); while (enumkey.hasMoreElements()) { String str = (String) enumkey.nextElement(); System.out.println(str + " --- " + hash.get(str)); if ("1".equals(hash.get(str))) hash.remove(str); } System.out.println("asdf:" + hash.get("asdf")); enumkey = hash.elements(); while (enumkey.hasMoreElements()) { String str = (String) enumkey.nextElement(); System.out.println(str ); } }
HashMap测试
public static void main(String[] args) {
// 在HashMap中的对象是无序的
HashMap hm = new HashMap();
hm.put("a", "wpskl 1");
hm.put("b", "wpskl 3");
hm.put("c", "wpskl 5");
// 测试是否包含关键字"a"
System.out.println(hm.containsKey("a"));//true
System.out.println(hm.containsKey("d"));//false
System.out.println(hm.get("a")); //wpskl 1
System.out.println(hm.entrySet());
//[a=wpskl 1, c=wpskl 5, b=wpskl 3]
Iterator it = hm.entrySet().iterator();
while (it.hasNext()) {
System.out.println(it.next());
//a=wpskl 1,c=wpskl 5,b=wpskl 3
}
// Set keySet()返回关键字的集合
it = hm.keySet().iterator();
while (it.hasNext()) {
System.out.println(hm.get(it.next()));
//get(key)返回关键字对应的值
}
// Collection values()返回值的集合
it = hm.values().iterator();
while (it.hasNext()) {
System.out.println(it.next());
//wpskl 1,wpskl 5,wpskl 3
}
}
3. List总结(ArrayList,Vector, LinkedList)
List除了具有Collection接口必备的iterator()方法外,它还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历
ArrayList,Vector, LinkedList的存储性能和特性:
(1)ArrayList是最常用的List实现类,内部通过数组实现,它允许对元素进行快速随机访问。当数组大小不满足时会增加存储能力(默认大小是10,每次扩充为原来的1.5倍),将已有数组数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行拷贝,移动,代价比较高。因此,它适合随即查找和遍历,不适合插入合删除。
(2)Vector与ArrayList一样,也是通过数组实现的。它支持线程的同步,避免多线程同时写引起的不一致性。但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
List list = Collections.synchronizedList(new ArrayList());//创建同步的ArrayList
(3)LinkedList使用双向链表实现存储,很适合数据的动态插入和删除,随即访问和遍历速度比较慢。另外,它还提供了List没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
(4)堆栈类继承Vector,Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Stack;
import java.util.Vector;
//演示List的使用 List是能维护元素的次序,它允许元素重复
public class TestList {
//初始化一个List
public static void init(List list) {
if (list != null) {
list.add("aaa");
list.add("ccc");
list.add("bbb");
list.add("eee");
list.add("ddd");
}
}
//输出List的内容
public static void output(List list) {
if (list != null) {// 根据列表下标遍历,使用list.size()获取列表中元素的个数
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
// 或者用迭代器遍历
Iterator it = list.iterator();
Object value = null;
while (it.hasNext()) {
value = it.next();
// System.out.println(value);
}//或
for(Iterator i=list.iterator();i.hasNext();){
value=i.next();
}
}
}
//使用ArrayList
public static void testArrayList() {
List list = new ArrayList();
init(list);
System.out.println("使用ArrayList: ");
output(list);
}
//使用Vector
public static void testVector() {
List list = new Vector();
init(list);
System.out.println("使用Vector: ");
output(list);
}
//使用LinkedList
public static void testLinkedList() {
List list = new LinkedList();
init(list);
System.out.println("使用LinkedList: ");
output(list);
}
public static void main(String[] args) {
TestList.testArrayList();
TestList.testVector();
TestList.testLinkedList();
List list = new ArrayList();
init(list);
// List支持元素重复
list.add("aaa");
list.add("bbb");
System.out.println("插入元素aaa, bbb后:");
output(list); //在末尾添加
list.add(1, "fff");// 指定元素插入的位置
System.out.println("在下标为1处插入fff后:");
output(list);
List list2 = new ArrayList();
list2.add("ggg");
list2.add("hhh");
// 将另一列表中的元素插入到列表中
list.addAll(list2);
System.out.println("添加list2的元素后:");
output(list);
// 判断列表是否包含某一元素
// 通过元素的equals方法,判断元素是否相等
System.out.println("list包含aaa? " + list.contains("aaa"));
// 判断列表中是否包含了另外一个列表中的所有元素。
System.out.println("list包含list2中的所有元素? " + list.containsAll(list2));
// 定位一个元素在列表中最先出现的位置System.out.println("aaa在list中第一次出现的位置: " + list.indexOf("aaa"));
// 定位一个元素在列表中最后出现的位置System.out.println("aaa在list中最后一次出现的位置: " + list.lastIndexOf("aaa"));
list.set(2, "xxx");// 更新列表中某个位置的元素值
System.out.println("更新位置为2的元素为xxx后:");
output(list);
// 删除列表中的某个元素,只删除第一次出现的那个
list.remove("aaa");
System.out.println("删除元素aaa后:");
output(list);
list.remove(1); // 删除列表中指定位置的元素
System.out.println("删除下标为1的元素后:");
output(list);
// 删除列表中的其他元素,只保留另一个列表中包含的元素
list.retainAll(list2);
System.out.println("删除除list2包含的以外的元素后:");
output(list);
// 删除列表中在另一列表中也包含了的元素
list.removeAll(list2);
System.out.println("删除list2包含的元素后:");
output(list);
list.clear();// 清空列表
// 判断列表中是否有数据
System.out.println("清空List后" + list.isEmpty());
init(list);
// 用列表中的某些元素构造一个新的列表
list2 = list.subList(1, 3);
System.out.println("用list的第1个到第3个元素构造一个新的List:");
output(list2);
// 用List特有的遍历器ListIterator遍历列表
// 与普通的Iterator不用,它允许两个方向遍历列表
ListIterator listIt = list.listIterator();
System.out.println("正向遍历列表");
while (listIt.hasNext()) {
System.out.print(listIt.next());
}
System.out.println("反向遍历列表");
while (listIt.hasPrevious()) {
System.out.print(listIt.previous());
}
// 也可以使用ListIterator从List中间插入和删除元素,
// 只能在遍历器当前位置添加和删除。
listIt.add("newadd");
System.out.println("ListIterator往列表中添加元素newadd后: ");
output(list);
listIt.next();
listIt.remove();
System.out.println("用ListIterator删除列表中元素后: ");
output(list);
// LinkedList自定义的方法
LinkedList linklist = new LinkedList();
init(linklist);
linklist.addFirst("fff");// 添加元素到列表头
System.out.println("把fff放到列表头后:");
output(linklist);
// 添加元素到列表尾
linklist.addLast("eee");
System.out.println("把eee放到列表尾后:");
output(linklist);
// 获取表头元素
System.out.println("列表头元素:" + linklist.getFirst());
// 获取表尾元素
System.out.println("列表尾元素:" + linklist.getLast());
linklist.removeFirst();// 删除列表头的元素
System.out.println("删除列表头元素后:");
output(linklist);
linklist.removeLast();// 删除列表尾的元素
System.out.println("删除列表尾元素后:");
output(linklist);
// 堆栈Stack类,它继承自Stack类
Stack myStack = new Stack();
myStack.push("aaa");// 插入元素,是插入到尾部
myStack.push("bbb");
myStack.push("ccc");
myStack.push("ddd");
myStack.push("aaa");
myStack.push("ddd");
System.out.println("堆栈中的元素是: ");
output(myStack);
System.out.println("堆栈尾部元素: " + myStack.peek());
System.out.println("弹出堆栈尾部元素: " + myStack.pop());
}
}
4. Map
Map接口提供3种集合的视图:
map的key不能够重复,value可以
(1)key-value映射集合 — entrySet() 返回包含映射的Set视图。Set中的每个元素都是一个Map.Entry对象,可以使用getKey()和getValue()方法(还有一个setValue() 方法)访问后者的键元素和值元素
(2)key集合 — keySet() 包含键的 Set 视图。删除 Set 中的元素还将删除 Map 中相应的映射(键和值)
(3)value集合,values() 是值的 Collection 视图。删除 Collection 中的元素还将删除 Map 中相应的映射(键和值)
我们还必须获得一个Iterator对象,进而取得相应的key-value映射、key和value。
Iterator keyValuePairs = aMap.entrySet().iterator();
Iterator keys = aMap.keySet().iterator();//keys.remove();删除当前键值对
Iterator values = aMap.values().iterator();//values.remove();删除当前键值对
Map增删方法
clear() 从 Map 中删除所有映射
remove(Object key) 从 Map 中删除键和关联的值
put(Object key, Object value) 将指定值与指定键相关联
Map访问方法
get(Object key) 返回与指定键关联的值
containsKey(Object key) 如果 Map 包含指定键的映射,则返回true
containsValue(Object value) 如果此 Map 将一个或多个键映射到指定值,则返回 true
isEmpty() 如果 Map 不包含键-值映射,则返回 true
size() 返回 Map 中的键-值映射的数目
5. 集合排序
list,set,map都是可以使用collections.sort()排序,http://lavasoft.blog.51cto.com/62575/68380
Java API针对集合类型排序提供了两种支持:
java.util.Collections.sort(java.util.List)
java.util.Collections.sort(java.util.List, java.util.Comparator)
实现Comparable接口
/*实现Comparable接口*/
// 要排序的元素对象
public class Cat implements Comparable<Cat> {
private int age;
private String name;
public Cat(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return "Cat{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public int compareTo(Cat o) {
return this.getAge() - o.getAge();
}
}
实现个性化排序测试
import java.util.*;
//通过实现Comparable接口实现个性化排序测试
public class TestComparable {
public static String outCollection(Collection coll) {
StringBuffer sb = new StringBuffer();
for (Object obj : coll) {
sb.append(obj + "\n");
}
System.out.println(sb.toString());
return sb.toString();
}
public static void main(String args[]) {
test();
test2();
}
public static void test() {
System.out.println("----------test()---------");
System.out.println("升序排序测试:");
List<Cat> listCat = new ArrayList<Cat>();
Cat cat1 = new Cat(34, "hehe");
Cat cat2 = new Cat(12, "haha");
Cat cat3 = new Cat(23, "leizhimin");
Cat cat4 = new Cat(13, "lavasoft");
listCat.add(cat1);
listCat.add(cat2);
listCat.add(cat3);
System.out.println("原集合为:");
outCollection(listCat);
System.out.println("调用Collections.sort(List<T> list)排序:");
Collections.sort(listCat);
outCollection(listCat);
System.out.println("逆序排列元素:");
Collections.sort(listCat, Collections.reverseOrder());
outCollection(listCat);
System.out.println("再次逆序排列元素:");
Collections.reverse(listCat);
outCollection(listCat);
System.out.println("添加一个元素后输出集合:");
listCat.add(cat4);
outCollection(listCat);
System.out.println("排列后输出:");
Collections.sort(listCat);
outCollection(listCat);
}
针对数组的排序测试
public static void test2(){
String[] strArray = new String[] {"z", "a", "C"};
System.out.println("----数组转换为列表-------");
List<String> list = Arrays.asList(strArray);
outCollection(list);
System.out.println("----列表转换为数组(1)-----");
String[] strArrayNew1 = list.toArray(strArray);
for(String str:strArrayNew1){
System.out.println(str);
}
System.out.println("---列表转换为数组(2)-----");
String[] strArrayNew2 = (String[]) list.toArray();
for(String str:strArrayNew2){
System.out.println(str);
}
System.out.println("----顺序排序列表------");
Collections.sort(list);
outCollection(list);
System.out.println("---按String实现的Comparator对象 String.CASE_INSENSITIVE_ORDER排序----");
Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
outCollection(list);
System.out.println("-----倒序排序列表------");
Collections.sort(list, Collections.reverseOrder());
outCollection(list);
System.out.println("-----按String实现的Comparator对象String.CASE_INSENSITIVE_ORDER排序----");
Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
outCollection(list);
System.out.println("-----反转列表元素的顺序------");
Collections.reverse(list);
outCollection(list);
}
}
Comparator接口排序
//要排序的元素对象
public class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
import java.util.Comparator;
//Person类的排序接口
public class PersonComparator implements
Comparator<Person> {
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
}
import java.util.*;
/* 结论:排序针对的是确切的集合对象,当集合对象的元素发生变化时,集合内的元素不会自动重新排序. */
public class TestComparator {
public static String outCollection(Collection coll) {
StringBuffer sb = new StringBuffer();
for (Object obj : coll) {
sb.append(obj + "\n");
}
System.out.println(sb.toString());
return sb.toString();
}
public static void main(String args[]) { test1(); }
public static void test1() {
System.out.println("----------test1()---------");
System.out.println("升序排序测试:");
List<Person> listPerson = new ArrayList<Person>();
Person person1 = new Person(34, "lavasoft");
Person person2 = new Person(12, "lavasoft");
Person person3 = new Person(23, "leizhimin");
Person person4 = new Person(13, "sdg");
listPerson.add(person1);
listPerson.add(person2);
listPerson.add(person3);
Comparator<Person> ascComparator = new PersonComparator();
//利用Collections静态工具方法对List进行排序
Collections.sort(listPerson, ascComparator);
outCollection(listPerson);
System.out.println("继续添加一个Person对象:");
listPerson.add(person4);
outCollection(listPerson);
System.out.println("添加一个对象后,重新排序:");
Collections.sort(listPerson, ascComparator);
outCollection(listPerson);
System.out.println("\n降序排序测试:");
Comparator<Person> descComparator = Collections.reverseOrder(ascComparator);
System.out.println("利用反转后的排序接口对象:");
Collections.sort(listPerson, descComparator);
outCollection(listPerson);
System.out.println("\n求最大最小元素测试:");
Person p_max = Collections.max(listPerson, ascComparator);
Person p_min = Collections.min(listPerson, ascComparator);
System.out.println("最大元素为:" + p_max.toString());
System.out.println("最小元素为:" + p_min.toString());
}
}
集合Map排序
Map<String, Integer> map = new TreeMap<String, Integer>();
map.put("j2se", 20);
map.put("j2ee", 10);
map.put("j2me", 30);
List<Map.Entry<String, Integer>> infoIds = new ArrayList<Map.Entry<String, Integer>>( map.entrySet());
//排序前
for (int i = 0; i < infoIds.size(); i++) {
String id = infoIds.get(i).toString();
System.out.println(id);
}
//排序
Collections.sort(infoIds, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1,Map.Entry<String, Integer> o2) {
return (o2.getValue() - o1.getValue());
} });
//排序后
for (int i = 0; i < infoIds.size(); i++) {
String id = infoIds.get(i).toString();
System.out.println(id);
}
排序前:
j2ee=10
j2me=30
j2se=20
排序后:
j2me=30
j2se=20
j2ee=10
6. java中hashcode()和equals()
equals()和hashcode()这两个方法都是从object类中继承过来的。String 、Math、还有Integer、Double等都覆盖了equals和hashcode方法
equals()方法在object类中定义如下:默认是按地址值进行的比较(即对象的引用)
public boolean equals(Object obj) { return (this == obj); }
hashcode默认是对象的地址,由于在内存中的地址肯定是不同的,所以运算得到的hashcode一般不会相同。
hashCode的作用: hashCode()是用来产生哈希玛的,而哈希玛是用来在散列存储结构中确定对象的存储地址的。HashSet来说,在将对象存入其中时,通过被存入对象的 hashCode() 来确定对象在 HashSet 中的存储地址,通过equals()来确定存入的对象是否重复,hashCode() ,equals()都需要自己重新定义。
equals()相等的两个对象,hashcode()一定相等;
hashcode()相等,equals()可能相等,也可能不等
public class HashSetTest {
public static void main(String[] args) {
HashSet<Student> hs = new HashSet<Student>();
hs.add(new Student(1, "zhangsan"));
hs.add(new Student(2, "lisi"));
hs.add(new Student(3, "wangwu"));
hs.add(new Student(1, "zhangsan"));
Iterator<Student> it = hs.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
class Student {
int num;
String name;
Student(int num, String name) {
this.num = num;
this.name = name;
}
public int hashCode() {
return num*name.hashCode();
}
public boolean equals(Object o) {
Student s = (Student) o;
return num == s.num && name.equals(s.name);
}
public String toString() {
return num + ":" + name;
}
}