13. Java类集 Part 2(Map接口、SortedMap接口、集合工具类Collection、Stack类、属性类Properties) ----- 学习笔记

来源:互联网 发布:小粉红 知乎 编辑:程序博客网 时间:2024/05/14 14:43

13.7  Map接口

      13.7.1 Map接口简介

      之前将接到的Collection、List、Set接口都属于单值得操作,也就是每次只能操作一个对象!!而Map与它们不同的是,每次操作的是一对对象(即二元偶对象),Map中的每个元素都使用 key--->value 的形式存储在集合中。

//Map接口的定义如下:public interface Map<K, V>

      在Map上也应用了泛型,必须同时设置好key 和 value的类型; 在Map中每一对 key--->value 都表示一个值。 在Map接口中也定义了大量的方法,如下所示:


      13.7.2 Map.Entry接口简介

Map.Entry是Map内部定义的一个接口,专门用来保存 key --> value 的内容。其定义如下:

//Map.Entry接口的定义:public static interface Map.Entry<K, V>

Map.Entry是使用static关键字声明的内部接口,此接口可以由外部通过“外部类.内部类“的形式直接调用!!!!Map.Entry接口中提供了如下的方法:

  在Map的操作中,所有的内容都是通过 key --> value 的形式保存数据的;那么对于集合来讲,实际上就是将 key --> value 的数据保存在了一个Map.Entry的实例之中,再在Map集合中插入的是一个Map.Entry的实例化对象!!!!如下所示:

====================================

Map.Entry在集合输出时会使用到!!! 在一般的Map操作中(如,增加或取出数据等操作)不用去管Map.Entry接口;但是,在将Map中的数据全部输出时就必须使用Map.Entry接口!!!!

====================================

      13.7.3 Map接口的常用子类

        Map接口也是依靠其子类对象来实例化自身的!! Map接口中常用的子类有:

  1. HashMap无序存放的,是新的操作类,key不允许重复
  2. Hashtable无序存放的,是旧的操作类,key不允许重复
  3. TreeMap: 可以排序的Map集合;按集合中的key排序,key不允许重复!!!!
  4. WeakHashMap: 弱引用的Map集合,当集合中的某些内容不再使用时,清除掉无用的数据,使用gc进行回收
  5. IdentityHashMapkey可以重复的Map集合

1. 新的子类: HashMap

    HashMap本身是Map的子类;直接使用此类为Map接口实例化即可!!!

//HashMap类的定义public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable

    HashMap是AbstractMap类的子类。AbstractMap类的定义如下:

//AbstractMap类的定义:public abstract class AbstractMap<K,V> extends Object implements Map<K,V>


2. 相关操作实例

   因为所有的操作都是以Map接口为操作的标准,且HashMap子类较为常用,所以下面的程序使用HashMap来讲解Map接口中的主要操作方法

(1)实例操作一:向集合中增加和取出内容

在Map接口中使用put(Object key, Object value)方法可以向集合中增加内容,之后可以通过 get(E key)方法根据key找出其对应的value

范例:增加和取得内容

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;public class HashMapDemo01{    public static void main(String args[]){        Map<String, String> map = null;        map = new HashMap<String, String>();                map.put("forfan06", "www.csdn.net");        map.put("Linda", "WHPU");        map.put("Tyler", "Wuhan");                String val = map.get("Linda");                System.out.println("取出的内容是:" + val);    }}

运行结果:

取出的内容是:WHPU

在程序中声明Map接口对象时指定好了key和value的泛型类型为String, 之后通过put()方法向Map集合中增加内容。最后通过get()方法取出一个key对应的value内容!!

(2)实例操作二:判断指定的key或value是否存在

    如果要判断某一个指定的key或value是否存在,可以使用Map接口中提供的containsKey(Object key)、containsValue(Object value)两个方法。 前者判断Map集合中是否存在指定的key; 后者是判断Map集合中是否存在指定的value

范例:判断指定内容是否存在

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;public class HashMapDemo02{    public static void main(String args[]){        Map<String, String> map = null;        map = new HashMap<String, String>();                map.put("forfan06", "www.csdn.net");        map.put("Linda", "WHPU");        map.put("Tyler", "Wuhan");        map.put("Wuhan", "HuBei");                if(map.containsKey("Linda")){            System.out.println("搜索的key存在!");        }else{            System.out.println("搜索的key不存在!");        }        if(map.containsValue("Wuhan")){            System.out.println("搜索的value存在!");        }else{            System.out.println("搜索的value不存在!");        }    }}

(3)实例操作三:输出全部的key

在Map中提供了一个叫做keySet()的方法,可以将一个Map中的key全部取出来后,保存到一个Set集合中。一旦有了Set实例,就可以直接使用Iterator接口来输出!

但是,在运行操作时一定要注意的是,接收的Set集合中指定的泛型要和Map中key的泛型类型保持一致!!!

范例:输出全部的key

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;import java.util.Collection;import java.util.Set;import java.util.HashSet;import java.util.Iterator;public class HashMapDemo03{    public static void main(String args[]){        Map<String, String> map = null;        map = new HashMap<String, String>();                map.put("forfan06", "www.csdn.net");        map.put("Linda", "WHPU");        map.put("Tyler", "Wuhan");        map.put("Wuhan", "Hubei");                Set<String> keys = map.keySet();        Iterator<String> iter = keys.iterator();        while(iter.hasNext()){            System.out.print(iter.next() + "、");        }    }}

运行结果:

Linda、forfan06、Wuhan、Tyler、

(4)实例操作四:输出全部的value

如果要输出全部的value,可以使用values()方法。此方法返回类型是Collection<V>。在操作时同样需要注意泛型的类型要保持一致。 然后通过Iterator接口来输出Collection内容

范例:输出全部的value

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;import java.util.Collection;import java.util.Set;import java.util.HashSet;import java.util.Iterator;public class HashMapDemo04{    public static void main(String args[]){        Map<String, String> map = null;        map = new HashMap<String, String>();                map.put("forfan06", "www.csdn.net");        map.put("Linda", "WHPU");        map.put("Tyler", "Wuhan");        map.put("Wuhan", "Hubei");                Collection<String> values = map.values();        Iterator<String> iter = values.iterator();        while(iter.hasNext()){            System.out.print(iter.next() + "、");        }    }}

3. 旧的子类:Hashtable

Hashtable也是Map中的一个子类。与Vector类的推出时间一样,都是属于旧的操作类;其使用上也和之前的HashMap类没有什么太大的区别

范例:Hashtable的操作

package org.forfan06.mapdemo;import java.util.Map;import java.util.Hashtable;import java.util.Collection;import java.util.Iterator;import java.util.Set;public class HashtableDemo01{    public static void main(String args[]){        Map<String, String> map = null;        map = new Hashtable<String, String>();                map.put("forfan06", "www.csdn.net");        map.put("Linda", "WHPU");        map.put("Tyler", "Wuhan");        map.put("Wuhan", "Hubei");                Set<String> keys = map.keySet();        Iterator<String> iter1 = keys.iterator();        System.out.print("全部的key:");        while(iter1.hasNext()){            System.out.print(iter1.next() + "、");        }                Collection<String> values = map.values();        Iterator<String> iter2 = values.iterator();        System.out.print("\n全部的value:");        while(iter2.hasNext()){            System.out.print(iter2.next() + "、");        }    }}

运行结果:

全部的key:Linda、Wuhan、Tyler、forfan06、全部的value:WHPU、Hubei、Wuhan、<a target=_blank href="http://www.csdn.net">www.csdn.net</a>、

4. HashMap与Hashtable的区别

        HashMap与Hashtable在操作上没有什么特别大的区别,那么该如何选择呢???

从实际的开发应用来看:HashMap类使用的较多!!!应该重点掌握!!!!!

5. 排序的子类:TreeMap

      在HashMap和Hashtable类进行存放数据时,数据并没有按照顺序存放。Map集合的内容输出时都是无序的。

      TreeMap类的主要功能就是将Map集合中的数据按照key进行排序!!!!

范例:观察TreeMap的排序

package org.forfan06.mapdemo;import java.util.Map;import java.util.TreeMap;import java.util.Collection;import java.util.Iterator;import java.util.Set;public class TreeMapDemo01{    public static void main(String args[]){        Map<String, String> map = null;        map = new TreeMap<String, String>();                map.put("A、forfan06", "www.csdn.net");        map.put("D、Linda", "WHPU");        map.put("C、Tyler", "Wuhan");        map.put("B、Wuhan", "Hubei");                Set<String> keys = map.keySet();        Iterator<String> iter = keys.iterator();        while(iter.hasNext()){            String str = iter.next();            System.out.println(str + "--->" + map.get(str));            //不能使用下面语句代替上面的。因为在下面语句中,iter.next()执行了两次,相当于取出了两次数据。指针会自动后移            //System.out.println(iter.next() + "--->" + map.get(iter.next()));        }    }}

运行结果:

A、forfan06--->www.csdn.netB、Wuhan--->HubeiC、Tyler--->WuhanD、Linda--->WHPU

从结果可以看出,最终保存在Map集合中的数据是经过排序后的数据!按其key值排序的。。。

  • 使用自定义类作为key时,该自定义类需要事先Comparable接口(覆写compareTo()方法)
  • TreeMap可以按照key排序,之前的代码使用的是String类作为key泛型; 因为String类本身就实现了Comparable接口,所以程序执行时不会产生问题; 但是,如果使用一个自定义类来作为key的泛型类型的话,则此类必须实现Comparable接口!!!否则将出现ClassCastException(类转换异常)

6. 弱引用类:WeakHashMap

         前面讲解到的HashMap、Hashtable、TreeMap三个Map接口的子类中的数据都是使用强引用保存的(里面的内容不管是否使用都始终在集合中保留)!!!

         如果希望集合自动清理暂时不用的数据,可以使用弱引用类:WeakHashMap类!!!这样,当进行垃圾收集时会释放掉集合中的垃圾信息。

//WeakHashMap类的定义public class WeakHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>

范例:弱引用WeakHashMap类的Map集合

package org.forfan06.mapdemo;import java.util.Map;import java.util.WeakHashMap;public class WeakHashMapDemo01{    public static void main(String args[]){        Map<String, String> map = null;        map = new WeakHashMap<String, String>();                map.put(new String("forfan06"), new String("www.csdn.net"));        map.put(new String("Linda"), new String("WHPU"));        map.put(new String("Tyler"), new String("Wuhan"));        map.put(new String("Wuhan"), new String("Hubei"));                System.gc();        map.put(new String("Jack"), new String("Daniel"));        map.put(new String("Skins"), new String("Cassie"));        System.out.println("内容:" + map);    }}

运行结果:

内容:{Skins=Cassie, Jack=Daniel}

注意: 直接调用集合名称来输出集合的话,Collection输出内容时用方括号括起来的;而Map则是花括号括起来的!!!!!

=============================================================

对象的引用强度说明:

在JDK1.2版本开始,Java把对象的引用分为4种级别。 从而使程序能更加灵活地控制对象的生命周期!!!!这4种级别由高到低依次是:强引用、软引用、弱引用、虚引用

  1. 强引用: 当内存不足时,JVM宁可出现OutOfMemeryError错误而使程序停止,也不会回收此对象来释放空间!!!
  2. 软引用:  当内存不足时,会回收这些对象的内容,用来实现内存敏感的高速缓存
  3. 弱引用:  无论内存是否紧张,被垃圾回收器发现立即回收!!
  4. 虚引用:  和没有任何引用一样。

=============================================================

      13.7.4 Map接口的使用注意事项

1. 注意事项一:  不能直接使用迭代输出Map中的全部内容

      对于Map接口来说,其本身是不能直接使用迭代(如Iterator、foreach)进行输出的,因为Map中的每个位置存放的是一对值(key --> value),而Iterator中每次只能找到一个值。所以,如果非要使用迭代进行输出,则必须按照以下步骤完成(以Iterator输出方法为例)。

  1. 将Map的实例通过entrySet()方法变为Set接口对象
  2. 通过Set接口实例化为Iterator实例化对象
  3. 通过Iterator迭代输出,每一个内容都是Map.Entry的对象
  4. 通过Map.Entry 进行 key ---> value的分离 getKey()、getValue()方法

      Map中的每对数据都是通过Map.Entry保存的,所以如果最终要进行输出也应该使用Map.Entry接口来完成!!!下面通过Iterator和foreach来演示Map的输出。

====================================================

Map一般很少直接输出,只是作为查询使用。

Map集合的内容在开发中基本上作为查询的应用比较多,全部输出的操作较少;

而Collection接口在开发中的主要作为就是用来传递内容及输出的

====================================================

(1)Map输出方式一:Iterator输出Map

范例:使用Iterator输出Map实例

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;import java.util.Iterator;import java.util.Map.Entry;import java.util.Collection;import java.util.Set;public class IteratorDemo04{    public static void main(String args[]){        Map<String, String> map = null;        map = new HashMap<String, String>();                map.put("forfan06", "www.csdn.net");        map.put("Linda", "WHPU");        map.put("Tyler", "Wuhan");        map.put("Wuhan", "Hubei");                //Set<Map.Entry<String, String>> set = map.entrySet();        Set<Map.Entry<String, String>> set = null;        set = map.entrySet();        //Iterator<Map.Entry<String, String>> iter = set.iterator();        Iterator<Map.Entry<String, String>> iter = null;        iter = set.iterator();        while(iter.hasNext()){            Map.Entry<String, String> entry = iter.next();   //避免使用两次iter.next()取出两次Map.Entry            String key = entry.getKey();            String value = entry.getValue();            System.out.println(key + "--->" + value);        }    }}

运行结果:

Linda--->WHPUforfan06--->www.csdn.netWuhan--->HubeiTyler--->Wuhan

     **********上面程序的操作流程是Map集合的标准输出流程,一定要牢牢记住**********

 从结果可以看出,HashMap类存储Map接口时,其内容是随机保存的!!!!

(2)Map输出方式二:foreach输出Map

     既然可以使用Iterator接口进行输出Map集合,那么同样也可以使用foreach进行输出。输出时,还是需要将Map集合转变为Set集合(Map接口中定义的entrySet()方法),Set集合中每一个元素都是Map.Entry接口对象!!!!!

范例:使用foreach输出Map集合内容

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;import java.util.Map.Entry;import java.util.Collection;import java.util.Set;public class ForeachDemo02{    public static void main(String args[]){        Map<String, String> map = null;        map = new HashMap<String, String>();                map.put("forfan06", "www.csdn.net");        map.put("Linda", "WHPU");        map.put("Tyler", "Wuhan");        map.put("Wuhan", "Hubei");                //Set<Map.Entry<String, String>> set = map.entrySet();        Set<Map.Entry<String, String>> set = null;        set = map.entrySet();                for(Map.Entry<String, String> entry:set){            System.out.println(entry.getKey() + "--->" + entry.getValue());        }    }}

运行结果:

Linda--->WHPUforfan06--->www.csdn.netWuhan--->HubeiTyler--->Wuhan

2. 注意事项二:直接使用非系统类作为泛型类型 key

     既然Map接口中所有的内容都是以 key --> value 的形式出现的,而且在声明Map对象时,使用了泛型声明类型,那么现在应该可以使用一个“字符串”表示一个Person对象。就是将自定义类作为Map接口中的泛型类型

范例:String --> Person映射

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}public class HashMapDemo05{    public static void main(String args[]){        Map<String, Person> map = null;        map = new HashMap<String, Person>();        map.put("带头大哥", new Person("forfan06", 27));        System.out.println(map.get("带头大哥"));  //查找内容,查找带头大哥的信息    }}

运行结果:

姓名:forfan06;年龄:27

上面程序在操作时,是以一个字符串匿名对象的方式查找的,从结果来看,是能够查找到其对应内容的。

那么,如果现在两个类型换一下位置呢??就是说Person类的对象来表示一个字符串!!!!

范例:Person --> String映射

import java.util.Map;import java.util.HashMap;class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}public class HashMapDemo06{    public static void main(String args[]){        Map<Person, String> map = null;        map = new HashMap<Person, String>();        map.put(new Person("forfan06", 27), "带头大哥");        System.out.println(map.get(new Person("forfan06", 27)));  //查找内容,查找带头大哥的信息    }}

此时的运行结果为: null !!!

分析:

上面HashMapDemo06的程序结构和HashMapDemo05的差不多,只是使用了一个Person的匿名对象作为key,将字符串的匿名对象作为了value;

唯一的不同之处只是改变了之前的key和value的位置,但是此时却无法查找到指定的内容。为什么一开始使用String可以,现在使用Person类对象却不可以呢???

范例:声明Person类对象 --> String映射

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}public class HashMapDemo07{    public static void main(String args[]){        Map<Person, String> map = null;        map = new HashMap<Person, String>();        //map.put(new Person("forfan06", 27), "带头大哥");        //System.out.println(map.get(new Person("forfan06", 27)));  //查找内容,查找带头大哥的信息        Person per = new Person("forfan06", 27);        map.put(per, "带头大哥");        System.out.println(map.get(per));  //找出此人的身份!!!    }}

运行结果:

带头大哥

此时,根据key能够找到相应的value,但是为什么此时可以找到,而之前使用匿名对象却不可能找到呢????由于之前的操作都是以Person类的匿名对象完成的,但是现在在查找操作时使用的并不是匿名对象,这样程序中设置和取得时都是使用了Person类的实例化对象,就得靠Object类中的hashCode()、equals()方法的帮助。 来区分是否是同一个对象!!!!!!!!!!!!!!!!!!!!!!

范例:覆写equals()、hashCode()方法

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    //@override equals() method    public boolean equals(Object obj){        if(this == obj){            return true;        }        if(!(obj instanceof Person)){            return false;        }        Person p = (Person) obj;        if((this.name.equals(p.name)) && (this.age == p.age)){            return true;        }else{            return false;        }    }    //@override hashCode() method    public int hashCode(){        return this.name.hashCode() * this.age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}public class HashMapDemo08{    public static void main(String args[]){        Map<Person, String> map = null;        map = new HashMap<Person, String>();        map.put(new Person("forfan06", 27), "带头大哥");        System.out.println(map.get(new Person("forfan06", 27)));  //查找内容,查找带头大哥的信息        //Person per = new Person("forfan06", 27);        //map.put(per, "带头大哥");        //System.out.println(map.get(per));    }}

运行结果:

带头大哥

===================================

由以上4个例子可以看出。如果要使用一个自定义类的对象表示Map中的key,则对象所在的类中一定要覆写equals()、hashCode()方法!!!否则无法找到对应的value

===================================

      13.7.5 key可以重复的Map集合:IdentityHashMap

        前面讲到的HashMap、Hashtable、TreeMap、WeakHashMap这4个针对Map操作时,key的值是不能重复的,例如,HashMap操作时key是不能重复的,如果重复则肯定会覆盖之前的内容。例如:

范例:Map中的key不允许重复,重复就是覆盖

package org.forfan06.mapdemo;import java.util.Map;import java.util.HashMap;import java.util.Set;import java.util.Iterator;class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    //@override equals() method    public boolean equals(Object obj){        if(this == obj){            return true;        }        if(!(obj instanceof Person)){            return false;        }        Person p = (Person) obj;        if((this.name.equals(p.name)) && (this.age == p.age)){            return true;        }else{            return false;        }    }    //@override hashCode() method    public int hashCode(){        return this.name.hashCode() * this.age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}public class IdentityHashMapDemo01{    public static void main(String args[]){        Map<Person, String> map = null;        map = new HashMap<Person, String>();        map.put(new Person("forfan06", 27), "带头大哥");        map.put(new Person("forfan06", 27), "大坏蛋");        map.put(new Person("Linda", 25), "小无赖");        map.put(new Person("Peter", 17), "小无赖");                Set<Map.Entry<Person, String>> set = null;        set = map.entrySet();        Iterator<Map.Entry<Person, String>> iter = null;        iter = set.iterator();        while(iter.hasNext()){            Map.Entry<Person, String> entry = iter.next();            Person per = entry.getKey();            String str = entry.getValue();            System.out.println(per + "--->" + str);        }    }}

运行结果:

姓名:Peter;年龄:17--->小无赖姓名:forfan06;年龄:27--->大坏蛋姓名:Linda;年龄:25--->小无赖

     可以发现 “姓名:forfan06;年龄:27 --->带头大哥”这条记录不见了。它是被“大坏蛋”这条记录给覆盖了!!!!


    为了防止数据被覆盖,可以使用IdentityHashMap类来保存数据。 使用此类时,只要key的地址不相等(key1 != key2),就表示不是重复的key,该数据可以添加到集合中!!!!

范例:使用IdentityHashMap修改上面程序

package org.forfan06.mapdemo;import java.util.Map;import java.util.IdentityHashMap;import java.util.Set;import java.util.Iterator;class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    //@override equals() method    public boolean equals(Object obj){        if(this == obj){            return true;        }        if(!(obj instanceof Person)){            return false;        }        Person p = (Person) obj;        if((this.name.equals(p.name)) && (this.age == p.age)){            return true;        }else{            return false;        }    }    //@override hashCode() method    public int hashCode(){        return this.name.hashCode() * this.age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}public class IdentityHashMapDemo02{    public static void main(String args[]){        Map<Person, String> map = null;        map = new IdentityHashMap<Person, String>();        map.put(new Person("forfan06", 27), "带头大哥");        map.put(new Person("forfan06", 27), "大坏蛋");        map.put(new Person("Linda", 25), "小无赖");        map.put(new Person("Peter", 17), "小无赖");                Set<Map.Entry<Person, String>> set = null;        set = map.entrySet();        Iterator<Map.Entry<Person, String>> iter = null;        iter = set.iterator();        while(iter.hasNext()){            Map.Entry<Person, String> entry = iter.next();            Person per = entry.getKey();            String str = entry.getValue();            System.out.println(per + "--->" + str);        }    }}

运行结果:

姓名:Peter;年龄:17--->小无赖姓名:Linda;年龄:25--->小无赖姓名:forfan06;年龄:27--->大坏蛋姓名:forfan06;年龄:27--->带头大哥

但是,如果此时修改上面代码如下:

package org.forfan06.mapdemo;import java.util.Map;import java.util.IdentityHashMap;import java.util.Set;import java.util.Iterator;class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    //@override equals() method    public boolean equals(Object obj){        if(this == obj){            return true;        }        if(!(obj instanceof Person)){            return false;        }        Person p = (Person) obj;        if((this.name.equals(p.name)) && (this.age == p.age)){            return true;        }else{            return false;        }    }    //@override hashCode() method    public int hashCode(){        return this.name.hashCode() * this.age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}public class IdentityHashMapDemo03{    public static void main(String args[]){        Map<Person, String> map = null;        map = new IdentityHashMap<Person, String>();        Person p = new Person("forfan06", 27);        map.put(p, "带头大哥");        map.put(p, "大坏蛋");        map.put(new Person("Linda", 25), "小无赖");        map.put(new Person("Peter", 17), "小无赖");                Set<Map.Entry<Person, String>> set = null;        set = map.entrySet();        Iterator<Map.Entry<Person, String>> iter = null;        iter = set.iterator();        while(iter.hasNext()){            Map.Entry<Person, String> entry = iter.next();            Person per = entry.getKey();            String str = entry.getValue();            System.out.println(per + "--->" + str);        }    }}

运行结果:

姓名:Peter;年龄:17--->小无赖姓名:Linda;年龄:25--->小无赖姓名:forfan06;年龄:27--->大坏蛋

=================================

上面两段代码,说明的是IdentityHashMap类对于判断是否是重复的key。当两个对象的地址相等时,也是会覆盖之前的数据的!!!!!

=================================

13.8 SortedMap接口

        SortedMap接口是一个排序接口!!!只要是实现了此接口的子类,都属于排序的子类!!!TreeMap就是此接口的一个子类。

//SortedMap接口的定义public interface SortedMap<K, V> extends Map<K, V>

前面讲到的TreeMap就是此接口的实现类,所有TreeMap可以完成排序的功能。

SortedMap接口中定义了一些Map接口中没有的方法,如下所示:


范例:SortedMap的演示

package org.forfan06.mapdemo;import java.util.SortedMap;import java.util.Map;import java.util.TreeMap;public class SortedMapDemo01{    public static void main(String args[]){        SortedMap<String, String> map = null;        map = new TreeMap<String, String>();   //通过子类来实例化SortedMap接口对象        map.put("D、forfan06", "www.csdn.net");        map.put("A、Linda", "WHPU");        map.put("C、Tyler", "Wuhan");        map.put("B、Wuhan", "Hubei");        map.put("B、Wuhan", "China");        map.put("D、forfan06", "www.csdn.net");                System.out.print("第一个元素的key:" + map.firstKey());        System.out.println(";对应的值:" + map.get(map.firstKey()));        System.out.print("最后一个元素的key:" + map.lastKey());        System.out.println(";对应的值:" + map.get(map.lastKey()));                System.out.println("返回小于指定范围的集合:");        for(Map.Entry<String, String> entry:map.headMap("B、Wuhan").entrySet()){            System.out.println("\t|- " + entry.getKey() + "--->" + entry.getValue());        }                System.out.println("返回大于指定范围的集合:");        for(Map.Entry<String, String> entry:map.tailMap("B、Wuhan").entrySet()){            System.out.println("\t|- " + entry.getKey() + "--->" + entry.getValue());        }                System.out.println("部分集合:");        for(Map.Entry<String, String> entry:map.subMap("B、Wuhan", "D、forfan06").entrySet()){            System.out.println("\t|- " + entry.getKey() + "--->" + entry.getValue());        }    }}

运行结果:

第一个元素的key:A、Linda;对应的值:WHPU最后一个元素的key:D、forfan06;对应的值:www.csdn.net返回小于指定范围的集合:|- A、Linda--->WHPU返回大于指定范围的集合:|- B、Wuhan--->China|- C、Tyler--->Wuhan|- D、forfan06--->www.csdn.net部分集合:|- B、Wuhan--->China|- C、Tyler--->Wuhan

===========================================

从上面的例子,注意到SortedMap中的3个方法headMap、tailMap、subMap中的参数,查看结果推断出是否包含参数列表中的key值!!!!!!!!!!

===========================================

SortedMap接口中定义了很多Map接口中没有的方法,但是如果要使用SortedMap中定义的方法,则对象所在的类必须实现Comparable接口!!!!覆写compareTo()方法

13.9 集合工具类:Collections

      13.9.1 Collections简介

       在集合的应用开发中,集合的若干接口和若干子类是最常使用的,但是在JDK中提供了一种集合操作的工具类 ----   Collections, 可以直接通过此类方便地操作集合。

       Collections类里面所定义的方法全部是静态方法(static关键字修饰), 不需要实例化Collections类的对象就可以直接调用它的方法! (另外,也看到这么一句话:Collections类是一个工具类,在开发中,一般都会让工具类部可实例化。 类似Math类)

      Collections类在包java.util中。

//Collections类的定义: public class Collections extends Object

     单从Collections类的定义上来看,它与集合没有什么太大的关系。 下面是Collections类的常用方法及类型:


      13.9.2 Collections操作实例

1. 实例操作一: 返回不可变的集合

      Collections类中可以返回空的List、Set、Map集合,但是通过这种方式返回的对象是无法进行增加数据的, 因为在这些操作中并没有实现add()方法!!!!

范例:返回空的集合对象

package org.forfan06.collectionsdemo;import java.util.Collections;import java.util.Collection;import java.util.List;import java.util.Set;public class CollectionsDemo01{    public static void main(String args[]){        List<String> allList = Collections.emptyList();                Set<String> allSet = Collections.emptySet();                allList.add("hello");  //allSet.add("Hello");也是一样的错误    }}

运行结果:

Exception in thread "main" java.lang.UnsupportedOperationExceptionat java.util.AbstractList.add(AbstractList.java:148)at java.util.AbstractList.add(AbstractList.java:108)at CollectionsDemo01.main(Unknown Source)
    表示不支持的方法异常,因为没有找到add()方法的实现!!!!

2. 实例操作二: 为集合增加内容

         使用addAll()方法可以为一个集合增加内容。该方法可以接收可变参数,所以可以传递任意多的参数作为集合的内容!!!!!!!!

范例:增加内容

package org.forfan06.collectionsdemo;import java.util.Collections;import java.util.ArrayList;import java.util.List;import java.util.Iterator;public class CollectionsDemo02{    public static void main(String args[]){        List<String> list = new ArrayList<String>();        Collections.addAll(list, "forfan06", "www.csdn.net", "WHPU");        Iterator<String> iter = list.iterator();        while(iter.hasNext()){            System.out.print(iter.next() + "、");        }    }}

看不懂?!! 该怎么理解上面的程序????

import java.util.Collections;import java.util.List;import java.util.ArrayList;import java.util.Iterator;public class CollectionsDemo02_2{    public static void main(String args[]){        List<Person> list = new ArrayList<Person>();    Student stu = new Student("Linda", 17, "Female");    Collections.addAll(list, new Person("forfan06", 27), stu);        Iterator<Person> iter = list.iterator();        while(iter.hasNext()){            System.out.print("\t" + iter.next());        }        //the following code can not through the complier        /**          *List<Student> list = new ArrayList<Student>();          *Person per = new Person("forfan06", 27);          *Collections.addAll(list, new Student("Linda", 17, "Female"), per);          *...          */              }}class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}class Student extends Person{    private String sex;    public Student(String name, int age, String sex){        super(name, age);        this.sex = sex;    }    public String toString(){        return super.toString() + ";性别:" + this.sex;    }}

运行结果:

姓名:forfan06;年龄:27姓名:Linda;年龄:17;性别:Female

-----------------------------------------------------------------------------------------------------------------------

解析Collections的增加内容allAll()方法,如下:

//Collections类中定义的addAll()方法的定义:public static <T> Boolean addAll(Collection<? super T> c, T... elements)

参数 c - 表示要增加内容的集合。 可以是Collection接口实例对象,或者Collection接口的子接口实例对象(这里是通过对象多态性自动向上转型操作的)List<? super T>、Set<? super T>等等!!

         另外这里Collection<? super T>集合泛型类型的限制,因为我们现在是要将T类型的对象或数组添加到集合Collection<? super T>里面去。为了保证操作的可执行性,该集合中保存的元素必须是T类型或者是T类型的父类!!!!同样,如果是Collection<superT>可以接收T类型的元素,也是通过对象多态性来处理的!!!!

        这也是上面的例子中,List<Person>可以增加Person类的子类Student类实例对象的原因。但是,反之,则不能成功。我们可以说Student是一个Person(Student is a Person); 但是,如果现在是List<Student>试图增加一个Person类的实例话对象,试想,Person类可能不止Student一个子类,还有teacher子类, 临界的排除,现在Person类对象由它的另外一个子类Teacher转型而来,那么现在试图将该对象保存到List<Student>是肯定不行的!!!!!

     elements - 要添加到集合中的元素!!!!

-----------------------------------------------------------------------------------------------------------------------

3. 实例操作三:反转集合中的内容

    直接使用Collections工具类中的reverse()方法即可将集合类中的内容反转保存!

范例:反转内容

package org.forfan06.collectionsdemo;import java.util.Collections;import java.util.List;import java.util.ArrayList;import java.util.Iterator;public class CollectionsDemo03{    public static void main(String args[]){        List<Person> list = new ArrayList<Person>();    Student stu = new Student("Linda", 17, "Female");    Collections.addAll(list, new Person("forfan06", 27), stu);  //增加内容        Collections.reverse(list);   //反转内容        Iterator<Person> iter = list.iterator();        while(iter.hasNext()){            System.out.print("\t" + iter.next());        }        //the following code can not through the complier        /**          *List<Student> list = new ArrayList<Student>();          *Person per = new Person("forfan06", 27);          *Collections.addAll(list, new Student("Linda", 17, "Female"), per);          *...          */              }}class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}class Student extends Person{    private String sex;    public Student(String name, int age, String sex){        super(name, age);        this.sex = sex;    }    public String toString(){        return super.toString() + ";性别:" + this.sex;    }}

运行结果:

姓名:Linda;年龄:17;性别:Female姓名:forfan06;年龄:27
从结果可以看出,Collections类中的方法reverse(List<?> list)反转内容时,是把list里面的元素当作一个整体来进行操作的!!!!

4. 实例操作四:检索内容 (戳我)

      通过Collections类中的方法binarySearch()方法,可以来进行内容的检索,检索之后会返回内容的位置(index of the search key. will be -1 if does not exist )

//binarySearch()方法的定义:public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)

Here is the description about binarySearch() method from jdk specify

----------------------------------------------------------------------------------------------------

Searches the specified list for the specified object using the binary search algorithm. The list must be sorted into ascending order according to thenatural ordering of its elements (as by the sort(List) method) prior to making this call. If it is not sorted, the results are undefined. If the list contains multiple elements equal to the specified object, there is no guarantee which one will be found.

list必须要是升序排序!!!!!!!!!!!JDK所有binarySearch接口,都需要自行将相关的集合/数组/容器,排序,然后再调用binarySearch

----------------------------------------------------------------------------------------------------

binarySearch的第一个参数类型是:
List<? extends Comparable<? super T>>

这个类型比较复杂,它首先要求你一个List对象,随后对这个List的泛型参数要求是:
? extends Comparable<? super T>

也就是一个实现了Comparable<? super T>接口的类T
然后来看你传入的参数是 List<Student>

所以Student类必须是一个 Comparable<? super Student> 的类,而你的Student类只实现了裸的Comparable,没有实现泛型版本的Comparable,所以参数不匹配

-----追问
“也就是一个实现了Comparable<? super T>接口的类T”这句不太懂,为什么一定是类T,只是说参数一定是?superT也就是T型的,但是没说实现Comparable的类就一定是T型的啊。(List<? extends Comparable<? super T>>, T)第二参数是comparable参数的父类,那我把第二参数编程object型,comparable还是不设置参数(就是默认参数是object),那样他们的不就一致了,为什么还是错的?还有泛型能继承和覆盖吗?
-----回答
——“也就是一个实现了Comparable<? super T>接口的类T”这句不太懂之前的表述不太清楚,我重新尝试解释一下吧。binarySearch有一个显示的泛型参数T,和两个参数,第二个参数是T类型,这就决定了整个方法的泛型参数。你传的是Student类型,所以T在这里无疑是Student类binarySearch的第一个参数是List<? extends Comparable<? super T>>,而你传的是List<Student>,所以Student就代替了上面的第一个问号,也就是说Student类必须满足extends Comparable<? super T> 这个条件,即Student类要实现Comparable<? super T>接口。注意的是这里的Comparable是有泛型的,也就是必须存在一个类U来代替上面Comparable泛型中的问号参数,并且U是T的父类(super你可以这样字面理解,但是准确的说应该是T类型的对象可以转换成U类型的对象,意味着T是U的子类,包括间接子类;或者T实现了U接口;或者T是U本身)。在这里,T是Student,所以U必须是Student的父类之一,或者Student实现的接口,或者Student本身现在你的Student确实实现了Comparable,但实现的是没有泛型的Comparable接口。你必须实现有泛型的。比如你可以让Student implements Comparable<Student>,这样我说的U就是Student本身,调用没有问题。你也可以让Student implements Comparable<Object>,这样U就是Object,而Object是Student的父类,这样也没有问题。——还有泛型能继承和覆盖吗?这个问题是想说List<String>继承List<Object>吗?不是,它们没有继承关系。所以List<String>类型的对象不能传给List<Object>类型的参数。你必须把参数类型定义成List<? extends Object>才能接受List<String>类型的对象。


package org.forfan06.collectionsdemo;import java.util.Collections;import java.util.List;import java.util.ArrayList;import java.util.Iterator;public class CollectionsDemo03_2{    public static void main(String args[]){        List<Person> list = new ArrayList<Person>();    Student stu = new Student("Linda", 17, "Female");    Collections.addAll(list, new Person("forfan06", 27), stu);  //增加内容        Collections.reverse(list);   //反转内容        Person p = stu;        //Collections.sort(list); 当Person、Student类实现了Comparable接口后,不需要用sort方法排序        int index = Collections.binarySearch(list, p);        System.out.println(index);        int index1 = Collections.binarySearch(list, new Person("forfan06", 27));        System.out.println(index1);        Iterator<Person> iter = list.iterator();        while(iter.hasNext()){            System.out.print("\t" + iter.next());        }        //the following code can not through the complier        /**          *List<Student> list = new ArrayList<Student>();          *Person per = new Person("forfan06", 27);          *Collections.addAll(list, new Student("Linda", 17, "Female"), per);          *...          */              }}class Person implements Comparable<Person>{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }    //@override compareTo() method    public int compareTo(Person p){        if(this.name.equals(p.name)){            if(this.age > p.age){                return 1;            }else if(this.age < p.age){                return -1;            }else{                return 0;            }        }else{            return this.name.compareTo(p.name);        }    }}class Student extends Person{    private String sex;    public Student(String name, int age, String sex){        super(name, age);        this.sex = sex;    }    public String toString(){        return super.toString() + ";性别:" + this.sex;    }}

运行结果:

01姓名:Linda;年龄:17;性别:Female姓名:forfan06;年龄:27

5. 实例操作五:替换集合中的内容

        Collection类中有替换集合中内容的方法:replaceAll()方法, 用来替换一个集合中的指定内容

//Collections中replaceAll方法的定义public static  <T> Boolean replaceAll(List<T> list, T oldVal, T newVal)

范例:替换集合中指定范围的内容

package org.forfan06.collectionsdemo;import java.util.Collections;import java.util.List;import java.util.ArrayList;import java.util.Iterator;public class CollectionDemo04{    public static void main(String args[]){        List<Person> list = new ArrayList<Person>();        Person p1 = new Person("forfan06", 27);        Person p2 = new Person("Linda", 17);        Student s1 = new Student("Eric", 25, 89);        Student s2 = new Student("Andy", 35, 2);        Collections.addAll(list, p1, p2, s1, s2, p1, s2);        Collections.replaceAll(list, p1, new Person("JTL", 5));        Collections.replaceAll(list, p2, new Person("Future", 0));        Iterator<Person> iter = list.iterator();        //output the person object by foreach        for(Person p:list){            System.out.print("\t" + p);        }        //output the person object by Iterator        System.out.println();        while(iter.hasNext()){            System.out.print("\t" + iter.next());        }    }}class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}class Student extends Person{    private int score;    public Student(String name, int age, int score){        super(name, age);        this.score = score;    }    public String toString(){        return super.toString() + ";分数:" + this.score;    }}

6. 实例操作流:集合排序!!!

    可以通过Collections类中的sort()方法对一个集合进行排序操作。但是,要求集合中每个对象所在的类必须实现Comparable接口!!!!!!!!!!!!!!!!!!!!

package org.forfan06.collectionsdemo;import java.util.Collections;import java.util.List;import java.util.ArrayList;import java.util.Iterator;public class CollectionDemo04{    public static void main(String args[]){        List<Person> list = new ArrayList<Person>();        Person p1 = new Person("forfan06", 27);        Person p2 = new Person("Linda", 17);        Student s1 = new Student("Eric", 25, 89);        Student s2 = new Student("Andy", 35, 2);        Collections.addAll(list, p1, p2, s1, s2, p1, s2);        Collections.addAll(list, new Person("JTL", 5));        Collections.addAll(list, new Student("Future", 0, 100));        //Collections.replaceAll(list, p1, new Person("JTL", 5));        //Collections.replaceAll(list, p2, new Person("Future", 0));        System.out.println("Before the sort");        //output the person object by foreach        for(Person p:list){            System.out.print("\t" + p);        }                Collections.sort(list);        Iterator<Person> iter = list.iterator();        System.out.println("\nAfter sort the list");        //output the person object by Iterator        System.out.println();        while(iter.hasNext()){            System.out.print("\t" + iter.next());        }    }}class Person implements Comparable<Person>{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }    //override compareTo(T o)    public int compareTo(Person per){        if(this.name.equals(per.name)){            if(this.age > per.age){                return 1;            }else if(this.age < per.age){                return -1;            }else{                return 0;            }        }else{            return this.name.compareTo(per.name);        }    }}class Student extends Person{    private int score;    public Student(String name, int age, int score){        super(name, age);        this.score = score;    }    public String toString(){        return super.toString() + ";分数:" + this.score;    }}

运行结果:

Before the sort姓名:forfan06;年龄:27姓名:Linda;年龄:17姓名:Eric;年龄:25;分数:89姓名:Andy;年龄:35;分数:2姓名:forfan06;年龄:27姓名:Andy;年龄:35;分数:2姓名:JTL;年龄:5姓名:Future;年龄:0;分数:100After sort the list姓名:Andy;年龄:35;分数:2姓名:Andy;年龄:35;分数:2姓名:Eric;年龄:25;分数:89姓名:Future;年龄:0;分数:100姓名:JTL;年龄:5姓名:Linda;年龄:17姓名:forfan06;年龄:27姓名:forfan06;年龄:27  

      必须注意的是: 如果是自定义的类(如上面的Person类),如果要使用Collections类中的sort()方法,则该类一定要实现Comparable接口,就像使用Collections类的binarySearch() 一样!!!!否则会出现类型转换异常

7. 实例操作七:交换指定位置的内容

      直接使用swap()方法可以把集合中两个位置的内容进行交换!!!

//Collections中swap方法的定义:public static void swap(List<?> list, int I, int j);//it's throws IndexOutOfBoundsException

范例:交换指定位置的元素

package org.forfan06.collectionsdemo;import java.util.Collections;import java.util.List;import java.util.ArrayList;import java.util.Iterator;public class CollectionDemo04{    public static void main(String args[]){        List<Person> list = new ArrayList<Person>();        Person p1 = new Person("forfan06", 27);        Person p2 = new Person("Linda", 17);        Student s1 = new Student("Eric", 25, 89);        Student s2 = new Student("Andy", 35, 2);        Collections.addAll(list, p1, p2, s1, s2, p1, s2);        Collections.addAll(list, new Person("JTL", 5));        Collections.addAll(list, new Student("Future", 0, 100));        //Collections.replaceAll(list, p1, new Person("JTL", 5));        //Collections.replaceAll(list, p2, new Person("Future", 0));        System.out.println("Before swap");        //output the person object by foreach        for(Person p:list){            System.out.print("\t" + p);        }                Collections.swap(list, 1, 5);        //Collections.sort(list);        Iterator<Person> iter = list.iterator();        System.out.println("\nAfter swap");        //output the person object by Iterator        System.out.println();        while(iter.hasNext()){            System.out.print("\t" + iter.next());        }    }}class Person implements Comparable<Person>{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }    //override compareTo(T o)    public int compareTo(Person per){        if(this.name.equals(per.name)){            if(this.age > per.age){                return 1;            }else if(this.age < per.age){                return -1;            }else{                return 0;            }        }else{            return this.name.compareTo(per.name);        }    }}class Student extends Person{    private int score;    public Student(String name, int age, int score){        super(name, age);        this.score = score;    }    public String toString(){        return super.toString() + ";分数:" + this.score;    }}

运行结果:

Before swap姓名:forfan06;年龄:27姓名:Linda;年龄:17姓名:Eric;年龄:25;分数:89姓名:Andy;年龄:35;分数:2姓名:forfan06;年龄:27姓名:Andy;年龄:35;分数:2姓名:JTL;年龄:5姓名:Future;年龄:0;分数:100After swap姓名:forfan06;年龄:27姓名:Andy;年龄:35;分数:2姓名:Eric;年龄:25;分数:89姓名:Andy;年龄:35;分数:2姓名:forfan06;年龄:27姓名:Linda;年龄:17姓名:JTL;年龄:5姓名:Future;年龄:0;分数:100

13.10 其他集合类

      13.10.1 Stack类

        栈,是采用先进后出的数据存储方式; 每一个栈都包含一个栈顶,每次出栈都是将栈顶的数据取出;每次进栈都是将数据存储到栈顶。

  • 栈的应用,在浏览器中存在一个后退的按钮,每次后退都是后退到上一步的操作,那么实际上这就是一个栈的应用!!采用的是一个先进后出的操作!!!

     在Java中使用Stack类进行栈的操作; Stack类是Vector类的子类。

//Stack类的定义:public class Stack<E> extends Vector<E>

范例: 完成入栈及出栈功能!

package org.forfan06.stackdemo;import java.util.Stack;public class StackDemo01{    public static void main(String args[]){        Stack<Person> s = new Stack<Person>();        Person[] p = new Person[]{new Person("forfan06", 27), new Person("Linda", 17), new Person("Lynn", 27)};        for(Person per:p){            s.push(per);        }        System.out.print(s.pop() + "、");        System.out.print(s.pop() + "、");        System.out.println(s.pop() + "、");        System.out.print(s.pop() + "、");  //error, 出栈出现异常,此时栈为空    }}class Person{    private String name;    private int age;    public Person(String name, int age){        this.name = name;        this.age = age;    }    public String toString(){        return "姓名:" + this.name + ";年龄:" + this.age;    }}

运行结果:

姓名:Lynn;年龄:27、姓名:Linda;年龄:17、姓名:forfan06;年龄:27、Exception in thread "main" java.util.EmptyStackExceptionat java.util.Stack.peek(Stack.java:102)at java.util.Stack.pop(Stack.java:84)at StackDemo01.main(Unknown Source)执行错误

      13.10.2 属性类:Properties

1. Properties类简介

     在Java中属性操作类是一个较为重要的类。而想要明白属性操作类的作用,就必须先弄清楚什么叫属性文件(在国际化操作时已经是用过属性文件Message.properties),在一个属性文件中保存了多个属性,每一个属性就是直接用字符串表示出来的 “ key = value ” 对(组), 而如果想要轻松地操作这些属性文件中的属性,可以通过Properties类方便地完成!!!!

  • 关于属性文件:  对于属性文件其实在Windows操作系统的很多地方都可以见到。 例如,Windows的启动主导文件boot.ini就是使用属性文件的方式保存的,例如:[ boot loader] timeout = 5                default = multi(0)disk(0)rdisk(0)partition(1)\WINDOWS   可以发现,其中都是通过  “ key = value ”形式保存的!! 那么, 这样的文件就是属性文件!!!!!!!!!!!!!!!!

       Properties类本身是Hashtable类的子类, 既然是Hashtable类的子类,则肯定也是按照key和value的形式存放数据的。

//Properties类的定义: public class Properties extends Hashtable<Object, Object>

       虽然Properties类是Hashtable类的子类, 也可以像Map那样使用put()方法保存任意类型的数据,但是一般属性都是由字符串组成的所以在使用本类时本书只关心Properties类本身的方法,而从Hashtable接口继承下来的方法,本书将不作任何介绍。下面以一些实际操作向读者讲解Properties类中各种方法的使用。

  • XML文件格式说明:  XML(eXtensible Markup Lanuage,可扩展的标记型语言)是在现在开发中使用最广泛的一门语言,所有的属性内容可以通过storeToXML()和loadFromXML()两个方法以XML文件格式进行保存和读取, 但是使用XML格式保存时将按照指定的文档格式进行存放,如果格式出错,则将无法读取。

2. Properties操作实例

(1) 实例操作一:设置和取得属性

           可以使用setProperty()和getProperty()方法设置和取得属性,操作时要以String为操作类型!!!!

范例:设置和取得属性

package org.forfan06.propertiesdemo;import java.util.Properties;public class PropertiesDemo01{    public static void main(String[] args){        Properties pro = new Properties();                pro.setProperty("forfan06", "27");        pro.setProperty("Linda", "17");        pro.setProperty("Lynn", "27");                System.out.println("1、Lynn属性存在:" + pro.getProperty("Lynn"));        System.out.println("2、Eric属性不存在:" + pro.getProperty("Eric"));        System.out.println("3、Eric属性不存在,同时设置显示的默认值:" + pro.getProperty("Eric", "没有发现"));    }}

运行结果:

1、Lynn属性存在:272、Eric属性不存在:null3、Eric属性不存在,同时设置显示的默认值:没有发现

(2)实例操作二: 将属性保存在普通文件中

       正常属性类操作完成之后,可以将其内容保存在文件中,那么直接使用store()方法即可,同时指定OutputStream类型,指明输出的位置。属性文件的后缀名是任意的,但是最好按照标准,将属性文件的后缀统一设置为: .properties

范例:保存属性到普通的文件中

package org.forfan06.propertiesdemo;import java.util.Properties;import java.io.File;import java.io.FileOutputStream;public class PropertiesDemo02{    public static void main(String[] args){        Properties pro = new Properties();        pro.setProperty("forfan06", "27");        pro.setProperty("Linda", "17");        pro.setProperty("Lynn", "27");        pro.setProperty("forfan06", "19"); //会把之前的forfan06, 27属性给覆盖掉                File file = new File("D:" + File.separator + "area.properties");        try{            pro.store(new FileOutputStream(file), "Area Info");        }catch(Exception e){            e.printStackTrace();        }    }}

运行结果:

#Area Info#Mon Aug 25 15:09:32 CST 2014Linda=17Lynn=27forfan06=19

分析:因为Properties类是Hashtable类的子类,而且,Hashtable类是无序存放的,key不允许重复!!!所以这里forfan06的值会被后面的19所覆盖!!!

追问:既然Hashtable类是无序存放的,那么Properties输出到普通文件中的顺序是不是有顺序的呢??????

(3)实例操作三: 从普通文件中读取属性内容

       既然可以将属性通过store()方法保存到文件中,同样,也可以通过load()方法,从输入流中将所保存的所有属性内容读取出来!!!

范例:从属性文件中读取内容

package org.forfan06.propertiesdemo;import java.util.Properties;import java.io.File;import java.io.FileInputStream;public class PropertiesDemo03{    public static void main(String[] args){        Properties pro = new Properties();        File file = new File("D:" + File.separator + "Area.properties");                try{            pro.load(new FileInputStream(file));        }catch(Exception e){            e.printStackTrace();        }        System.out.println("1、forfan06: " + pro.getProperty("forfan06"));        System.out.println("2、Lynn: " + pro.getProperty("Lynn"));        System.out.println("3、Linda: " + pro.getProperty("Linda"));    }}

(4)实例操作四:将属性保存在XML文件中

        在Properties类中也可以把全部内容以XML格式的内容通过输出流输出,如果要把属性保存在XML文件中,则文件的后缀名最好是 “   *.xml  ”

范例:将属性保存在XML文件中

package org.forfan06.propertiesdemo;import java.util.Properties;import java.io.File;import java.io.FileOutputStream;public class PropertiesDemo04{    public static void main(String[] args){        Properties pro = new Properties();        File file = new File("D:" + File.separator + "Area.xml");                pro.setProperty("forfan06", "27");        pro.setProperty("Linda", "17");        pro.setProperty("Lynn", "27");        pro.setProperty("forfan06", "19");                try{            pro.storeToXML(new FileInputStream(file), "Area Info");        }catch(Exception e){            e.printStackTrace();        }    }}

运行结果:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"><properties><comment>Area Info</comment>      <entry key="Linda">17</entry>      <entry key="Lynn">27</entry>      <entry key="forfan06">19</entry></properties>

(5)实例操作五:从XML文件中读取属性

         以XML文件格式输出全部属性之后,必须要使用loadFromXML()方法将内容读取进来

范例:读取XML文件内容

package org.forfan06.propertiesdemo;import java.util.Properties;import java.io.File;import java.io.FileInputStream;public class PropertiesDemo05{    public static void main(String args[]){        Properties pro = new Properties();        File file = new File("D:" + File.separator + "Area.xml");                try{            pro.loadFromXML(new FileInputStream(file));        }catch(Exception e){            e.printStackTrace();        }                System.out.println("1、forfan06:" + pro.getProperty("forfan06"));        System.out.println("2、Linda:" + pro.getProperty("Linda"));        System.out.println("3、Lynn:" + pro.getProperty("Lynn"));    }}

运行结果:

1、forfan:192、Linda:173、Lynn:27

13.11 范例

         下面讲解两个基于类集应用的范例,这两个范例将作为以后Java EE的开发基础!!!!!!!!!!!!!!

      13.11.1 范例 --- 一对多关系

          使用类集可以表示出以下关系: 一个学校可以包含多个学生,一个学生属于一个学校; 那么这就是一个典型的一对多关系,此时就可以通过类集进行关系的表示!!!

范例:定义学生类

package org.forfan06.execdemo01;public class Student{    private String name;    private int age;    private School school;   //一个学生属于一个学校    public Student(String name, int age){        this.setName(name);        this.setAge(age);    }    public void setName(String name){        this.name = name;    }    public String getName(){        return name;    }    public void setAge(int age){        this.age = age;    }    public int getAge(){        return age;    }    public void setSchool(School school){        this.school = school;    }    public School getSchool(){        return school;    }        public String toString(){        return "学生姓名:" + this.name + ";年龄:" + this.age;    }}

       以上的Student类中包含了一个School属性,表示一个学生属于一个学校。 在程序运行时,只需要传入School类的引用就可以完成这样的关系

范例:定义学校类

package org.forfan06.execdemo01;import java.util.ArrayList;import java.util.List;public class School{    private String name;    private List<Student> allStudents;  //一个学校有多个学生    public School(){     //无参构造方法        this.allStudents = new ArrayList<Student>();  //实例化List对象集合    }    public School(String name){        this();        this.setName(name);    }    public String getName(){        return name;    }    public void setName(String name){        this.name = name;    }    public List<Student> getAllStudents(){  //取得全部的学生        return allStudents;    }    public String toString(){        return "学校名称:" + this.name;    }} 

            在定义学校类时定义了一个List类型的属性,并指定其泛型类型是Student类类型,这样一来就表示在一个School对象中会包含多个Student类型的引用

范例:测试程序,并设置关系

package org.forfan06.execdemo;import java.util.Iterator;public class TestDemo{    public static void main(String args[]){        School sch = new School("WHPU");                Student s1 = new Student("forfan06", 27);        Student s2 = new Student("Lynn", 27);        Student s3 = new Student("Linda", 17);        Student s4 = new Student("forfan06", 19);                sch.getAllStudents().add(s1);        sch.getAllStudents().add(s2);        sch.getAllStudents().add(s3);        sch.getAllStudents().add(s4);                s1.setSchool(sch);        s2.setSchool(sch);        s3.setSchool(sch);        s4.setSchool(sch);                System.out.println(sch);        //实例化Iterator对象,用于输出全部的学生信息        Iterator<Student> iter = sch.getAllStudents().iterator();        while(iter.hasNext()){            System.out.println("\t|-" + iter.next());        }    }}

运行结果:

学校名称:WHPU|-学生姓名:forfan06;年龄:27|-学生姓名:Lynn;年龄:27|-学生姓名:Linda;年龄:17|-学生姓名:forfan06;年龄:19

完整程序代码:

package org.forfan06.execdemo;import java.util.Iterator;import java.util.ArrayList;import java.util.List;class Student{    private String name;    private int age;    private School school;    public Student(String name, int age){        this.setName(name);        this.setAge(age);    }    public void setName(String name){        this.name = name;    }    public String getName(){        return name;    }    public void setAge(int age){        this.age = age;    }    public int getAge(){        return age;    }    public void setSchool(School school){        this.school = school;    }    public School getSchool(){        return school;    }        public String toString(){        return "学生姓名:" + this.name + ";年龄:" + this.age;    }}class School{    private String name;    private List<Student> allStudents;  //一个学校有多个学生    public School(){     //无参构造方法        this.allStudents = new ArrayList<Student>();  //实例化List对象集合    }    public School(String name){        this();        this.setName(name);    }    public String getName(){        return name;    }    public void setName(String name){        this.name = name;    }    public List<Student> getAllStudents(){  //取得全部的学生        return allStudents;    }    public String toString(){        return "学校名称:" + this.name;    }}public class TestDemo{    public static void main(String args[]){        School sch = new School("WHPU");                Student s1 = new Student("forfan06", 27);        Student s2 = new Student("Lynn", 27);        Student s3 = new Student("Linda", 17);        Student s4 = new Student("forfan06", 19);                sch.getAllStudents().add(s1);        sch.getAllStudents().add(s2);        sch.getAllStudents().add(s3);        sch.getAllStudents().add(s4);                s1.setSchool(sch);        s2.setSchool(sch);        s3.setSchool(sch);        s4.setSchool(sch);                System.out.println(sch);        //实例化Iterator对象,用于输出全部的学生信息        Iterator<Student> iter = sch.getAllStudents().iterator();        while(iter.hasNext()){            System.out.println("\t|-" + iter.next());        }    }}

               程序首先分别实例化了School、Student类的对象,之后通过两个类中的属性保存彼此的引用关系,从而形成了一个学校有多个学生,一个学生属于一个学校的 一对多关系!!!!!!!!!!!

      13.11.2 范例 --- 多对多关系

            使用类集不仅可以表示出一对一的关系,也可以表示出多对多的关系。   例如,一个学生可以选多门课程,一门课程可以有多个学生参加; 那么这就是一个典型的多对多的关系!!!!

           要实现上面的功能,首先应该定义两个类,学生信息类Student、 课程信息类Course。 在一个学生类中存在一个集合,保存全部课程;而在一个课程类中也要存在一个集合,保存全部的学生!!!

范例:定义学生类

package org.forfan06.execdemo02;import java.util.List;import java.util.ArrayList;public class Student{    private String name;    private int age;    private List<Course> allCourses;    public Student(){        this.allCourses = new ArrayList<Course>();    }    public Student(String name, int age){        this();        this.setName(name);        this.setAge(age);    }    public void setName(String name){        this.name = name;    }    public String getName(){        return name;    }    public void setAge(int age){        this.age = age;    }    public int getAge(){        return age;    }        public List<Course> getAllCourses(){        return allCourses;    }        public String toString(){        return "学生姓名:" + this.name + ";年龄:" + this.age;    }}

          在学生类中存在一个 allCourses的 List集合 , 这样在程序运行时, 一个学生类中可以保存多个Course对象 。

范例:定义课程类

package org.forfan06.execdemo02;import java.util.List;import java.util.ArrayList;public class Course{    private String name;    private int credit;  //表示学分     private List<Student> allStudents;    public Course(){        this.allStudents = new ArrayList<Student>();    }    public Course(String name, int credit){        this();        this.setName(name);        this.setCredit(credit);    }    public String getName(){        return name;    }    public void setName(String name){        this.name = name;    }        public int getCredit(){        return credit;    }    public void setCredit(int credit){        this.credit = credit;    }        public List<Student> getAllStudents(){        return allStudents;    }    public void setAllStudents(List<Student> allStudents){        this.allStudents = allStudents;    }        public String toString(){        return "课程名称:" + this.name + ";课程学分:" + this.credit;    }}

          课程类与学生类一样,都定义了一个List集合,用于保存多个学生的信息 ! 

范例:测试代码

package org.forfan06.execdemo02;import java.util.List;import java.util.ArrayList;import java.util.Iterator;public class TestDemo{    public static void main(String args[]){        Course c1 = new Course("英语", 3);        Course c2 = new Course("计算机", 5);                Student s1 = new Student("forfan06", 27);        Student s2 = new Student("Linda", 17);        Student s3 = new Student("Lynn", 27);        Student s4 = new Student("forfan06", 19);        Student s5 = new Student("Sam", 45);        Student s6 = new Student("Dean", 21);        Student s7 = new Student("Eric", 31);                //第一门课有3个人参加,向课程中增加3个学生信息,同时向学生中增加课程信息        c1.getAllStudents().add(s1);  //向课程中增加学生信息         c1.getAllStudents().add(s2);        c1.getAllStudents().add(s5);        s1.getAllCourses().add(c1);    //向学生中增加课程信息        s2.getAllCourses().add(c1);        s5.getAllCourses().add(c1);                //第二门课有7个人参加 ,向课程中增加7个学生信息,同时向学生中增加课程信息        c2.getAllStudents().add(s1);//向课程中增加学生信息         c2.getAllStudents().add(s2);        c2.getAllStudents().add(s3);        c2.getAllStudents().add(s4);        c2.getAllStudents().add(s5);        c2.getAllStudents().add(s6);        c2.getAllStudents().add(s7);        s1.getAllCourses().add(c2);   //向学生中增加课程信息        s2.getAllCourses().add(c2);        s3.getAllCourses().add(c2);        s4.getAllCourses().add(c2);        s5.getAllCourses().add(c2);        s6.getAllCourses().add(c2);        s7.getAllCourses().add(c2);                //输出一门课程的信息,观察一门课程有多少个学生参加        System.out.println(c1);  //输出第一门课程信息        Iterator<Student> iter1 = c1.getAllStudents().iterator();        while(iter1.hasNext()){            System.out.println("\t|- " + iter1.next());        }                //输出一个学生参加的课程信息,观察有多少门课程         System.out.println(s3);        Iterator<Course> iter2 = s3.getAllCourses().iterator();        while(iter2.hasNext()){            Course c = iter2.next();            System.out.println("\t|- " + c);        }    }}

运行结果:

课程名称:英语;课程学分:3|- 学生姓名:forfan06;年龄:27|- 学生姓名:Linda;年龄:17|- 学生姓名:Sam;年龄:45学生姓名:Lynn;年龄:27|- 课程名称:计算机;课程学分:5

完整代码:

import java.util.List;import java.util.ArrayList;import java.util.Iterator;class Student{    private String name;    private int age;    private List<Course> allCourses;    public Student(){        this.allCourses = new ArrayList<Course>();    }    public Student(String name, int age){        this();        this.setName(name);        this.setAge(age);    }    public void setName(String name){        this.name = name;    }    public String getName(){        return name;    }    public void setAge(int age){        this.age = age;    }    public int getAge(){        return age;    }        public List<Course> getAllCourses(){        return allCourses;    }        public String toString(){        return "学生姓名:" + this.name + ";年龄:" + this.age;    }}class Course{    private String name;    private int credit;  //表示学分     private List<Student> allStudents;    public Course(){        this.allStudents = new ArrayList<Student>();    }    public Course(String name, int credit){        this();        this.setName(name);        this.setCredit(credit);    }    public String getName(){        return name;    }    public void setName(String name){        this.name = name;    }        public int getCredit(){        return credit;    }    public void setCredit(int credit){        this.credit = credit;    }        public List<Student> getAllStudents(){        return allStudents;    }    public void setAllStudents(List<Student> allStudents){        this.allStudents = allStudents;    }        public String toString(){        return "课程名称:" + this.name + ";课程学分:" + this.credit;    }}public class TestDemo{    public static void main(String args[]){        Course c1 = new Course("英语", 3);        Course c2 = new Course("计算机", 5);                Student s1 = new Student("forfan06", 27);        Student s2 = new Student("Linda", 17);        Student s3 = new Student("Lynn", 27);        Student s4 = new Student("forfan06", 19);        Student s5 = new Student("Sam", 45);        Student s6 = new Student("Dean", 21);        Student s7 = new Student("Eric", 31);                //第一门课有3个人参加,向课程中增加3个学生信息,同时向学生中增加课程信息        c1.getAllStudents().add(s1);  //向课程中增加学生信息         c1.getAllStudents().add(s2);        c1.getAllStudents().add(s5);        s1.getAllCourses().add(c1);    //向学生中增加课程信息        s2.getAllCourses().add(c1);        s5.getAllCourses().add(c1);                //第二门课有7个人参加 ,向课程中增加7个学生信息,同时向学生中增加课程信息        c2.getAllStudents().add(s1);//向课程中增加学生信息         c2.getAllStudents().add(s2);        c2.getAllStudents().add(s3);        c2.getAllStudents().add(s4);        c2.getAllStudents().add(s5);        c2.getAllStudents().add(s6);        c2.getAllStudents().add(s7);        s1.getAllCourses().add(c2);   //向学生中增加课程信息        s2.getAllCourses().add(c2);        s3.getAllCourses().add(c2);        s4.getAllCourses().add(c2);        s5.getAllCourses().add(c2);        s6.getAllCourses().add(c2);        s7.getAllCourses().add(c2);                //输出一门课程的信息,观察一门课程有多少个学生参加        System.out.println(c1);  //输出第一门课程信息        Iterator<Student> iter1 = c1.getAllStudents().iterator();        while(iter1.hasNext()){            System.out.println("\t|- " + iter1.next());        }                //输出一个学生参加的课程信息,观察有多少门课程         System.out.println(s3);        Iterator<Course> iter2 = s3.getAllCourses().iterator();        while(iter2.hasNext()){            Course c = iter2.next();            System.out.println("\t|- " + c);        }    }}

      从程序来看,设置关系的地方较为复杂, 因为现在的程序采用的是双向的处理关系,所以学生在选择一个课程时, 除了课程中要添加学生之外, 在学生中也要添加课程信息。

     在输出课程信息时, 可以通过课程对象中的集合找到参加此课程的全部学生信息,也可以通过学生对象找到全部参加的课程信息 。

13.12 本章要点

  1. 类集的目的是用来创建动态的对象数组操作 。
  2. Collection接口是类集众的最大单值 操作的父接口, 但是一般开发中不会直接使用此接口; 而 常使用List或Set接口。
  3. List接口扩展了Collection接口,里面的内容是允许重复的。
  4. List接口的常用子类是ArrayList和Vector类;在开发中ArrayList类的性能较高,属于异步处理;而Vector性能较低,属于同步处理。
  5. Set接口与Collection接口的定义一致,但是,Set接口里面的内容是不允许重复的,依靠Object类中的equals()、hashCode()方法来区分是否是同一个对象。
  6. Set接口的常用子类是HashSet和TreeSet类。前者HashSet类是散列存放,没有顺序;TreeSet类是顺序存放,使用Comparable进行排序操作。
  7. 集合的输出要使用Iterator接口完成,Iterator属于迭代输出接口。
  8. 在JDK1.5之后集合也可以使用foreach的方式输出。
  9. Enumeration属于最早的迭代输出接口,现在基本上很少使用,在类集中Vector类可以使用Enumeration接口进行内容的输出。
  10. List集合的操作可以使用ListIterator接口进行双向的输出操作。
  11. Map接口可以存放一对内容,所有的内容都是以  key --> value 的形式保存,每一对 key --> value都是一个Map.Entry对象的实例。
  12. Map中的常用子类有HashMap、TreeMap、Hashtable。HashMap属于异步处理,性能较高;TreeMap属于排序类,按照Comparable指定的顺序进行key的排序;Hashtable属于同步处理,性能较低。
  13. 类集众提供了Collections工具类完成类集的相关操作。
  14. Stack类可以完成先进后出的操作。
  15. Properties类属于属性操作类,使用属性操作类可以直接操作属性文件,属性文件可以按普通文件或XML的文件格式进行保存。
  16. 使用类集可以方便地表示出一对多、多对多的关系。

13.13 习题

  1. 编写学生类,该类定义了3个属性: 学号、姓名、成绩。 可以通过构造方法设置3个属性的内容,并覆写Object类中的toString()方法,在List集合中加入5个学生对象,并将内容输出,之后使用比较器将对象的内容进行排序并显示在屏幕上。
  2. 完成一个学生管理程序,使用学号作为键添加5个学生对象,并可以将全部的信息保存在文件中,可以实现对学生信息的学号查找、输出全部学生信息的功能。
  3. 自己手动编写一个双向链表。
  4. 编写程序通过栈的方式将任意输入的字符串内容进行逆序输出。
  5. 将本章中讲解的一对多关系加入菜单及文件的操作,可以试想一个学校-学生的管理程序。
2 0