java基础---->Java Collections Framework
一、类集概述
1.1、类集的引入
最早的时候可以通过对象数组保存一组数据,但是慢慢的发现如果程序中都使用对象数组开发的话,本身会存在大小的限制问题,即:所有的数组的大小是不可改变的,但是从实际的开发来看,有很多的时候是根本就无法知道到底要开辟多少的数组空间,后来通过链表解决类此类问题,但是如果每一次的开发中都使用链表的话,肯定很麻烦,所以在Java中专门提供了一套动态对象数组的操作类——类集框架,在Java中类集框架实际上也就是对数据结构的Java实现。
1.2、主要接口
在Java中类集框架里,为了操作方便提供了一系列的类集的操作接口,主要的操作接口有以下三个:
· Collection:存放单值的最大父接口 public interface Collection<E> extendsIterable<E>
· Map:是存放一对的内容 public interface Map<K,V>
· Iterator:输出作用 public interface Iterator<E>
在以上的三个接口中Collection接口并不会被直接使用,而都使用它的两个子接口:List、Set。
在Collection接口中定义了如下的几个核心操作:
No. |
方法名称 |
类型 |
描述 |
1 |
public boolean add(E e) |
普通 |
向集合中增加元素 |
2 |
public void clear() |
普通 |
删除集合中的全部内容 |
3 |
public boolean contains(Object o) |
普通 |
判断指定内容是否存在 |
4 |
public Iterator<E> iterator() |
普通 |
为Iterator接口实例化 |
5 |
public boolean remove(Object o) |
普通 |
从集合中删除元素 |
6 |
public int size() |
普通 |
取得集合的大小 |
7 |
public Object[] toArray() |
普通 |
将集合变为对象数组输出 |
8 |
public <T> T[] toArray(T[] a) |
普通 |
将集合变为对象数组输出 |
二、允许重复的子接口:List
List接口本身属于Collection的子接口,但是List子接口本身大量的扩充了Collection接口,主要的扩充方法如下:
No. |
方法名称 |
类型 |
描述 |
1 |
public void add(int index,E element) |
普通 |
在指定的位置上增加内容 |
2 |
public E get(int index) |
普通 |
取得指定位置上的内容 |
3 |
public E set(int index,E element) |
普通 |
修改指定位置的内容 |
4 |
public ListIterator<E> listIterator() |
普通 |
为ListIterator接口实例化 |
5 |
public E remove(int index) |
普通 |
删除指定位置上的内容 |
既然要使用接口,那么就一定要依靠子类进行父接口的实例化。
1、新的子类:ArrayList
ArrayList子类是在进行List接口操作中使用最多的一个子类,那么此类定义如下:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
那么下面通过代码来观察基本的使用范例:设置内容
package list; import java.util.ArrayList; import java.util.List; public class ArrayListDemo01 { public static void main(String[] args) { List<String> all = new ArrayList<String>();// 实例化List接口 all.add("hello");// 向集合中增加内容 all.add("hello");// 向集合中增加内容 all.add("world");// 向集合中增加内容 all.add("!!!");// 向集合中增加内容 for (int x = 0; x < all.size(); x++) { System.out.println(all.get(x)) ; } } }
2、旧的子类:Vector
Vector子类实际上是最早的数据结构的实现类,也称为向量,但是在JDK 1.0的时候并没有所谓现在的类集框架的概念,那么只是单单的提供了一个这样的操作类而已,后来到了JDK 1.2之后提出了类集的框架,而且也提供了大量的类集的操作接口,所以为了保留此类的使用,在JDK 1.2之后让其多实现了一个List的接口,这样才被保留下来继续使用。
但是,不管是使用何种子类的,最终的代码的操作形式永远是一样的,因为所有的子类最终都必须发生向上转型的关系为父接口进行对象的实例化。
import java.util.List; import java.util.Vector; public class VectorDemo { public static void main(String[] args) { List<String> all = new Vector<String>();// 实例化List接口 all.add("hello");// 向集合中增加内容 all.add("world");// 向集合中增加内容 all.add("!!!");// 向集合中增加内容 for (int x = 0; x < all.size(); x++) { System.out.println(all.get(x)) ; } } }
3、ArrayList和Vector的区别
从代码的最终的操作形式上可以发现,代码的输出结果与之前是一样的,而且没有区别,但是两者的区别还在于其内部的组成上。
No. |
区别点 |
ArrayList |
Vector |
1 |
推出时间 |
JDK 1.2之后 |
JDK 1.0的时候推出 |
2 |
线程处理 |
ArrayList采用异步处理 |
采用同步处理 |
3 |
性能 |
速度较快 |
速度相对较慢 |
4 |
安全性 |
非线程安全性的操作 |
属于线程安全的操作 |
5 |
输出 |
由于都是List接口的子类,所以都可以依靠size()和get()两个方法完成循环输出 |
|
for、Iterator、ListIterator |
for、Iterator、ListIterator、Enumeration |
三、不允许重复的子接口:Set
List接口中的内容是允许重复的,但是如果现在要求集合中的内容不允许重复的话,则就可以使用Set子接口完成,Set接口并不像List接口那样对Collection接口进行了大量的扩充,而与Collection接口的定义是完全一样的。与List接口一样,如果要想使用Set接口则一定也要通过子类进行对象的实例化,常用的两个子类:HashSet、TreeSet。
3.1、散列存放的子类:HashSet
import java.util.HashSet; import java.util.Set; public class HashSetDemo { public static void main(String[] args) { Set <String> all = new HashSet<String>(); all.add("W"); all.add("W");//重复设置 all.add("B"); all.add("X"); all.add("C"); all.add("A"); all.add(null); System.out.println(all) ; } } //结果为 [null, W, A, B, C, X]
在Set接口中不允许有重复的元素出现,而且发现与List接口不同的是,List采用的是顺序的方式加入的元素,而Set中的内容并没有任何的顺序,属于散列存放的。
3.2、排序存放的子类:TreeSet
TreeSet操作的子类是使用顺序的方式保存里面的元素,
import java.util.Set; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { Set<String> all = new TreeSet<String>(); all.add("B"); all.add("B"); all.add("X"); all.add("C"); all.add("A"); //all.add(null); //不能添加null,否则运行会出现java.lang.NullPointerException异常 System.out.println(all); // 结果是[A, B, C, X] } }
此时,没有重复的内容,而且可以发现虽然加入的时候没有任何的顺序,但是输出的时候却是按照顺序的方式输出。
3.3、关于排序的说明
TreeSet子类的内容是允许进行排序的,那么下面就使用这个子类完成一个任意类型的排序操作。
如果多个对象要想进行排序,则无论在何种情况下都必须使用Comparable接口完成,用于指定排序的规则。但是在进行排序的时候实际上每一个类中的属性最好都进行判断。
package set; import java.util.Set; import java.util.TreeSet; 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 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); } } } public class SortDemo { public static void main(String[] args) { Set<Person> all = new TreeSet<Person>(); all.add(new Person("A", 18)); all.add(new Person("B", 20)); all.add(new Person("B", 20));//这个添加不进去 all.add(new Person("C", 20)); System.out.println(all); } } //[姓名:B,年龄:20, 姓名:C,年龄:20, 姓名:A,年龄:18]
3.4、关于重复元素的说明(TreeSet靠compareTo方法判断重复元素,而HashSet靠equals()和hashCode()来判断重复元素),
证明如下。
Comparable可以完成TreeSet类的重复元素的判断,如果真的可以通用的话,那么在HashSet中也一样可以。将上例中的TreeSet改成HashSet,代码如下所示,发现可以添加两个new Person("B", 20),Set接口不是不能添加重复元素吗?说明重复元素的判断并不想我们想象的那样。
package set; import java.util.HashSet; import java.util.Set; 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 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); } } } public class SortDemo { public static void main(String[] args) { Set<Person> all = new HashSet<Person>(); all.add(new Person("A", 18)); all.add(new Person("B", 20)); all.add(new Person("B", 20));//这个能添加进去,因为现在在HashSet中Comparable接口并不能使用。 //也就是说真正要去掉重复元素的操作并不是靠Comparable完成的 all.add(new Person("C", 20)); System.out.println(all); } } //[姓名:B,年龄:20, 姓名:A,年龄:18, 姓名:B,年龄:20, 姓名:C,年龄:20]
但是,从实际的结果来看,现在并没有完成此类内容,因为现在在HashSet中Comparable接口并不能使用。也就是说真正要去掉重复元素的操作并不是靠Comparable完成的,而是靠两个方法的作用,在Object类中定义:
No. |
方法名称 |
类型 |
描述 |
1 |
public boolean equals(Object obj) |
普通 |
判断是否相等 |
2 |
public int hashCode() |
普通 |
对象编码 |
hashCode()就相当于一个对象的唯一的编号,而如果要想进行具体的内容验证,就需要使用equals()方法完成。hashCode()方法返回的是一个数字,那么很明显,就必须通过一种算法,可以完成一个唯一的编号。hashCode是本地方法, public native int hashCode();和开发环境有关。如果现在使用的是eclipse进行开发的话,则此工具将会自动生成编号和比较。
package set; 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 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) { if (other.name !=null) return false; } else if (!name.equals(other.name)) return false; return true; } public String toString() { return"姓名:" +this.name +",年龄:" +this.age; } } public class RepeatDemo { public static void main(String[] args) { Set<Person> all = new HashSet<Person>(); all.add(new Person("张三", 20)); Person P1=new Person("李四", 20); Person P2=new Person("李四", 20); System.out.println(P1.equals(P2)); System.out.println(P1.hashCode()); System.out.println(P2.hashCode()); all.add(P1); all.add(P2); all.add(new Person("王五", 19)); System.out.println(all); } } /* true 843642 843642 [姓名:张三,年龄:20, 姓名:李四,年龄:20, 姓名:王五,年龄:19] 如果上面的代码中注释掉hashcode或者equals任何一个,则两次new Person("李四", 20)都不会被判别为重复元素,都能添加进HashSet中去 */
上面重写了hashCode和equals方法,两个李四年龄和姓名都相同,会被判别为重复元素,无法插入。如果上面的代码中注释掉hashcode或者equals任何一个,则两次new Person("李四", 20)都不会被判别为重复元素,都能添加进HashSet中去。hashcode也就是“哈希码”的作用就是为支持数据结构中的哈希表结构而存在的,换句话说,也就是只有用到集合框架的 Hashtable、HashMap、HashSet的时候,才需要重载hashCode()方法。否则hashCode就是本地方法,和开发环境有关。 public native int hashCode();
四、集合迭代输出:
4.1、Iterator
只要是碰见集合的输出问题,不要思考,直接使用Iterator输出。
Iterator本身是一个专门用于输出的操作接口,其接口定义了三种方法:
No. |
方法名称 |
类型 |
描述 |
1 |
public boolean hasNext() |
普通 |
判断是否有下一个元素 |
2 |
public E next() |
普通 |
取出当前元素 |
3 |
public void remove() |
普通 |
删除当前内容 |
在Collection接口中已经定义了iterator()方法,可以为Iterator接口进行实例化操作。
范例:集合输出的标准操作
import java.util.ArrayList; import java.util.Iterator; import java.util.List; publicclass IteratorDemo { publicstaticvoid main(String[] args) { List<String> all = new ArrayList<String>(); all.add("hello"); all.add("world"); Iterator<String> iter = all.iterator(); while (iter.hasNext()) {// 指针向下移动,判断是否有内容 String str = iter.next(); System.out.print(str +"、"); } } }
4.2、双向迭代输出:ListIterator
Iterator接口的主要的功能只能完成从前向后的输出,而如果现在要想完成双向(由前向后、由后向前)则可以通过ListIterator接口完成功能,此接口定义如下:
public interface ListIterator<E>
extends Iterator<E> |
ListIterator是Iterator的子接口,除了本身继承的方法外,此接口又有如下两个重要方法:
No. |
方法名称 |
类型 |
描述 |
1 |
public boolean hasPrevious() |
普通 |
判断是否有前一个元素 |
2 |
public E previous() |
普通 |
取出当前的元素 |
但是需要注意的是,如果要想进行由后向前的输出,必须先由前向后。但是在Collection接口中并没有为ListIterator接口实例化的操作,但是在List接口中存在此方法:public ListIterator<E> listIterator()
import java.util.ArrayList; import java.util.List; import java.util.ListIterator; public class ListIteratorDemo { public static void main(String[] args) { List<String> all = new ArrayList<String>(); all.add("hello"); all.add("world"); ListIterator<String> iter = all.listIterator();//必须先由前向后输出再由后向前输出 System.out.println("=========== 由前向后输出 ============"); while (iter.hasNext()) { System.out.print(iter.next() +"、"); } System.out.println("\n=========== 由后向前输出 ============"); while (iter.hasPrevious()) { System.out.print(iter.previous() +"、"); } } }
五、Map接口
Collection接口操作的时候每次都会向集合中增加一个元素,但是如果现在增加的元素是一对的话,则就可以使用Map接口完成功能,Map接口的定义如下:
public interface Map<K,V> |
在Map接口中有以下几个常用方法:
No. |
方法名称 |
类型 |
描述 |
1 |
public V put(K key,V value) |
普通 |
向集合中增加元素 |
2 |
public V get(Object key) |
普通 |
根据key取得value |
3 |
public Set<K> keySet() |
普通 |
取出所有的key |
4 |
public Collection<V> values() |
普通 |
取出所有的value |
5 |
public V remove(Object key) |
普通 |
删除一个指定的key |
6 |
public Set<Map.Entry<K,V>> entrySet() |
普通 |
将所有的集合变为Set集合 |
需要说明的是,在Map接口中还定义了一个内部接口—— Map.Entry。
public static interface Map.Entry<K,V> |
Entry是在Map接口中使用的static定义的内部接口,所以就是一个外部接口。
5.1、新的子类:HashMap
如果要使用Map接口的话,可以使用HashMap子类为接口进行实例化操作。
范例:验证增加和查询
import java.util.HashMap; import java.util.Map; public class HashMapDemo01 { public static void main(String[] args) { Map<String, String> all =new HashMap<String, String>(); all.put("BJ","BeiJing"); all.put("NJ","NanJing"); String value = all.get("BJ");// 根据key查询出value System.out.println(value); System.out.println(all.get("TJ")); } }
在Map的操作中,可以发现,是根据key找到其对应的value,如果找不到,则内容为null。
而且现在由于使用的是HashMap子类,所以里面的key允许一个为null。 all.put(null,"NULL");
现在所有的内容都有了,下面可以通过keySet()方法取出所有的key集合。Set<String> set = all.keySet();
5.2、Map集合的输出
按照最正统的做法,所有的Map集合的内容都要依靠Iterator输出,以上虽然是完成了输出,但是完成的不标准,Map集合本身并不能直接为Iterator实例化,如果此时非要使用Iterator输出Map集合中内容的话,则要采用如下的步骤
1、 将所有的Map集合通过entrySet()方法变成Set集合,里面的每一个元素都是Map.Entry的实例;
2、 利用Set接口中提供的iterator()方法为Iterator接口实例化;
3、 通过迭代,并且利用Map.Entry接口完成key与value的分离。
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class MapPrint { public static void main(String[] args) { Map<String, String> all =new HashMap<String, String>(); all.put("BJ","BeiJing"); all.put("NJ","NanJing"); all.put(null,"NULL"); Set<Map.Entry<String, String>> set = all.entrySet(); Iterator<Map.Entry<String, String>> iter = set.iterator(); while (iter.hasNext()) { Map.Entry<String, String> me = iter.next(); System.out.println(me.getKey() +" --> " + me.getValue()); } } }
5.3、有序的存放:TreeMap
HashMap子类中的key都属于无序存放的,如果现在希望有序(按key排序)则可以使用TreeMap类完成,但是需要注意的是,由于此类需要按照key进行排序,而且key本身也是对象,那么对象所在的类就必须实现Comparable接口。
import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class TreeMapDemo { public static void main(String[] args) { Map<String, String> all = new TreeMap<String, String>(); all.put("NJ", "NanJing"); all.put("BJ", "BeiJing"); Set<Map.Entry<String, String>> set = all.entrySet(); Iterator<Map.Entry<String, String>> iter = set.iterator(); while (iter.hasNext()) { Map.Entry<String, String> me = iter.next(); System.out.println(me.getKey() + " --> " + me.getValue()); } } } //BJ --> BeiJing NJ --> NanJing
5.4、旧的子类:Hashtable
Hashtable与Vector都是属于JDK 1.0的时候推出的操作类,在JDK 1.2之后让其实现了Map接口,那么不管使用何种子类,肯定最终还是依靠Map接口完成功能。
import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Set; public class HashtableDemo { public static void main(String[] args) { Map<String, String> all =new Hashtable<String, String>(); all.put("NJ","NanJing"); all.put("BJ","BeiJing"); Set<Map.Entry<String, String>> set = all.entrySet(); Iterator<Map.Entry<String, String>> iter = set.iterator(); while (iter.hasNext()) { Map.Entry<String, String> me = iter.next(); System.out.println(me.getKey() +" --> " + me.getValue()); } } } // BJ --> BeiJing // NJ --> NanJing
5.5、HashMap与Hashtable的区别
HashMap和Hastable在使用上相似,那么两者的区别如下:
No. |
区别点 |
HashMap |
Hashtable |
1 |
推出时间 |
JDK 1.2之后 |
JDK 1.0的时候推出 |
2 |
线程处理 |
采用异步处理 |
采用同步处理 |
3 |
性能 |
速度较快 |
速度相对较慢 |
4 |
安全性 |
非线程安全性的操作 |
属于线程安全的操作 |
5 |
保存null |
允许key设置成null |
不允许设置,否则出现NullPointerException |
5.6、关于key的说明
在HashMap中,中如果一个任意类的对象需要作为key保存的话,则对象所在的类必须实现Object类中的equals()和hashCode()两个方法。
1. HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key
2. Map的key和Set都有一个共同的特性就是集合的唯一性.TreeMap更是多了一个排序的功能.
Hashtable待研究
import java.util.HashMap; import java.util.Map; 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; } @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) { if (other.name !=null) return false; } else if (!name.equals(other.name)) return false; return true; } } public class MapKeyDemo { public static void main(String[] args) { Map<Person, String> all =new HashMap<Person, String>(); all.put(new Person("张三", 20), "ZS"); System.out.println(all.get(new Person("张三", 20))); } }
不过从一般的开发来看,使用String作为key的情况是最多的。
六、Stack类
Stack表示的是栈的操作类,栈是一种典型的先进后出的程序,此类的定义如下:
public class Stack<E> extends Vector<E> |
Stack是Vector类的子类,栈的主要操作方法:
·入栈:public E push(E item)
·出栈:public E pop()
范例:观察入栈和出栈的操作
import java.util.Stack; public class StackDemo { public static void main(String[] args) { Stack<String> s = new Stack<String>(); s.push("A"); s.push("B"); s.push("C"); System.out.println(s.pop()); System.out.println(s.pop()); System.out.println(s.pop()); System.out.println(s.pop());//EmptyStackException } }
七、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、设置、保存和读取属性
所有的属性的内容都是可以通过输出和输入流进行保存和读取的,下面先通过代码观察如何保存在普通的文件之中。
此时通过一个普通的文件流将所有的属性保存在了文件之中,而且一定要记住,所有的属性文件一定要使用“*.properties”作为后缀。
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"); } }
以上是将属性保存在了普通文件之中,也可以将其保存在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 version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>AREA INFO</comment> <entry key="BJ">BeiJing</entry> <entry key="NJ">NanJing</entry> </properties>
以后肯定也只能从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.2、列出属性
在实际的开发中,如果使用了IO流进行操作的话,有可能由于编码的不同而造成乱码的问题,因为程序的编码和本地环境的编码不统一,所以会造成乱码的显示,那么该如何查询本地编码呢,就需要通过Properties类的list()方法完成。
public class PropertiesDemo06 { public static void main(String[] args) throws Exception { System.getProperties().list(System.out); } }
7.3、工厂设计终极版
工厂设计经过发展已经有两种模型:
1、 简单工厂,所有的工厂类随着子类的增加而要修改
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("NJ")); a.getInfo(); } }
配置文件:area.properties
#AREA INFO #Sun Nov 04 16:33:49 CST 2012 BJ=BeiJing NJ=NanJing
现在的程序中可以发现,都是通过配置文件控制的,而且只要配置文件改变了,程序可以立刻发生改变。达到了配置文件与程序相分离的目的。
总结
1、 类集就是动态对象数组
2、 类集中的主要接口:Collection、List、Set、Map、Iterator、ListIterator、Enumeration
List 内容可以重复
ArrayList
Vector
Set 内容不可以重复
散列存放的子类:HashSet
排序存放的子类:TreeSet
1. HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key
2. Map的key和Set都有一个共同的特性就是集合的唯一性.TreeMap更是多了一个排序的功能.
Map键值对 键不能相同,相同的put会被覆盖,
HashMap HashMap子类中的key都属于无序存放的,子类key允许一个为null
TreeMap有序的存放,根据Comparable借口的compareTo方法的比较
Hashtable key不允许为null,同步的。jdk1.0推出的。
3、 类集的主要目的就是为了保存数据和输出数据
4、 所有的属性都依靠Iterator完成
5、 就是各个子类的不同
6、 map的标准输出
7、 Stack表示的是栈的操作类,栈是一种典型的先进后出的程