• Java 类集框架


    Java 类集框架http://blog.csdn.net/chai_daguanren/article/details/5111988

    1. Java类集框架产生的原因

            在基础的应用中,我们可以通过数组来保存一组对象或者基本数据,但数组的大小是不可更改的,因此出于灵活性的考虑和对空间价值的担忧,我们可以使用链表来实现动态的数组。灵活的代价是操作上的繁琐,在计算机的世界,处理繁琐问题的不二法门就是将其封装,只向外暴露以供调用的方法视图。Java类集框架就是对这一方法的一种官方实现——一套动态对象数组的操作类,它其实就是Java对数据结构的一个大概的封装。

    2. 三个核心接口

    1. //存放单值的最大父接口——Collection  
    2. public interface Collection<E> extends Iterable<E>  
    3.   
    4. //存放一对数据的最大接口——Map  
    5. public interface Map<K,V>  
    6.   
    7. //通用的输出接口——Iterator  
    8. public interface Iterator<E>  

    备注:泛型的说明

            在JDK1.5之后,这些接口都增加了泛型的定义,最早的时候这三个接口中的内容都使用Object进行操作。出于安全问题的考虑,以及避免转型之间的繁琐,JDK1.5将整个类集框架都升级为泛型,真是造福大众呀!!!

    3. Collection和它的孩子们

            按照面向对象的考虑,在使用单值集合时应以接口Collection来作为父类引用,但实践的结果是Collection的两个子接口List和Set获得了更多的青睐。

    1. Collection的主要方法视图:

    1. //1.添加一个元素  
    2. public boolean add(E e);  
    3. //2.清空集合  
    4. public void clear();  
    5. //3.是否包含特定元素  
    6. public boolean contains(E e);  
    7. //4.实例化Iterator遍历接口  
    8. public Iterator<E> iterator();  
    9. //5.从集合中删除特定的元素  
    10. public boolean remove(Object o);  
    11. //6.取得集合的大小  
    12. public int size();  
    13. //7.将集合转变为一个对象数组输出  
    14. public Object[] toArray();  
    15. //8.将集合转变为一个对象数组输出--泛型版本  
    16. public <T> T[] toArray();  

    2. List(Collection的一个子接口——允许重复且有序)的新增的主要方法视图:

    1. //1.在指定的位置上添加一个元素  
    2. public void add(int index, E element);  
    3. //2.取得指定位置上的元素  
    4. public E get(int index);  
    5. //3.修改指定位置上的元素,返回原先的元素  
    6. public E set(int index, E element);  
    7. //4.为ListIterator接口实例化  
    8. public ListIterator<E> listIterator();  
    9. //5.删除指定位置上的元素,返回删除的那个元素的引用  
    10. public E remove(int index);  

     备注:ListIterator

            它是Iterator接口的一个子接口,可以向前向后遍历List,而Iterator只能向后遍历。

    2.1 新的子类:ArrayList

    1. public class ArrayList<E> extends AbstractList<E>  
    2.                           implements List<E>,RandomAccess,Cloneable,Serializable  

    2.1.1 范例:设置内容

    1. import java.util.ArrayList;  
    2. import java.util.List;  
    3. public class ArrayListDemo01 {  
    4.     public static void main(String[] args) {  
    5.         List<String> all = new ArrayList<String>(); // 实例化List接口  
    6.         all.add("hello"); // 向集合中增加内容  
    7.         all.add("world"); // 向集合中增加内容  
    8.         all.add("!!!"); // 向集合中增加内容  
    9.         for (int x = 0; x < all.size(); x++) {  
    10.             System.out.println(all.get(x)) ;   
    11.         }  
    12.     }  
    13. }  

    说明:本例中使用List接口接收ArrayList实例,在取出数据的时候使用了List接口自己才有的get(int index)方法,如果使用Collection接收,取出数据时要先将其中的数据放到一个数组,然后从数组中取。如下例:

    2.1.2 范例:Collection转换成数组输出

    1. import java.util.ArrayList;  
    2. import java.util.Collection;  
    3. public class ArrayListDemo02 {  
    4.     public static void main(String[] args) {  
    5.         Collection<String> all = new ArrayList<String>(); // 实例化List接口  
    6.         all.add("hello"); // 向集合中增加内容  
    7.         all.add("world"); // 向集合中增加内容  
    8.         all.add("!!!"); // 向集合中增加内容  
    9.         all.remove("!!!"); // 从集合中删除指定对象  
    10.         Object obj[] = all.toArray(); // 将所有的内容变为对象数组  
    11.         for (int x = 0; x < obj.length; x++) {  
    12.             String str = (String) obj[x];  
    13.             System.out.print(str + "、");  
    14.         }  
    15.     }  
    16. }  

    说明:为了对输出数组的运行时类型进行更精确的控制,可以使用如下的方式来连接数组与集合。

    2.1.3 范例:Collection转换成数组输出(精确控制数组类型)

    1. import java.util.ArrayList;  
    2. import java.util.Collection;  
    3. public class ArrayListDemo02 {  
    4.     public static void main(String[] args) {  
    5.         Collection<String> all = new ArrayList<String>(); // 实例化List接口  
    6.         all.add("hello"); // 向集合中增加内容  
    7.         all.add("world"); // 向集合中增加内容  
    8.         all.add("!!!"); // 向集合中增加内容  
    9.         all.remove("!!!"); // 从集合中删除指定对象  
    10.         Object obj[] = all.toArray(new String[]{}); // 将所有的内容变为对象数组  
    11.                   //或者Object obj[] = alll.toArray(new String[0]);  
    12.         for (int x = 0; x < obj.length; x++) {  
    13.             String str = (String) obj[x];  
    14.             System.out.print(str + "、");  
    15.         }  
    16.     }  
    17. }  

     说明:toArray()能够将集合转换成对象数组,是两种对象管理方式之间的桥梁,也连接了双方的API。

    2.2 旧的子类:Vector

            Vector是最早的数据结构的实现类,也称为向量,在JDK1.0时并没有现在的类集框架的概念,它只是一个应需而生的操作类。在JDK1.2之后提出 了类集框架,一系列专门设计的接口被推出,为了保留这个类,JDK1.2让它实现了List接口,完成类集的大一统。

    范例:Vector的常规应用

    1. import java.util.List;  
    2. import java.util.Vector;  
    3. public class VectorDemo {  
    4.     public static void main(String[] args) {  
    5.         List<String> all = new Vector<String>(); // 实例化List接口  
    6.         all.add("hello"); // 向集合中增加内容  
    7.         all.add("world"); // 向集合中增加内容  
    8.         all.add("!!!"); // 向集合中增加内容  
    9.         for (int x = 0; x < all.size(); x++) {  
    10.             System.out.println(all.get(x)) ;   
    11.         }  
    12.     }  
    13. }  

     2.3 ArrayList和Vector的比较

    二者的操作接口基本一致,其区别是在内部的实现上:ArrayList在JDK1.2推出,比Vector晚,它采用异步处理的方式,而非 Vector的同步方式,所以速度比较快,这也是它比较受欢迎的原因。相应的,ArrayList非线程安全,Vector则是线程安全的。二者都是 List的实现类,都可以依靠size()和get()两个方法完成循环输出,都支持Iterator输出,不过Vector还支持 Enumeration的输出方式,在实际运用中这种方式很少用到。

    3. 不允许重复的子接口:Set

    List接口中的内容是允许重复的,但是如果现在要求集合中的内容不能重复的话,就只能使用Set接口。Set接口不像List那样对Collection进行了大量的扩充,它对外的方法视图与Collection是完全一样的。

    3.1 散列存放的子类:HashSet

    1. public class HashSet<E>  
    2. extends AbstractSet<E>  
    3. implements Set<E>, Cloneable, Serializable  

    HashSet的定义方式和ArrayList很相似。

    范例:添加元素与输出

    1. import java.util.HashSet;  
    2. import java.util.Set;  
    3. public class HashSetDemo {  
    4.     public static void main(String[] args) {  
    5.         Set<String> all = new HashSet<String>();  
    6.         all.add("hello");  
    7.         all.add("hello"); // 重复设置  
    8.         all.add("world");  
    9.         all.add("!!!");  
    10.         System.out.println(all) ;  
    11.     }  
    12. }  

    说明:在Set接口中不允许有重复的元素存在,而且其中的元素是无序的,称为散列存放。

    3.2 排序存放的子类:TreeSet

    范例:排序存放

    1. import java.util.Set;  
    2. import java.util.TreeSet;  
    3. public class TreeSetDemo {  
    4.     public static void main(String[] args) {  
    5.         Set<String> all = new TreeSet<String>();  
    6.         all.add("B");  
    7.         all.add("B");  
    8.         all.add("X");  
    9.         all.add("C");  
    10.         all.add("A");  
    11.         System.out.println(all);  
    12.     }  
    13. }  

    说明:TreeSet不允许有重复内容,而且添加元素无序,输出时却是有序输出。

    3.3 关于排序的补充

    TreeSet中的元素对象可以排序要求它们实现Comparable接口,事先指定好排序规则。

    范例:排序加入,compareTo()为0的对象元素将不会被再次添加

    1. import java.util.Set;  
    2. import java.util.TreeSet;  
    3. class Person implements Comparable<Person> {  
    4.     private String name;  
    5.     private int age;  
    6.     public Person(String name, int age) {  
    7.         this.name = name;  
    8.         this.age = age;  
    9.     }  
    10.     public String toString() {  
    11.         return "姓名:" + this.name + ",年龄:" + this.age;  
    12.     }  
    13.     @Override  
    14.     public int compareTo(Person o) {  
    15.         if (this.age < o.age) {  
    16.             return 1;  
    17.         } else if (this.age > o.age) {  
    18.             return -1;  
    19.         } else {  
    20.             return this.name.compareTo(o.name);   
    21.         }  
    22.     }  
    23. }  
    24. public class SortDemo {  
    25.     public static void main(String[] args) {  
    26.         Set<Person> all = new TreeSet<Person>();  
    27.         all.add(new Person("张三", 20));  
    28.         all.add(new Person("李四", 20));  
    29.         all.add(new Person("李四", 20));  
    30.         all.add(new Person("王五", 19));  
    31.         System.out.println(all);  
    32.     }  
    33. }  

     3.4 关于重复元素的补充

    Comparable可以完成TreeSet类中重复元素的判断,如果这种判断重复的方式通用的话,那么在HashSet中应该也能够使用。但是测 试的结果否定了这样的猜测,Set中去掉重复元素的操作不是靠Comparable完成,它们靠两个方法来确定,这两个方法在Object中提供了定义:

    1. public boolean equals(Object obj);  
    2.   
    3. public int hashCode();  

    hashCode()可以为对象提供一个标示编号,如果要对对象内容进行验证需要重写equals()方法。hashCode()返回一个数字,它是通过特定的算法得到的,指定算法并不难,指定一个好的使同一个hashCode尽可能少地对应对象就需要花些心思了。

    范例:重写hashCode()和equals()

    1. import java.util.HashSet;  
    2. import java.util.Set;  
    3. class Person{  
    4.     private String name;  
    5.     private int age;  
    6.     public Person(String name, int age) {  
    7.         this.name = name;  
    8.         this.age = age;  
    9.     }  
    10.     @Override  
    11.     public int hashCode() {  
    12.         final int prime = 31;  
    13.         int result = 1;  
    14.         result = prime * result + age;  
    15.         result = prime * result + ((name == null) ? 0 : name.hashCode());  
    16.         return result;  
    17.     }  
    18.     @Override  
    19.     public boolean equals(Object obj) {  
    20.         if (this == obj)  
    21.             return true;  
    22.         if (obj == null)  
    23.             return false;  
    24.         if (getClass() != obj.getClass())  
    25.             return false;  
    26.         Person other = (Person) obj;  
    27.         if (age != other.age)  
    28.             return false;  
    29.         if (name == null) {  
    30.             if (other.name != null)  
    31.                 return false;  
    32.         } else if (!name.equals(other.name))  
    33.             return false;  
    34.         return true;  
    35.     }  
    36.     public String toString() {  
    37.         return "姓名:" + this.name + ",年龄:" + this.age;  
    38.     }  
    39. }  
    40. public class RepeatDemo {  
    41.     public static void main(String[] args) {  
    42.         Set<Person> all = new HashSet<Person>();  
    43.         all.add(new Person("张三", 20));  
    44.         all.add(new Person("李四", 20));  
    45.         all.add(new Person("李四", 20));  
    46.         all.add(new Person("王五", 19));  
    47.         System.out.println(all);  
    48.     }  
    49. }  

    说明:JVM在管理众多的对象时,其底层实现采用的是一个大的哈希表,这个哈希表可 能是用数组来模拟的,数组的下标是hashCode,在哈希表上每个值对应的是一个链表,链表中有哈希值相同的对象的引用。这样进行对象查找时就可以如同 查字典一样,先计算对象的hashCode,这时的hashCode如果一个索引;然后迅速定位到索引所对应的对象链表,然后借助equals的内容比较 方式进行属性的逐一比对以找到对应的对象。

    4. 集合输出

    在实际的应用中,只要是集合的输出基本上都不会采用将其变为对象数组的方式。

    遍历的方式有如下四种,它们的使用率是不一样的:

    Iterator--95%

    ListIterator--1%

    Enumeration--4%

    foreach--0%

    4.1 迭代输出:Iterator

    Iterator只声明了三个方法:

    1. //判断是否有下一个元素  
    2. public boolean hasNext();  
    3.   
    4. //取出当前的元素  
    5. public E next();  
    6.   
    7. //删除当前的内容(不常用)  
    8. public void remove();  

    范例:集合输出的标准操作

    1. import java.util.ArrayList;  
    2. import java.util.Iterator;  
    3. import java.util.List;  
    4. public class IteratorDemo {  
    5.     public static void main(String[] args) {  
    6.         List<String> all = new ArrayList<String>();  
    7.         all.add("hello");  
    8.         all.add("world");  
    9.         Iterator<String> iter = all.iterator();  
    10.         while (iter.hasNext()) { // 指针向下移动,判断是否有内容  
    11.             String str = iter.next();  
    12.             System.out.print(str + "、");  
    13.         }  
    14.     }  
    15. }  

    4.2 双向迭代输出:ListIterator

    Iterator接口完成的是从前往后的单向输出,如果要实现双向输出则要借助它的子接口:ListIterator

    1. public interface ListIterator<E>  
    2. extends Iterator<E>  
    3.   
    4. //ListIterator新增的方法:  
    5. //判断是否有前一个元素  
    6. public boolean hasPrevious();  
    7. //取出前面的元素  
    8. public E previous();  

    要实现ListIterator,只能借助List的listIterator()来获得,Collection并没有提供。

    范例:双向遍历

    1. import java.util.ArrayList;  
    2. import java.util.List;  
    3. import java.util.ListIterator;  
    4. public class ListIteratorDemo {  
    5.     public static void main(String[] args) {  
    6.         List<String> all = new ArrayList<String>();  
    7.         all.add("hello");  
    8.         all.add("world");  
    9.         ListIterator<String> iter = all.listIterator();  
    10.         System.out.println("=========== 由前向后输出 ============");  
    11.         while (iter.hasNext()) {  
    12.             System.out.print(iter.next() + "、");  
    13.         }  
    14.         System.out.println("/n=========== 由后向前输出 ============");  
    15.         while (iter.hasPrevious()) {  
    16.             System.out.print(iter.previous() + "、");  
    17.         }  
    18.     }  
    19. }  

    4.3 几乎废弃的接口:Enumeration

    Enumeration接口是Iterator的前辈,发展到现在已经很少使用了。

    以下是Enumeration提供的方法(名字起得挺长的):

    1. //判断是否有下一个元素  
    2. public boolean hasMoreElements();  
    3.   
    4. //取出当前的元素  
    5. public E nextElement();  

    Enumeration的限制:Collection接口本身并不支持这种输出,只有与之同时期的Vector支持这种输出方式。在Vector类中定义了这样的方法:public Enumeration<E> elements();

    范例:使用Enumeration输出

    1. import java.util.Enumeration;  
    2. import java.util.Vector;  
    3. public class EnumerationDemo {  
    4.     public static void main(String[] args) {  
    5.         Vector<String> all = new Vector<String>();  
    6.         all.add("hello");  
    7.         all.add("world");  
    8.         Enumeration<String> enu = all.elements();  
    9.         while (enu.hasMoreElements()) {  
    10.             String str = enu.nextElement();  
    11.             System.out.print(str + "、");  
    12.         }  
    13.     }  
    14. }  

    4.4 新的支持:foreach

    JDK1.5为我们提供了一种新的集合输出方式,即增强型的for循环,它的语法比较简洁,但语法简洁的代价是灵活性的缺失,所以很多开发人员并不常用。

    范例:foreach输出

    1. import java.util.ArrayList;  
    2. import java.util.List;  
    3. public class ForEachDemo {  
    4.     public static void main(String[] args) {  
    5.         List<String> all = new ArrayList<String>();  
    6.         all.add("hello");  
    7.         all.add("world");  
    8.         for (String str : all) {  
    9.             System.out.println(str);  
    10.         }  
    11.     }  
    12. }  

    5. Map接口

    Collection接口操作的时候每次都会向集合中添加一个元素,但是如果要添加的元素是一对的话,就要使用Map接口来完成了,其定义如下:

    1. public interface Map<K,V>  
    2. //K表示键,V表示值  

    Map的常用方法的视图:

    1. //向集合中添加元素,返回与key值以前关联的value,如果之前没有关联则返回null  
    2. public V put(K key, V value);  
    3. //根据key获得value  
    4. public V get(Object key);  
    5. //取出所有的key  
    6. public Set<K> keySet();  
    7. //取出所有的value  
    8. public Collection<V> values();  
    9. //删除一个指定的key  
    10. public V remove(Object key);  
    11. //将所有的键值对变为Set集合  
    12. public Set<Map.Entry<K,V>> entrySet();   

    在Map接口的内部还定义了一个内部接口——Map.Entry,因为采用static interface来定义,所以外部可以通过Map.Entry来访问。

    5.1 新的子类:HashMap

    如果要使用Map的话,可以使用HashMap对其进行实例化。

    范例:添加与查询

    1. import java.util.HashMap;  
    2. import java.util.Map;  
    3. public class HashMapDemo01 {  
    4.     public static void main(String[] args) {  
    5.         Map<String, String> all = new HashMap<String, String>();  
    6.         all.put("BJ", "BeiJing");  
    7.         all.put("NJ", "NanJing");  
    8.         String value = all.get("BJ"); // 根据key查询出value  
    9.         System.out.println(value);  
    10.         System.out.println(all.get("TJ"));  
    11.     }  
    12. }  

    说明:在Map的操作中,会依据key来获得对应的value,如果找不到,则会返回null。

    由于现在使用的是HashMap子类,所以里面的key值可以有一个为null。

    范例:key值为null

    1. import java.util.HashMap;  
    2. import java.util.Map;  
    3. public class HashMapDemo02 {  
    4.     public static void main(String[] args) {  
    5.         Map<String, String> all = new HashMap<String, String>();  
    6.         all.put("BJ", "BeiJing");  
    7.         all.put("NJ", "NanJing");  
    8.         all.put(null, "NULL");  
    9.         System.out.println(all.get(null));  
    10.     }  
    11. }  

     范例:借助keySet()来获得所有key的集合,然后遍历Map

    1. import java.util.HashMap;  
    2. import java.util.Iterator;  
    3. import java.util.Map;  
    4. import java.util.Set;  
    5. public class HashMapDemo03 {  
    6.     public static void main(String[] args) {  
    7.         Map<String, String> all = new HashMap<String, String>();  
    8.         all.put("BJ", "BeiJing");  
    9.         all.put("NJ", "NanJing");  
    10.         all.put(null, "NULL");  
    11.         Set<String> set = all.keySet();  
    12.         Iterator<String> iter = set.iterator();  
    13.         while (iter.hasNext()) {  
    14.             String key = iter.next() ;  
    15.             System.out.println(key + " --> " + all.get(key)) ;    
    16.         }  
    17.     }  
    18. }  

    5.2 Map集合的输出

    正统做法:依靠Iterator来输出,但Map本身并不能直接为Iterator实例化,如果非要使用Iterator输出Map集合的话,则要采用如下的步骤:

    1. 将所有的Map集合通过entrySet()方法变成Set集合,里面的每一个元素都是Map.Entry的实例;
    2. 利用Set接口中提供的iterator()方法来为Iterator接口实例化;
    3. 通过迭代,并且利用Map.Entry接口完成key与value的分离。

    范例:使用Iterator输出Map

    1. import java.util.HashMap;  
    2. import java.util.Iterator;  
    3. import java.util.Map;  
    4. import java.util.Set;  
    5. public class MapPrint {  
    6.     public static void main(String[] args) {  
    7.         Map<String, String> all = new HashMap<String, String>();  
    8.         all.put("BJ", "BeiJing");  
    9.         all.put("NJ", "NanJing");  
    10.         all.put(null, "NULL");  
    11.         Set<Map.Entry<String, String>> set = all.entrySet();  
    12.         Iterator<Map.Entry<String, String>> iter = set.iterator();  
    13.         while (iter.hasNext()) {  
    14.             Map.Entry<String, String> me = iter.next();  
    15.             System.out.println(me.getKey() + " --> " + me.getValue());  
    16.         }  
    17.     }  
    18. }  

    5.3 有序的存放:TreeMap

    HashMap子类中的key都属于无序存放的,如果现在希望有序则可以通过TreeMap来实现(按key排序),但是需要注意的是既然按照key来排序,而key又是对象,所以就要求key实现Comparable接口。

    范例:TreeMap的简单使用

    1. import java.util.Set;  
    2. import java.util.TreeMap;  
    3. public class TreeMapDemo {  
    4.     public static void main(String[] args) {  
    5.         Map<String, String> all = new TreeMap<String, String>();  
    6.         all.put("BJ", "BeiJing");  
    7.         all.put("NJ", "NanJing");  
    8.         Set<Map.Entry<String, String>> set = all.entrySet();  
    9.         Iterator<Map.Entry<String, String>> iter = set.iterator();  
    10.         while (iter.hasNext()) {  
    11.             Map.Entry<String, String> me = iter.next();  
    12.             System.out.println(me.getKey() + " --> " + me.getValue());  
    13.         }  
    14.     }  
    15. }  

    5.4 旧的子类:Hashtable

    Hashtable和Vector都是属于JDK1.0时推出的集合操作类,在JDK1.2之后为了保留让它实现了Map接口。

    范例:Hashtable的使用

    1. import java.util.Hashtable;  
    2. import java.util.Iterator;  
    3. import java.util.Map;  
    4. import java.util.Set;  
    5. public class HashtableDemo {  
    6.     public static void main(String[] args) {  
    7.         Map<String, String> all = new Hashtable<String, String>();  
    8.         all.put("BJ", "BeiJing");  
    9.         all.put("NJ", "NanJing");  
    10.         Set<Map.Entry<String, String>> set = all.entrySet();  
    11.         Iterator<Map.Entry<String, String>> iter = set.iterator();  
    12.         while (iter.hasNext()) {  
    13.             Map.Entry<String, String> me = iter.next();  
    14.             System.out.println(me.getKey() + " --> " + me.getValue());  
    15.         }  
    16.     }  
    17. }  

    5.5 HashMap和Hashtable的区别

    No.               区别点                      HashMap                                         Hashtable

    1.                 推出时间                   JDK1.2之后                                       JDK1.0

    2.                 线程处理                   异步处理                                            同步处理

    3.                 性能                         较快                                                  较慢

    4.                 安全性                      非线程安全                                         线程安全

    5.                 支持null                    允许key设置为null                             不允许key为null,否则会有NullPointerException

    5.6 关于key的说明

    在Map中如果一个任意的对象需要作为key保存时,则该对象需要实现Object中的equals()和hashCode()方法。

    范例:覆写equals()和hashCode()来保证对象可以做key

    1. import java.util.HashMap;  
    2. import java.util.Map;  
    3. class Person {  
    4.     private String name;  
    5.     private int age;  
    6.     public Person(String name, int age) {  
    7.         this.name = name;  
    8.         this.age = age;  
    9.     }  
    10.     public String toString() {  
    11.         return "姓名:" + this.name + ",年龄:" + this.age;  
    12.     }  
    13.     @Override  
    14.     public int hashCode() {  
    15.         final int prime = 31;  
    16.         int result = 1;  
    17.         result = prime * result + age;  
    18.         result = prime * result + ((name == null) ? 0 : name.hashCode());  
    19.         return result;  
    20.     }  
    21.     @Override  
    22.     public boolean equals(Object obj) {  
    23.         if (this == obj)  
    24.             return true;  
    25.         if (obj == null)  
    26.             return false;  
    27.         if (getClass() != obj.getClass())  
    28.             return false;  
    29.         Person other = (Person) obj;  
    30.         if (age != other.age)  
    31.             return false;  
    32.         if (name == null) {  
    33.             if (other.name != null)  
    34.                 return false;  
    35.         } else if (!name.equals(other.name))  
    36.             return false;  
    37.         return true;  
    38.     }  
    39. }  
    40. public class MapKeyDemo {  
    41.     public static void main(String[] args) {  
    42.         Map<Person, String> all = new HashMap<Person, String>();  
    43.         all.put(new Person("张三", 20), "ZS");  
    44.         System.out.println(all.get(new Person("张三", 20)));  
    45.     }  
    46. }  

    说明:在很多情况下,通常直接使用String作为key,String类本身已经覆写了equals()和hashCode()。

    6. Stack类

    Stack表示的是栈的操作类,栈是一种典型的先进先出的设计,此类是Vector的子类。

    常规操作:

    1. //入栈  
    2. public E push(E item);  
    3. //出栈  
    4. public E pop();  

    范例:入栈与出栈的操作

    1. import java.util.Stack;  
    2. public class StackDemo {  
    3.     public static void main(String[] args) {  
    4.         Stack<String> s = new Stack<String>();  
    5.         s.push("A");  
    6.         s.push("B");  
    7.         s.push("C");  
    8.         System.out.println(s.pop());  
    9.         System.out.println(s.pop());  
    10.         System.out.println(s.pop());  
    11.         System.out.println(s.pop());  
    12.     }  
    13. }  

    7. Properties类

    Properties类的主要功能是用于操作属性,在各个语言(包括操作系统)都会存在着许多的配置文件。所有的属性文件中的属性都是按照“key=value”的形式保存的,而且保存的内容都是String(字符串),此类定义如下:

    public class Properties extends Hashtable<Object,Object>

             此类是Hashtable的子类,而且已经默认指定好了泛型是Object,但是所有的属性操作中的类型肯定都是字符串,那么操作的时候主要使用的是Properties类完成。

             Properties类中定义的主要操作方法:

    No.

    方法名称

    类型

    描述

    1

    public Object setProperty(String key,String value)

    普通

    设置属性

    2

    public String getProperty(String key)

    普通

    根据属性的名字取得属性的内容,如果没有返回null结果

    3

    public String getProperty(String key,String defaultValue)

    普通

    根据属性的名字取得属性内容,如果没有则返回默认值(defaultValue)

    4

    public void list(PrintStream out)

    普通

    从一个输出流中显示所有的属性内容

    5

    public void store(OutputStream out,String comments) throws IOException

    普通

    向输出流中输出属性

    6

    public void load(InputStream inStream) throws IOException

    普通

    从输入流中读取属性内容

    7

    public void storeToXML(OutputStream os,String comment)  throws IOException

    普通

    以XML文件格式输出属性内容

    8

    public void loadFromXML(InputStream in) throws IOException,InvalidPropertiesFormatException

    普通

    以XML文件格式输入属性内容

    7.1、设置和取得属性

    import java.util.Properties;

    public class PropertiesDemo01 {

        public static void main(String[] args) {

            Properties pro = new Properties();

            pro.setProperty("BJ", "BeiJing");

            pro.setProperty("NJ", "NanJing");

            System.out.println(pro.getProperty("BJ"));

            System.out.println(pro.getProperty("TJ"));

            System.out.println(pro.getProperty("TJ", "没有此地区"));

        }

    }

    7.2、保存和读取属性

             所有的属性的内容都是可以通过输出和输入流进行保存和读取的,下面先通过代码观察如何保存在普通的文件之中。

    import java.io.File;

    import java.io.FileOutputStream;

    import java.util.Properties;

    public class PropertiesDemo02 {

        public static void main(String[] args) throws Exception {

            Properties pro = new Properties();

            pro.setProperty("BJ", "BeiJing");

            pro.setProperty("NJ", "NanJing");

            pro.store(new FileOutputStream(new File("D:" + File.separator

                    + "area.properties")), "AREA INFO");

        }

    }

             此时通过一个普通的文件流将所有的属性保存在了文件之中,而且一定要记住,所有的属性文件一定要使用“*.properties”作为后缀。

    import java.io.File;

    import java.io.FileInputStream;

    import java.util.Properties;

    public class PropertiesDemo03 {

        public static void main(String[] args) throws Exception {

            Properties pro = new Properties();

            pro.load(new FileInputStream(new File("D:" + File.separator

                    + "area.properties")));

            System.out.println(pro.getProperty("BJ"));

            System.out.println(pro.getProperty("TJ"));

            System.out.println(pro.getProperty("TJ", "没有此地区"));

        }

    }

             以上是将属性保存在了普通文件之中,也可以将其保存在XML文件之中,代码如下:

    import java.io.File;

    import java.io.FileOutputStream;

    import java.util.Properties;

    public class PropertiesDemo04 {

        public static void main(String[] args) throws Exception {

            Properties pro = new Properties();

            pro.setProperty("BJ", "BeiJing");

            pro.setProperty("NJ", "NanJing");

            pro.storeToXML(new FileOutputStream(new File("D:" + File.separator

                    + "area.xml")), "AREA INFO");

        }

    }

             以后肯定也只能从XML文件格式中读取属性了。

    import java.io.File;

    import java.io.FileInputStream;

    import java.util.Properties;

    public class PropertiesDemo05 {

        public static void main(String[] args) throws Exception {

            Properties pro = new Properties();

            pro.loadFromXML(new FileInputStream(new File("D:" + File.separator

                    + "area.xml")));

            System.out.println(pro.getProperty("BJ"));

            System.out.println(pro.getProperty("TJ"));

            System.out.println(pro.getProperty("TJ", "没有此地区"));

        }

    }

    7.3、列出属性

             在实际的开发中,如果使用了IO流进行操作的话,有可能由于编码的不同而造成乱码的问题,因为程序的编码和本地环境的编码不统一,所以会造成乱码的显示,那么该如何查询本地编码呢,就需要通过Properties类的list()方法完成。

    public class PropertiesDemo06 {

        public static void main(String[] args) throws Exception {

            System.getProperties().list(System.out) ;

        }

    }

             关于文件的编码,在程序中主要有以下几种:

                       · GB2312、GBK:表示的是国标编码,2312表示的是简体中文,而GBK包含了简体和繁体中文

                       · ISO 8859-1:主要用于英文字母的编码方式

                       · UNICODE:Java中使用十六进制进行编码,能够表示出世界上所有的编码

                       · UTF编码:中文采用十六进制,而普通的字母依然采用和ISO 8859-1一样的编码

             在以后的程序中经常会出现乱码的问题,这种问题造成的根本原因就是在于编码不统一。

    import java.io.File;

    import java.io.FileOutputStream;

    import java.io.OutputStream;

    public class EncodingDemo {

        public static void main(String[] args) throws Exception {

            OutputStream output = new FileOutputStream(new File("D:"

                    + File.separator + "hello.txt"));

            String info = "你好啊,中国!" ;

            output.write(info.getBytes("ISO8859-1")) ;

            output.close() ;

        }

    }

    7.4、工厂设计终极版

             工厂设计经过发展已经有两种模型:

                       1、   简单工厂,所有的工厂类随着子类的增加而要修改

                       2、   反射工厂,只要传递进去完整的包.类,就可以完成实例化操作

             但是,第2种实现本身也有问题,因为每次都要传递一个完整的“包.类”实在是太麻烦了。

    import java.io.File;

    import java.io.FileInputStream;

    import java.util.Properties;

    interface Area {

        public void getInfo();

    }

    class BeiJing implements Area {

        public void getInfo() {

            System.out.println("你在北京,欢迎您!");

        }

    }

    class NanJing implements Area {

        public void getInfo() {

            System.out.println("你在南京,欢迎您!");

        }

    }

    class Factory {

        public static Area getInstance(String className) {

            Area a = null;

            try {

                a = (Area) Class.forName(className).newInstance();

            } catch (Exception e) {

            }

            return a;

        }

    }

    public class FactoryDemo {

        public static void main(String[] args) throws Exception {

            Properties pro = new Properties();

            pro.load(new FileInputStream(new File("D:" + File.separator

                    + "area.properties")));

            Area a = Factory.getInstance(pro.getProperty("area"));

            a.getInfo();

        }

    }

    配置文件:area.properties

    area=org.lxh.factorydemo.NanJing

             现在的程序中可以发现,都是通过配置文件控制的,而且只要配置文件改变了,程序可以立刻发生改变。

             达到了配置文件与程序相分离的目的。

  • 相关阅读:
    关于测试开发及其他——写在离职之前
    牛腩新闻发布系统——初探CSS
    牛腩新闻发布系统——后台前台整合技术
    Android Audio Focus的应用(requestAudioFocus)
    正则表达式详解
    牛腩新闻发布系统——初探JQuery,AJAX
    牛腩新闻发布系统——初探Javascript
    进入中文维基百科的方法
    *args 和**kwargs 的溯源
    mathematica9激活
  • 原文地址:https://www.cnblogs.com/MR-Guo/p/3341598.html
Copyright © 2020-2023  润新知