北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 1 1、课程名称:Java 类集 2、知识点 2.1、上次课程的主要知识点 1、 File 类,与文件本身的操作有关,例如:文件的创建、文件夹的创建、文件的删除、列表等操作; 2、 字节流和字符流: · 字节流:OutputStream、InputStream、直接与终端操作; · 字符流:Writer、Reader、中间通过缓冲区与终端交互; 3、 文件流:FileOutputStream、FileInputStream、FileWriter、FileReader · 所有的输出都是向文件之中,所有的输入都是从文件中而来; 4、 内存流:ByteArrayOutputStream、ByteArrayInputStream、CharArrayOutputStream、CharArrayInputStream · 所有的输出都是向内存中完成,所有的输入都是从内存中而来; · 内存流为以后讲解 AJAX + XML + DOM 的时候使用的。 5、 打印流:PrintStream、PrintWriter; 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 2 · 打印流属于装饰设计模式,本身需要给一个输出的位置(OutputStream 子类指定),使用打印流可以方便的完成数 据的操作,提供了一系列的 print()或 println()方法; 6、 JDK 1.5 新特性的支持 —— java.util.Scanner · Scanner 提供了方便的数据输入流的操作功能; 7、 以后只要是输出就是 PrintStream、只要是输入数据都使用 Scanner; 8、 对象序列化,重点的是概念以及 Serializable 接口,对象序列化使用的时候就是可以将一个内存中保存的对象以二进 制数据流的形式传递。 2.2、本次预计讲解的知识点 1、 类集的主要组成及核心操作接口; 2、 类集的输出操作; 3、 类集的实际应用。 3、具体内容 Java SE 的第二大重点就是类集(集合框架)。 3.1、认识类集(重点) 对象数组本身可以保存一组对象,但是对象数组本身却存在一个致命的缺点就是数据的长度是有限的,而之后采用 了链表的形式可以完成动态的对象数组,但是链表的开发相当的麻烦,而且链表又是实际工作中经常使用到的内容,这样 一来如果让用户每次都自己开发链表根本就不现实,所以在 java 之中,专门为用户提供好了数据结构的实现 —— 类集(集 合框架)。 在整个的类集之中基本上都是接口的应用,定义了如下几个核心接口:Collection、List、Set、Map、Iterator、Enumeration。 3.2、保存单值的最大父接口:Collection(重点) 在之前的自己手工开发的链表程序之中,可以发现,所有的程序每次保存的时候都是保存了一个对象,就好比压子 弹一样,每次只能压一颗子弹进去。 在 Collection 接口中定义了 15 个方法,但是有如下的几个核心方法: No. 方法名称 类型 描述 1 public Iterator iterator() 普通 取得 Iterator 接口实例 2 public boolean add(E e) 普通 向集合中增加元素 3 public boolean contains(Object o) 普通 判断某一个对象是否存在 4 public boolean remove(Object o) 普通 从集合中删除一个对象 5 public int size() 普通 返回集合中元素的个数 6 public Object[] toArray() 普通 将集合中的数据变为对象数组形式返回 7 public T[] toArray(T[] a) 普通 返回指定类型的对象数组 以上接口中的大部分方法基本上都在之前开发链表的时候使用过了,其基本的原理不再重复了。 但是按照最早的设计理论来讲,所有的操作应该以父接口为主,但是这一点在类集的设计上就需要稍微变更了一下, 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 3 Collection 是作为单值的最大父接口,但是其下有两个子接口:List、Set,实际中基本上已经不再出现直接使用 Collection 接口的情况了,而都使用它的子接口。 1998 年 ~ 2003 年之间,一直提倡使用的是 Collection 接口,这一点在 EJB 2.x 技术之中体现的非常明显,但是后来 到了 SUN 的 PET SHOP 开源项目之中不再直接使用 Collection 了, 而使用 List 或 Set 接口了。 Pet Shop 这个项目最早的时候不是由 SUN 开发的,而是有许多的爱好者开发的,但是此项目由于没有做任何的合理 性的设计,而且代码结构极其的混乱,所以导致此项目的性能并不高。 3.3、允许重复允许为空的子接口:List(重点),70% List 接口属于 Collection 接口的子接口,但是此接口扩充了许多的 Collection 接口的方法,但是从实际的使用来讲, 还是建议以 Collection 接口中的方法为主,List 主要有以下几个方法需要了解: No. 方法名称 类型 描述 1 public E get(int index) 普通 根据下标取得指定位置的对象 2 public E set(int index,E element) 普通 修改指定位置上的内容 3 public List subList(int fromIndex,int toIndex) 普通 取出指定范围的子集合 4 public ListIterator listIterator() 普通 取得 ListIterator 的实例 List 本身也是一个接口,所以按照面向对象的概念来理解的话,那么应该通过子类为父接口进行实例化操作。 3.3.1、新的子类:ArrayList ArrayList 类是 List 接口的子类,也是最常用的一个子类,此类定义如下: public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, Serializable ArrayList 继承了 AbstractList 类,这个类的定义如下: public abstract class AbstractList extends AbstractCollection implements List 之所以这样的重复定义,就深怕某些同志们不知道 ArrayList 是 List 接口的子类。 范例:增加元素及输出元素 package org.lxh.demo; import java.util.ArrayList; import java.util.List; public class CollectionDemo { public static void main(String[] args) { List all = new ArrayList(); // 为接口实例化 all.add("hello"); // 增加元素 all.add("hello"); // 增加重复元素 all.add("world"); // 增加元素 for (int x = 0; x < all.size(); x++) { System.out.println(all.get(x)); // 取出每一个内容 } } 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 4 } 以上的操作是集合的基本操作,从实际应用来讲,集合中增加元素及取得元素的操作使用的是最多的。 范例:其他操作 package org.lxh.demo; import java.util.ArrayList; import java.util.List; public class CollectionDemo { public static void main(String[] args) { List all = new ArrayList(); // 为接口实例化 System.out.println("size = " + all.size()); System.out.println("isEmpty = " + all.isEmpty()); // 判断是否为null all.add("hello"); // 增加元素 all.add("hello"); // 增加重复元素 all.add("world"); // 增加元素 System.out.println("size = " + all.size()); System.out.println("isEmpty = " + all.isEmpty()); // 判断是否为null all.remove("hello"); // 删除指定元素 System.out.println("删除元素之后的集合内容:" + all); all.set(1, "MLDN"); // 修改指定位置的元素 System.out.println("修改元素之后的集合内容:" + all); System.out.println("MLDN是否存在:" + all.contains("MLDN")); } } 由于 List 是 Collection 接口的子接口,所以现在也可以使用 ArrayList 类为 Collection 接口进行对象的实例化操作。 范例:直接使用 Collection 操作 package org.lxh.demo; import java.util.ArrayList; import java.util.Collection; public class CollectionDemo { public static void main(String[] args) { Collection all = new ArrayList(); // 为接口实例化 all.add("hello"); // 增加元素 all.add("hello"); // 增加重复元素 all.add("world"); // 增加元素 Object[] obj = all.toArray(); // 变为对象数组 for (int x = 0; x < obj.length; x++) { String str = (String) obj[x]; // 存在安全隐患 System.out.println(str); } } } List 的操作要比 Collection 的操作更加的方便,而且以上的代码会存在 ClassCastException 的安全隐患,所以在 JDK 1.5 之后,Collection 又增加了一个新的方法:public T[] toArray(T[] a) String[] str = all.toArray(new String[] {}); // 变为对象数组 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 5 for (int x = 0; x < str.length; x++) { System.out.println(str[x]); } 这种操作根本就不舒服,只能算是补救。 3.3.2、旧的子类:Vector Vector 类也是 List 的子类,此类的定义如下: public class Vector extends AbstractList implements List, RandomAccess, Cloneable, Serializable Vector 类同样是 AbstractList 抽象类的子类,实际上 Vector 类是一个非常古老的操作类,是在 Java 推出的时候就有的, 当时被称为“向量”,但是后来到了 JDK 1.2(Java 2)之后,java 开始提出了集合框架的概念,原本是打算废除掉 Vector, 但是后来由于很多的开发者已经习惯于使用此类了,所以 SUN 的设计师就考虑让其多实现了一个 List 接口,这样才被保 留下来了。 范例:使用 Vectory package org.lxh.demo; import java.util.Collection; import java.util.Vector; public class CollectionDemo { public static void main(String[] args) { Collection all = new Vector(); // 为接口实例化 all.add("hello"); // 增加元素 all.add("hello"); // 增加重复元素 all.add("world"); // 增加元素 String[] str = all.toArray(new String[] {}); // 变为对象数组 for (int x = 0; x < str.length; x++) { System.out.println(str[x]); } } } 不管每个类的具体的操作是什么,都以为接口为准。 3.3.3、ArrayList 和 Vector 类的区别 ArrayList 和 Vector 类都属于 List 接口的子类,那么这两个类有何种区别呢? No. 区别 ArrayList Vector 1 推出时间 JDK 1.2 之后推出 JDK 1.0 时推出 2 性能 采用异步处理方式性能更高 采用同步处理方式,性能相对较低 3 安全性 非线程安全的操作 线程安全的操作 4 输出 支持 Iterator、ListIterator、foreach 支持 Iterator、ListIterator、foreach、Enumeration 从实际来讲,主要使用的是 ArrayList,因为 java 主要是应用在网络开发上。 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 6 3.4、不允许重复允许为空的子接口:Set(重点),20% 与 List 接口对应的还有 Set 子接口,此接口中保存的所有数据都是不允许重复的,Set 接口并不像 List 接口那样对 Collection 接口做了大量的扩充,而是完整的继承了下来,而 Set 接口中也有两个常用的子类:HashSet、TreeSet。 3.4.1、散列存放的子类:HashSet HashSet 属于无序的存放类,里面的所有元素都采用无序的方式保存。 package org.lxh.demo; import java.util.HashSet; import java.util.Set; public class CollectionDemo { public static void main(String[] args) { Set all = new HashSet(); // 实例化Set接口对象 all.add("hello"); all.add("hello"); // 重复元素不能保存 all.add("world"); all.add("mldn"); all.add("mabohui"); System.out.println(all); } } Set 集合之中发现不能保存任何的重复元素,而且元素的保存也是无序的,更重要的是与 List 相比,List 是按照插入 顺序保存的,而 Set 不是。 3.4.2、有存放的子类:TreeSet TreeSet 是可以进行排序的子类,里面的每个元素都可以按照顺序保存。 package org.lxh.demo; import java.util.Set; import java.util.TreeSet; public class CollectionDemo { public static void main(String[] args) { Set all = new TreeSet(); // 实例化Set接口对象 all.add("B"); all.add("C"); all.add("A"); all.add("X"); all.add("M"); System.out.println(all); } } 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 7 现在所有的数据已经可以正常的排序了。 3.4.3、关于数据排序的说明(重点) TreeSet 类中的数据可以排序,那么之前操作的是 String 型的数据,如果现在给出的是一个用户自己定义的类呢? 由于此类的对象要涉及到对象的比较问题,所以对象所在的类中必须实现 Comparable 接口,同时指定比较规则。 在指定比较规则的时候一定要注意的是,类中的每一个属性都必须比较其大小。 package org.lxh.demo; import java.util.Set; import java.util.TreeSet; class Person implements Comparable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "姓名:" + this.name + ",年龄:" + this.age + "\n"; } @Override public int compareTo(Person o) { if (this.age > o.age) { return 1; } else if (this.age < o.age) { return -1; } else { return this.name.compareTo(o.name); // 继续调用String类中的compareTo()方法 } } } public class CollectionDemo { public static void main(String[] args) { Set all = new TreeSet(); // 实例化Set接口对象 all.add(new Person("张三", 30)); all.add(new Person("张三", 30)); // 完全重复 all.add(new Person("王五", 28)); all.add(new Person("赵六", 50)); all.add(new Person("李四", 30)); // 姓名不同,年龄相同 System.out.println(all); } } 所有的对象排序都需要 Comparable 接口的支持,而且在进行比较的时候必须将每一个属性都分别完成比较的操作, 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 8 但是以上操作的时候发现如果现在有重复元素也没有保存,可是这并不是真正意义上的重复元素的操作,而是 TreeSet 特 有的一种支持,依靠 Comparable 完成,只要属性完全相等就认为是同一个对象。 3.4.4、关于对象重复元素的说明 Set 接口中的数据是没有重复元素的,那么这样一来,程序是如何区分重复元素的呢? 所以在程序之中这种重复元素的判断首先必须知道一个对象的唯一编号,之后如果发现此编号了,则就要进行进一 步的比较,例如:比较查到的和原本的属性是否一致,如果一样,则认为是重复的,如果不一样,则认为不是重复的。 这个编号在 Java 之中就依靠 Object 类中的方法:public int hashCode(),但是有一个问题,身份证编号是有一个固定 的公式的,可是对象该如何设计这个公式呢?而且光有公式也不行,还需要 equals()的支持。 package org.lxh.demo; import java.util.HashSet; import java.util.Set; class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "姓名:" + this.name + ",年龄:" + this.age + "\n"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 9 if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } } public class CollectionDemo { public static void main(String[] args) { Set all = new HashSet(); // 实例化Set接口对象 all.add(new Person("张三", 30)); all.add(new Person("张三", 30)); // 完全重复 all.add(new Person("王五", 28)); all.add(new Person("赵六", 50)); all.add(new Person("李四", 30)); // 姓名不同,年龄相同 System.out.println(all); } } 在 Collection 中 remove()方法实际上要想删除一个对象依靠的也是 hashCode()和 equals()两个方法。 以后如果要进行数据结构的开发,标准的做法首先要找到 hashCode(),找到之后,再使用 equals()判断,最后才能确 定是否是重复以及是否可以删除。 3.5、集合的输出(重点) 之前所讲解过的所有的操作实际上都没有解决集合的输出问题,在集合框架之中,集合的输出一共有四种操作形式。 3.5.1、Iterator 输出(核心重点) 在集合之中存在了一个 Iterator 接口,此接口的主要功能是用于集合的输出操作,此接口定义如下几个方法: No. 方法名称 类型 描述 1 public boolean hasNext() 普通 判断是否还有内容 2 public E next() 普通 取出内容 3 public void remove() 普通 删除当前元素 之前学习过的 Scanner 类就是 java.util.Iterator 接口的子类,而且现在有一个问题,Iterator 如何可以进行对象的实例化 呢?依靠 Collection 接口中的:public Iterator iterator()方法。 package org.lxh.demo; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class CollectionDemo { public static void main(String[] args) { List all = new ArrayList(); all.add("hello"); 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 10 all.add("world"); all.add("mldn"); Iterator iter = all.iterator(); // 实例化Iterator接口 while (iter.hasNext()) { // 判断是否有内容 String str = iter.next(); // 取出内容 System.out.println(str); } } } 此操作在 Collection 接口中定义,所以 List 和 Set 接口都肯定存在此方式,而且从实际开发来讲,只要是集合的输出 都使用 Iterator 完成。 3.5.2、双向输出接口:ListIterator Iterator 接口可以完成由前向后的输出,但是如果现在要想完成双向的输出就只能靠 Iterator 的子接口,ListIterator 接 口完成了,此接口定义了如下的几个方法: No. 方法名称 类型 描述 1 public boolean hasPrevious() 普通 判断是否有上一个元素 2 public E previous() 普通 取出当前元素 但是 Collection 接口中可没有定义为此接口实例化的操作,而要想为此接口实例化只能使用 List 接口完成,有如下一 个方法:public ListIterator listIterator()。 package org.lxh.demo; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; public class CollectionDemo { public static void main(String[] args) { List all = new ArrayList(); all.add("hello"); all.add("world"); all.add("mldn"); ListIterator iter = all.listIterator(); // 实例化ListIterator接口 System.out.println("===== 由前向后输出 ====="); while (iter.hasNext()) { // 判断是否有内容 String str = iter.next(); // 取出内容 System.out.println(str); } System.out.println("===== 由后向前输出 ====="); while (iter.hasPrevious()) { // 判断是否有内容 String str = iter.previous(); // 取出内容 System.out.println(str); } } } 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 11 但是有一点也需要注意的是,如果现在要想完成由后向前的输出,必须首先进行由前向后的输出操作。 3.5.3、废弃的接口:Enumeration(重点) Enumeration 实际上最早的时候就称为枚举输出,但是为此接口实例化的方法不在 Collection、List、Set 接口之中,而 只在 Vector 类之中。因为 Vector 和 Enumeration 最早的时候都属于元老级的类,在 Vector 类中定义了如下的一个方法: · 方法:public Enumeration elements() Enumeration 接口中定义了如下两个方法: No. 方法名称 类型 描述 1 public boolean hasMoreElements() 普通 判断是否有下一个元素 2 public E nextElement() 普通 取出当前元素 可以发现 Enumeration 接口中定义的方法与 Iterator 接口中定义方法的功能类似,但是,单词太长了,所以才被废除。 package org.lxh.demo; import java.util.Enumeration; import java.util.Vector; public class CollectionDemo { public static void main(String[] args) { Vector all = new Vector(); all.add("hello"); all.add("world"); all.add("mldn"); Enumeration enu = all.elements(); while (enu.hasMoreElements()) { String str = enu.nextElement(); // 取出元素 System.out.println(str); } } } Enumeration 和 Iterator 相比较肯定还是 Iterator 接口使用起来会比较方便一些,所以开发中 90%都是使用了 Iterator 接口,但是却有 5%的情况使用了 Enumeration。 3.5.4、JDK 1.5 的新支持 —— foreach 在 JDK 1.5 之后 for 循环增加了功能,除了可以方便的输出数组之外,也可以输出集合了。 package org.lxh.demo; import java.util.Vector; public class CollectionDemo { public static void main(String[] args) { Vector all = new Vector(); all.add("hello"); all.add("world"); all.add("mldn"); for (String str : all) { // 取出每一个元素给了str 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 12 System.out.println(str); } } } 通过代码的比较可以发现 foreach 输出比较简单,但是 100%不许用。 3.6、偶对象:Map 接口(重点) Collection 接口每次操作的时候都是针对于一个对象完成的,但是有时候往往会出现一对的信息。 · 结婚登记,肯定是两个人,两个人一起登记才有效。 · 电话号码本,肯定要有姓名要有号码。 这样的数据,每次都要保存一对,那么这就是 Map 接口的作用,以电话本为例,实际上姓名就相当于是查找的 key, 而电话号码就相当于要找到 value,是一种:key  value 的形式保存的; · 张三 123456 · 李四 234567 如果要张到“张三”的电话,则肯定要先根据 key 找到“张三”,之后再由张三得到号码,Map 接口中也定义了许多 的方法,如下所示。 No. 方法名称 类型 描述 1 public V put(K key,V value) 普通 向集合保存数据 2 public V get(Object key) 普通 根据 key 查找 value 3 public Set> entrySet() 普通 将 Map 集合变为 Set 集合 4 public int size() 普通 取得集合中的全部数据个数 5 public boolean containsKey(Object key) 普通 判断某一个 key 是否存在,靠 hashCode()、equals() 6 public boolean containsValue(Object value) 普通 判断某一个 value 是否存在 7 public Set keySet() 普通 取出全部的 key,不能重复 8 public Collection values() 普通 取出全部的 value,可以重复 在 Map 接口中也有三个主要使用的子类:HashMap、Hashtable、TreeMap。 3.6.1、新的子类:HashMap HashMap 子类是 Map 接口中使用最多的一个子类,此类使用的时候依然以 Map 接口中定义的方法为主。 package org.lxh.demo; import java.util.HashMap; import java.util.Map; public class CollectionDemo { public static void main(String[] args) { Map map = new HashMap(); map.put("zs", "ZhangSan"); map.put("ls", "LiSi"); map.put("ww", "WangWu"); String val = map.get("zs"); // 内容 System.out.println(val); System.out.println(map.get("zl")); // 内容不存在,返回null 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 13 } } 可以发现 Map 集合中的主要功能除了可以保存数据之外,最大的特点还在于可以进行数据的查询,而 Collection 只 是保存或者输出数据。 范例:取出集合中的全部 key package org.lxh.demo; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class CollectionDemo { public static void main(String[] args) { Map map = new HashMap(); map.put("zs", "ZhangSan"); map.put("ls", "LiSi"); map.put("ww", "WangWu"); Set keys = map.keySet(); // 取出全部的key Iterator iter = keys.iterator(); while (iter.hasNext()) { String key = iter.next() ; System.out.println(key + " --> " + map.get(key)) ; } } } Map 操作的形式是比较固定的,主要就是设置内容之后进行查找使用,而且 HashMap 中的数据是无序的,因为 key 没有序,而且使用了 HashMap 子类的话,可以将 key 或 value 设置成 null。 3.6.2、排序的集合:TreeMap 如果现在希望 Map 中的数据可以按照 key 进行排序的话,则就要使用 TreeMap,但是不管如何操作,使用记住了, key 也是一组对象,所以这个时候的排序还是依靠了 Comparable 接口完成的。 package org.lxh.demo; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class CollectionDemo { public static void main(String[] args) { Map map = new TreeMap(); map.put("zs", "ZhangSan"); map.put("ls", "LiSi"); map.put("ww", "WangWu"); Set keys = map.keySet(); // 取出全部的key Iterator iter = keys.iterator(); 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 14 while (iter.hasNext()) { String key = iter.next() ; System.out.println(key + " --> " + map.get(key)) ; } } } TreeMap 中 key 是不能设置成 null 的,否则会出现 NullPointerException 异常。 3.6.3、旧的子类:Hashtable Hashtable 也属于一个古老的操作类,是最早实现这种偶对象保存的类,最早也称为哈希表。 package org.lxh.demo; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Set; public class CollectionDemo { public static void main(String[] args) { Map map = new Hashtable(); map.put("zs", "ZhangSan"); map.put("ls", "LiSi"); map.put("ww", "WangWu"); Set keys = map.keySet(); // 取出全部的key Iterator iter = keys.iterator(); while (iter.hasNext()) { String key = iter.next() ; System.out.println(key + " --> " + map.get(key)) ; } } } 通过以上的程序可以发现,Hashtable 中的内容也是无序的,而且也不能设置成 null。 3.6.4、HashMap 和 Hashtable 的区别 HashMap 和 Hashtable 都属于 Map 接口的子类,那么这两个类有何种区别呢? No. 区别 HashMap Hashtable 1 推出时间 JDK 1.2 之后推出 JDK 1.0 时推出 2 性能 采用异步处理方式性能更高 采用同步处理方式,性能相对较低 3 安全性 非线程安全的操作 线程安全的操作 4 key 为 null 允许为 null 不允许为 null,否则出现异常 从实际来讲,主要使用的是 HashMap 类,因为 java 主要是应用在网络开发上。 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 15 3.6.5、关于 Map 接口的输出(核心重点) Map 本身就属于一个集合,既然是集合之前就已经给出了一个明确的要求:所有的集合必须通过 Iterator 输出,但是 Map 中不能直接使用 Iterator 输出,因为 Iterator 是要依次找到每一个对象,但是 Map 中的每一个对象是一对。 通过以上的图形发现,对于 Map 集合中的每一对元素,实际上都会默认的将其包装成 Map.Entry 保存,而 Map.Entry 中就分别保存了每一对数据的 key 和 value 的内容,也就是说如果现在非要使用 Iterator 输出的话,则每一次调用 next()方 法取出的是 Map.Entry 对象。 Map.Entry 接口定义如下: public static interface Map.Entry 从定义上可以发现,这个接口是 Map 接口的子接口,而且使用了 static 关键字进行了定义,此接口定义方法: No. 方法名称 类型 描述 1 public K getKey() 普通 取出 key 2 public V getValue() 普通 取出 value 如果现在 Map 要想直接通过 Iterator 输出的话,那么可以按照如下步骤进行: 1、 使用 Map 接口中的 entrySet()方法,将 Map 集合全部变为 Set 集合; 2、 Set 接口中存在着 Iterator 方法,通过 Set 接口为 Iterator 实例化; 3、 迭代取出 Set 集合(Map 集合)中的每一个元素,并进行 key 与 value 的分离; 范例:使用 Iterator 输出 Map 集合 package org.lxh.demo; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Set; public class CollectionDemo { public static void main(String[] args) { Map map = new Hashtable(); map.put("zs", "ZhangSan"); map.put("ls", "LiSi"); map.put("ww", "WangWu"); Set> set = map.entrySet();// 将Map集合变为Set集合 Iterator> iter = set.iterator(); // 实例化Iterator接口 while (iter.hasNext()) { Map.Entry me = iter.next(); // 取出每一个元素 System.out.println(me.getKey() + " --> " + me.getValue()); // 进行key和value 分离 } } } 以上的代码是 Map 集合输出的标准格式,以后但凡有此操作,其核心的原理都是一样的。 范例:现在也可以使用 foreach 输出,但是这种操作并不建议使用 package org.lxh.demo; import java.util.Hashtable; 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 16 import java.util.Map; public class CollectionDemo { public static void main(String[] args) { Map map = new Hashtable(); map.put("zs", "ZhangSan"); map.put("ls", "LiSi"); map.put("ww", "WangWu"); for (Map.Entry me : map.entrySet()) { System.out.println(me.getKey() + " --> " + me.getValue()); } } } Map 集合的 Iterator 输出是一个代码相对麻烦的一个操作,但是这种操作是以后所有开发中必定要使用的一种,而对 于这种 foreach 输出,就当是个玩具完了,别当真,别使用,知道就行了。 3.6.6、关于 key 的说明 从 Map 集合的定义中可以发现,Map 上可以指定 K 和 V 的泛型,而且之前的很多程序都是使用了 String 作为了 key 出现的,那么如果要想使用一个自定义的类呢? 可以发现一个自定义的类现在如果作为 key 出现确实找不到对应的 value,因为这个时候一个类要想作为 key 出现必 须有一个对象的编号,而这个编号就需要 hashCode()的支持,但是只有 hashCode()也不行,还需要覆写 equals()。 即:任何一个想要作为 key 的类,都必须覆写 hashCode()和 equals()。 package org.lxh.demo; import java.util.HashMap; import java.util.Map; class Person { private String name; public Person(String name) { this.name = name; } @Override public String toString() { return "姓名:" + this.name; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 17 return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } } public class CollectionDemo { public static void main(String[] args) { Map map = new HashMap(); map.put(new Person("张三"), new String("zs")); System.out.println(map.get(new Person("张三"))); } } 在实际的工作之中,使用 String 作为 key 是最常见的,而使用自定义的类作为 key 比较少见。 3.7、栈操作:Stack(理解) 栈是一个典型的先进后出的数据结构。 一般在编辑软件上有撤消功能。 像 IE 浏览器上的后退的功能,最后打开的首先后退,这些都是通过栈实现的,而要想实现这个操作在 Java 中就可以 使用 Stack 类,此类的定义如下: public class Stack extends Vector 此类是 Vector 类的子类,栈的主要操作就是入栈和出栈,所以在此类中提供了如下的方法: No. 方法名称 类型 描述 1 public E push(E item) 普通 入栈 2 public E pop() 普通 出栈 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 18 范例:观察栈的操作 package org.lxh.demo; import java.util.Stack; public class CollectionDemo { public static void main(String[] args) { Stack st = new Stack(); st.push("A"); st.push("B"); st.push("C"); System.out.println(st.pop()); System.out.println(st.pop()); System.out.println(st.pop()); System.out.println(st.pop()); // 异常,EmptyStackException } } 栈的这种数据结构最早的时候在“字符串反转”操作上使用的比较多一些,但是由于 StringBuffer 已经提供了 reverse() 方法,所以栈的作用大概理解即可,不用做多深入的掌握了。 3.8、属性操作类:Properties(重点) 在之前讲解国际化程序的时候讲解过一种称为资源文件的操作,在资源文件之中所保存的数据是:“key=value”的形 式,那么在 Java 类集中专门提供了与之对应的操作类 Properties,这个类定义如下: public class Properties extends Hashtable 在此类中由于设置的都是属性,所以 key 和 value 都是 String,此类的常用方法如下: No. 方法名称 类型 描述 1 public Object setProperty(String key,String value) 普通 设置属性 2 public String getProperty(String key) 普通 根据 key 取得属性内容,没有返回 null 3 public String getProperty(String key,String defaultValue) 普通 根据 key 取得属性内容,没有返回默认值 4 public void store(OutputStream out,String comments) throws IOException 普通 向指定的输出流中输出所有的属性内容 5 public void storeToXML(OutputStream os,String comment) throws IOException 普通 以 XML 文件格式输出内容 6 public void load(InputStream inStream) throws IOException 普通 从指定的输入流读取属性内容 7 public void loadFromXML(InputStream in) throws IOException,InvalidPropertiesFormatException 普通 从指定的输入流中读取 XML 文件格式的数据 范例:设置和取得属性 package org.lxh.demo; import java.util.Properties; public class CollectionDemo { public static void main(String[] args) { 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 19 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","NOFOUND")); } } 范例:将所有的属性保存在普通属性文件之中 package org.lxh.demo; import java.io.File; import java.io.FileOutputStream; import java.util.Properties; public class CollectionDemo { 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"); } } 范例:也可以将属性保存成 XML 风格的文件样式 package org.lxh.demo; import java.io.File; import java.io.FileOutputStream; import java.util.Properties; public class CollectionDemo { 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"); } } 范例:从普通的文件流中读取属性内容 package org.lxh.demo; import java.io.File; import java.io.FileInputStream; import java.util.Properties; public class CollectionDemo { public static void main(String[] args) throws Exception { Properties pro = new Properties(); 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 20 pro.load(new FileInputStream(new File("D:" + File.separator + "area.properties"))) ; System.out.println(pro.getProperty("TJ")); } } 范例:从 XML 风格的文件中读取数据 package org.lxh.demo; import java.io.File; import java.io.FileInputStream; import java.util.Properties; public class CollectionDemo { 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("TJ")); } } 属性文件的操作等下在集合的应用上进行深入的讲解,此处先将基本语法掌握。 3.9、集合的工具类:Collections(了解) 在 java.util 包中提供了一个 Collections 的类,此类定义如下: public class Collections extends Object 面试题:请解释 Collection 和 Collections 的关系 · 两者之间没有任何继承的关系,而 Collections 只是提供了一个操作工具而已。 范例:直接观察代码 package org.lxh.demo; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class CollectionDemo { public static void main(String[] args) throws Exception { List all = new ArrayList(); Collections.addAll(all, "hello", "world", "mldn"); Collections.reverse(all) ; System.out.println(all); } } 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 21 3.10、集合的应用(重点) 3.10.1、工厂设计模式深入 工厂设计模式的主要目的,进行解耦合操作,即:所有的接口的子类对象可以不通过 new 直接取得实例,而通过工 厂取得。 package org.lxh.demo; interface Fruit{ public void eat() ; } class Apple implements Fruit{ public void eat(){ System.out.println("** 吃苹果。") ; } } class Orange implements Fruit{ public void eat(){ System.out.println("** 吃橘子。") ; } } class Factory { public static Fruit getFruit(String className){ Fruit fruit = null ; try { fruit = (Fruit) Class.forName(className).newInstance() ; }catch(Exception e){} return fruit ; } } public class CollectionDemo { public static void main(String[] args) throws Exception { Fruit fruit = Factory.getFruit("org.lxh.demo.Apple") ; fruit.eat() ; } } 如果现在的程序按照此种方式开发,的确可以解决了工厂的扩充及接口取得对象实例化的问题,但是对于日后程序 的用户修改层面上是否方便? 如果现在将之前的“包.类”名称通过程序的编写,则对于日后的维护不方便,那么如果现在假设将其定义在一个资 源文件之中呢? 范例:定义 fruit.properties 文件 #AREA INFO #Mon Sep 13 14:18:04 CST 2010 fruit=org.lxh.demo.Apple 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 22 范例:随后在程序中通过读取资源文件完成子类的读取 public class CollectionDemo { public static void main(String[] args) throws Exception { Properties pro = new Properties() ; pro.load(new FileInputStream(new File("D:"+File.separator+"fruit.properties"))) ; Fruit fruit = Factory.getFruit(pro.getProperty("fruit")) ; fruit.eat() ; } } 就是说现在的程序之中是通过一个资源文件控制着程序的运行效果,那么以后如果碰到了修改的时候直接修改资源 文件的配置即可,这样的话,程序不用做任何的变化。 但是如果每一个小程序都需要这些资源文件来配置的话,那么实际上另外一个问题就会出现,这样的话会造成资源 文件满天飞。 3.10.2、关系应用 emp、dept 是最常用的两张表,这个时候已经可以具备了通过程序表示这两个类之间关系的程度了。 曾经解释过,这种单独表示某一种类型的类都称为简单 Java 类,现在对于这样的简单 Java 类也有了明确的要求: · 这种类为了以后的扩展方便,必须都实现 java.io.Serializable 接口; · 类中的所有属性不能出现任何的基本数据类型,只能是包装类; @SuppressWarnings("serial") class Emp implements java.io.Serializable { private Integer empno; private String ename; private String job; private Date hiredate; private Double sal; private Double comm; private Emp mgr; private Dept dept; // 每个雇员属于一个部门 } @SuppressWarnings("serial") class Dept implements java.io.Serializable { private Integer deptno; private String dname; private String loc; private List emps; // 一个部门有多个雇员 } 使用 List 可以很典型的表示出一对多的操作关系。 北大青鸟---北大公学---青鸟学社倾情奉献(组织部、校联部、文体部、科技文化部、纪检部、宣传部) 祝学弟学妹们学习愉快 人生就是历练、活着就要挑战 易婷 23 4、总结 1、 集合出现的主要目的是为了解决动态数组操作的,核心就是增加及输出; 2、 List 允许重复、Set 不允许重复,List 使用较多; · Set 依靠的是 hashCode()和 equals()区分重复元素的; 3、 集合的输出任何时候都使用 Iterator 完成; 4、 Map 保存一对内容,主要的功能是用于查找使用; 5、 属性操作类可以直接进行属性文件的操作。
还剩22页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

471685249

贡献于2013-05-27

下载需要 5 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf