ArrayList 和 和 Vector 的区别
从代码的最终的操作形式上可以发现,代码的输出结果与之前是一样的,而且没有区别,但是两者的区别还在于其
内部的组成上。No. | 区别点 | Vector | Vector |
1 | 推出时间 | DK 1.2 之后 | JDK 1.0 的时候推出 |
2 | 线程处理 | ArrayList 采用异步处理 | 采用同步处理 |
3 | 性能 | 速度较快 | 速度较慢 |
4 | 安全性 | 非线程安全性的操作 | 线程安全性的操作 |
5 | 输出 | 由于都是 List 接口的子类,所以都可以依靠 size()和 get()两个方法完成循环输出 | |
6 | for、Iterator、ListIterator | for、Iterator、ListIterator、Enumeration |
不允许重复的子接口:Set
List 接口中的内容是允许重复的,但是如果现在要求集合中的内容不允许重复的话,则就可以使用 Set 子接口完成,
Set 接口并不像 List 接口那样对 Collection 接口进行了大量的扩充,而与 Collection 接口的定义是完全一样的。与 List 接口一样,如果要想使用 Set 接口则一定也要通过子类进行对象的实例化,常用的两个子类:HashSet、TreeSet。3.3.1、散列存放 的 子 类:HashSet
HashSet 本身是 Set 的子类,此类的定义如下:public class HashSetextends AbstractSet implements Set , Cloneable, Serializable
与 ArrayList 类的定义结构是非常类似的,也是继承了一个抽象类,而且实现了接口。
在 Set 接口中不允许有重复的元素出现,而且发现与 List 接口不同的是,List 采用的是顺序的方式加入的元素,而 Set
中的内容并没有任何的顺序,属于散列存放的3.3.2、 、 排序存放 的 子 类:TreeSet
TreeSet 操作的子类是使用顺序的方式保存里面的元素,下面通过代码观察:
package org.lxh.setdemo;import java.util.Set;import java.util.TreeSet;public class TreeSetDemo {public static void main(String[] args) {Setall = new TreeSet ();all.add("B");all.add("B");all.add("X");all.add("C");all.add("A");System.out.println(all);}}
此时,没有重复的内容,而且可以发现虽然加入的时候没有任何的顺序,但是输出的时候却是按照顺序的方式输出
3.3.3 、关于 排序 的 说明
TreeSet 子类的内容是允许进行排序的,那么下面就使用这个子类完成一个任意类型的排序操作。如果多个对象要想进行排序,则无论在何种情况下都必须使用 Comparable 接口完成,用于指定排序的规则。但是在进行排序的时候实际上每一个类中的属性最好都进行判断。package org.lxh.setdemo.sort;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;}public String toString() { return "姓名:" + this.name + ",年龄:" + this.age;}@Overridepublic 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 all = new TreeSet (); all.add(new Person("张三", 20)); all.add(new Person("李四", 20)); all.add(new Person("李四", 20)); all.add(new Person("王五", 19)); System.out.println(all); }}
此时加入了验证之后,可以发现,如果加入的对象重复的话,是不会正常加入的,可以去掉重复的内容。
3.3.4 、关于 重 复 元素 的 说明
Comparable 可以完成 TreeSet 类的重复元素的判断,如果真的可以通用的话,那么在 HashSet 中也一样可以。但是,从实际的结果来看,现在并没有完成此类内容,因为现在在 HashSet 中 Comparable 接口并不能使用。也就是说真正要去掉重复元素的操作并不是靠 Comparable 完成的,而是靠两个方法的作用,在 Object 类中定义:No. 方法名称 类型 型 描述1 public boolean equals(Object obj) 普通 判断是否相等2 public int hashCode() 普通 对象编码hashCode()就相当于一个对象的唯一的编号,而如果要想进行具体的内容验证,就需要使用 equals()方法完成。hashCode()方法返回的是一个数字,那么很明显,就必须通过一种算法,可以完成一个唯一的编号。如果现在使用的是 eclipse 进行开发的话,则此工具将会自动生成编号和比较。1 package org.lxh.setdemo.repeat; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 class Person{ 6 private String name; 7 private int age; 8 public Person(String name, int age) { 9 this.name = name;10 this.age = age;11 }12 @Override13 public int hashCode() {14 final int prime = 31;15 int result = 1;16 result = prime * result + age;17 result = prime * result + ((name == null) ? 0 : name.hashCode());18 return result;19 }20 @Override21 public boolean equals(Object obj) {22 if (this == obj)23 return true;24 if (obj == null)25 return false;26 if (getClass() != obj.getClass())27 return false;28 Person other = (Person) obj;29 if (age != other.age)30 return false;31 if (name == null) {32 if (other.name != null)33 return false;34 } else if (!name.equals(other.name))35 return false;36 return true;37 }38 public String toString() {39 return "姓名:" + this.name + ",年龄:" + this.age;40 }41 }42 public class RepeatDemo {43 public static void main(String[] args) {44 Setall = new HashSet ();45 all.add(new Person("张三", 20));46 all.add(new Person("李四", 20));47 48 all.add(new Person("李四", 20));49 all.add(new Person("王五", 19));50 System.out.println(all);51 }52 }
3.4、集合输出( 、集合输出( 重点) )
在正常情况中,只要是集合的输出基本上都不会采用将其变为对象数组的方式,而是采用以下的四种形式完成的:- Iterator(95%)
- ListIterator(1%)
- Enumeration(4%)
- foreach(0%)
3.4.1、 迭 代 输出: :Iterator( ( 核 心 重 点) )
只要是 碰见 集 合 的 输出问题 ,不要 思考 , 直接使用 用 Iterator 输出。Iterator 本身是一个专门用于输出的操作接口,其接口定义了三种方法:No. 方法名称 类型 型 描述- public boolean hasNext() 普通 通 判断 是 否 有 下 一个 元素
- public E next() 普通 通 取出当前元素
- public void remove() 普通 删除当前内容
在 Collection 接口中已经定义了 iterator()方法,可以为 Iterator 接口进行实例化操作。
范例: :集合输出的标准操作1 package org.lxh.printdemo; 2 import java.util.ArrayList; 3 import java.util.Iterator; 4 import java.util.List; 5 public class IteratorDemo { 6 public static void main(String[] args) { 7 Listall = new ArrayList (); 8 all.add("hello"); 9 all.add("world");10 Iterator iter = all.iterator();11 while (iter.hasNext()) { // 指针向下移动,判断是否有内容12 String str = iter.next();13 System.out.print(str + "、");14 }15 }16 }
以上的代码为集合输出的标准格式。
3.4.2 双向迭 代 输出:ListIteratorIterator 接口的主要的功能只能完成从前向后的输出,而如果现在要想完成双向(由前向后、由后向前)则可以通过ListIterator 接口完成功能,此接口定义如下:public interface ListIteratorextends Iterator
ListIterator 是 Iterator 的子接口,除了本身继承的方法外,此接口又有如下两个重要方法:
- public boolean hasPrevious() 判断是否有前一个元素
- public E previous() 取出当前的元素
但是需要注意的是,如果要想进行由后向前的输出,必须先由前向后。但是在 Collection 接口中并没有为 ListIterator
接口实例化的操作,但是在 List 接口中存在此方法:public ListIterator<E> listIterator()1 package org.lxh.printdemo; 2 import java.util.ArrayList; 3 import java.util.List; 4 import java.util.ListIterator; 5 public class ListIteratorDemo { 6 public static void main(String[] args) { 7 Listall = new ArrayList (); 8 all.add("hello"); 9 all.add("world");10 ListIterator iter = all.listIterator();11 System.out.println("=========== 由前向后输出 ============");12 while (iter.hasNext()) {13 System.out.print(iter.next() + "、");14 }15 System.out.println("\n=========== 由后向前输出 ============");16 while (iter.hasPrevious()) {17 System.out.print(iter.previous() + "、");18 }19 }20 }
3.4.3 几乎废弃 的 接口:Enumeration
Enumeration 接口算是最早完成这种迭代输出的操作接口了,但是 Enumeration 接口发展到今天几乎已经不再使用了,只在一些很少的关键部分上依然会看见此方法的应用,在此接口中定义了两个方法:- public boolean hasMoreElements() 判断是否有下一个元素
- public E nextElement() 取出当前元素
从方法名称上可以发现,要比 Iterator 接口中的方法难记很多,所以这个接口几乎废弃了。
而且 Collection 接口本身并不支持这种输出,而只有与之同时期出现的 Vector 支持此种输出方式。在 Vector 类中定义了一个方法:public Enumeration<E> elements()范例: :使用 Enumeration 输出3.4.4、 、 新 的 支持: :foreach在 JDK 1.5 之后增加的 foreach 输出本身也可以用于集合的输出上,但是从一般的开发角度来看,使用此种输出方式的人员并不多。package org.lxh.printdemo;import java.util.ArrayList;import java.util.List;public class ForEachDemo { public static void main(String[] args) { List<String> all = new ArrayList<String>();all.add("hello");all.add("world");for (String str : all) { System.out.println(str);}}}3.5 、Map 接口Collection 接口操作的时候每次都会向集合中增加一个元素,但是如果现在增加的元素是一对的话,则就可以使用Map 接口完成功能,Map 接口的定义如下:public interface Map<K,V>里面需要同时指定两个泛型,主要的原因,Map 中的所有保存数据都是按照“key à value”的形式存放的,例如:以电话号码本为例:· 张三:123456· 李四:234567· 王五:345678以上的数据每次保存的时候都是按照一对的形式存放的,如果现在要找到张三的电话,很明显张三是一个 key,而他的电话就是一个 value。在 Map 接口中有以下几个常用方法:No. 方法名称 类型 型 描述1 public V put(K key,V value) 普通 通 向 集 合 中 增加元素2 public V get(Object key) 普通 通 据 根据 key 取得 value3 public Set<K> keySet() 普通 取出所有的 key4 public Collection<V> values() 普通 取出所有的 value5 public V remove(Object key) 普通 删除一个指定的 key6 public Set<Map.Entry<K,V>> entrySet() 普通 通 将所 有的集 合变为 为 Set 集 集合 合需要说明的是,在 Map 接口中还定义了一个内部接口 —— Map.Entry。public static interface Map.Entry<K,V>Entry是在 Map 接口中使用的 static 定义的内部接口,所以就是一个外部接口。3.5.1、 、 新 的 子 类:HashMap如果要使用 Map 接口的话,可以使用 HashMap 子类为接口进行实例化操作。范例: :验证增加和查询package org.lxh.mapdemo;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查询出valueSystem.out.println(value);System.out.println(all.get("TJ"));}}在 Map 的操作中,可以发现,是根据 key找到其对应的 value,如果找不到,则内容为 null。而且 现在由 于 使是 用的是 HashMap 子 子 类, 所 以 里面的 的 key 允许为 一个为 null 。package org.lxh.mapdemo;import java.util.HashMap;import java.util.Map;public class HashMapDemo02 { 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");System.out.println(all.get(null));}}现在所有的内容都有了,下面可以通过 keySet()方法取出所有的 key集合。package org.lxh.mapdemo;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Set;public class HashMapDemo03 { 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<String> set = all.keySet();Iterator<String> iter = set.iterator();while (iter.hasNext()) { String key = iter.next() ;System.out.println(key + " --> " + all.get(key)) ;}}}3.5.2 、Map 集 集 合 的 输出按照最正统的做法,所有的 Map 集合的内容都要依靠 Iterator 输出,以上虽然是完成了输出,但是完成的不标准,Map 集合本身并不能直接为 Iterator 实例化,如果此时非要使用 Iterator 输出 Map 集合中内容的话,则要采用如下的步骤:1、 将所有的 Map 集合通过 entrySet()方法变成 Set 集合,里面的每一个元素都是 Map.Entry的实例;2、 利用 Set 接口中提供的 iterator()方法为 Iterator 接口实例化;3、 通过迭代,并且利用 Map.Entry接口完成 key与 value 的分离。package org.lxh.mapdemo;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());}}}以上的输出操作是 Map 接口输出的标准语句形式,以后包括各种框架的学习的输出原理与之是一样的。3.5.3 、有 序 的 存放: :TreeMapHashMap 子类中的 key 都属于无序存放的,如果现在希望有序(按 key 排序)则可以使用 TreeMap 类完成,但是需要注意的是,由于此类需要按照 key进行排序,而且 key本身也是对象,那么对象所在的类就必须实现 Comparable 接口。package org.lxh.mapdemo;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("BJ", "BeiJing");all.put("NJ", "NanJing");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());}}}3.5.4、 、 旧 的 子 类:HashtableHashtable 与 Vector 都是属于 JDK 1.0 的时候推出的操作类,在 JDK 1.2 之后让其实现了 Map 接口,那么不管使用何种子类,肯定最终还是依靠 Map 接口完成功能。package org.lxh.mapdemo;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("BJ", "BeiJing");all.put("NJ", "NanJing");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());}}}3.5.5 、HashMap 与 与 Hashtable 的 的 区别HashMap 和 Hastable 在使用上相似,那么两者的区别如下:No. 区别点 点 HashMap Hashtable1 推出时间 JDK 1.2 之后 JDK 1.0 的时候推出2 线程处理 采用异步处理 采用同步处理3 性能 速度较快 速度相对较慢4 安全性 非线程安全性的操作 属于线程安全的操作5 保存 null 允许 key设置成 null 不允许设置,否则出现 NullPointerException3.5.6 、关于 key 的 的 说明在Map中如果一个任意类的对象需要作为key保存的话,则对象所在的类必须实现Object类中的equals()和hashCode()两个方法。package org.lxh.mapdemo;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;}@Overridepublic int hashCode() { final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic 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的情况是最多的。3.6 、Stack 类(理解)Stack 表示的是栈的操作类,栈是一种典型的先进后出的程序,此类的定义如下:public class Stack<E> extends Vector<E>Stack 是 Vector 类的子类,栈的主要操作方法:· 入栈:public E push(E item)· 出栈:public E pop()范例: :观察入栈和出栈的操作package org.lxh.otherdemo;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());}}3.7 、Properties 类( 类( 核心重点) )Properties 类的主要功能是用于操作属性,在各个语言(包括操作系统)都会存在着许多的配置文件。所有的属性文件中的属性都是按照“key=value”的形式保存的,而且保存的内容都是 String(字符串),此类定义如下:public class Properties extends Hashtable<Object,Object>此类是 Hashtable 的子类,而且已经默认指定好了泛型是 Object,但是所有的属性操作中的类型肯定都是字符串,那么操作的时候主要使用的是 Properties 类完成。Properties 类中定义的主要操作方法:No. 方法名称 类型 型 描述1 public Object setProperty(String key,String value) 普通 设置属性2 public String getProperty(String key) 普通根据属性的名字取得属性的内容,如果没有返回null 结果3public String getProperty(String key,StringdefaultValue)普通根据属性的名字取得属性内容,如果没有则返回默认值(defaultValue)4 public void list(PrintStream out) 普通 从一个输出流中显示所有的属性内容5public void store(OutputStream out,String comments)throws IOException普通 向输出流中输出属性6public void load(InputStream inStream) throwsIOException普通 从输入流中读取属性内容7public void storeToXML(OutputStream os,Stringcomment) throws IOException普通 以 XML 文件格式输出属性内容8public void loadFromXML(InputStream in) throwsIOException,InvalidPropertiesFormatException普通 以 XML 文件格式输入属性内容3.7.1 、设 置和取得属性package org.lxh.otherdemo;import java.util.Properties;public class PropertiesDemo01 { public static void main(String[] args) { Properties pro = new Properties();pro.setProperty("BJ", "BeiJing");pro.setProperty("NJ", "NanJing");System.out.println(pro.getProperty("BJ"));System.out.println(pro.getProperty("TJ"));System.out.println(pro.getProperty("TJ", "没有此地区"));}}3.7.2、 、 保存和读取属性所有的属性的内容都是可以通过输出和输入流进行保存和读取的,下面先通过代码观察如何保存在普通的文件之中。package org.lxh.otherdemo;import java.io.File;import java.io.FileOutputStream;import java.util.Properties;public class PropertiesDemo02 { public static void main(String[] args) throws Exception { Properties pro = new Properties();pro.setProperty("BJ", "BeiJing");pro.setProperty("NJ", "NanJing");pro.store(new FileOutputStream(new File("D:" + File.separator+ "area.properties")), "AREA INFO");}}此时通过一个普通的文件流将所有的属性保存在了文件之中,而且一定要记住,所有的属性文件一定要使用“*.properties”作为后缀。package org.lxh.otherdemo;import java.io.File;import java.io.FileInputStream;import java.util.Properties;public class PropertiesDemo03 { public static void main(String[] args) throws Exception { Properties pro = new Properties();pro.load(new FileInputStream(new File("D:" + File.separator+ "area.properties")));System.out.println(pro.getProperty("BJ"));System.out.println(pro.getProperty("TJ"));System.out.println(pro.getProperty("TJ", "没有此地区"));}}以上是将属性保存在了普通文件之中,也可以将其保存在 XML 文件之中,代码如下:package org.lxh.otherdemo;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 文件格式中读取属性了。package org.lxh.otherdemo;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", "没有此地区"));}}3.7.3、 、 列出属性在实际的开发中,如果使用了 IO 流进行操作的话,有可能由于编码的不同而造成乱码的问题,因为程序的编码和本地环境的编码不统一,所以会造成乱码的显示,那么该如何查询本地编码呢,就需要通过 Properties 类的 list()方法完成。package org.lxh.otherdemo;public class PropertiesDemo06 { public static void main(String[] args) throws Exception { System.getProperties().list(System.out) ;}}关于文件的编码,在程序中主要有以下几种:· GB2312、GBK:表示的是国标编码,2312 表示的是简体中文,而 GBK 包含了简体和繁体中文· ISO 8859-1:主要用于英文字母的编码方式· UNICODE:Java 中使用十六进制进行编码,能够表示出世界上所有的编码· UTF 编码:中文采用十六进制,而普通的字母依然采用和 ISO 8859-1 一样的编码在以后的程序中经常会出现乱码的问题,这种问题造成的根本原因就是在于编码不统一。package org.lxh.otherdemo;import java.io.File;import java.io.FileOutputStream;import java.io.OutputStream;public class EncodingDemo { public static void main(String[] args) throws Exception { OutputStream output = new FileOutputStream(new File("D:"+ File.separator + "hello.txt"));String info = "你好啊,中国!" ;output.write(info.getBytes("ISO8859-1")) ;output.close() ;}}3.7.4、 、 工厂 设计 终极版 ( 理解) )工厂设计经过发展已经有两种模型:1、 简单工厂,所有的工厂类随着子类的增加而要修改2、 反射工厂,只要传递进去完整的包.类,就可以完成实例化操作但是,第 2 种实现本身也有问题,因为每次都要传递一个完整的“包.类”实在是太麻烦了。package org.lxh.factorydemo;import java.io.File;import java.io.FileInputStream;import java.util.Properties;interface Area { public void getInfo();}class BeiJing implements Area { public void getInfo() { System.out.println("你在北京,欢迎您!");}}class NanJing implements Area { public void getInfo() { System.out.println("你在南京,欢迎您!");}}class Factory { public static Area getInstance(String className) { Area a = null;try { a = (Area) Class.forName(className).newInstance();} catch (Exception e) { }return a;}}public class FactoryDemo { public static void main(String[] args) throws Exception { Properties pro = new Properties();pro.load(new FileInputStream(new File("D:" + File.separator+ "area.properties")));Area a = Factory.getInstance(pro.getProperty("area"));a.getInfo();}}配置文 件:area.properties#AREA INFO#Mon Dec 28 14:55:28 CST 2009area=org.lxh.factorydemo.NanJing现在的程序中可以发现,都是通过配置文件控制的,而且只要配置文件改变了,程序可以立刻发生改变。达到了配置文件与程序相分离的目的。3.8、两种问题( 、两种问题( 重点) )3.8.1 、一 对多 多一个人有多本书,要求通过程序描述。package org.lxh.demo01;import java.util.ArrayList;import java.util.List;public class Person { private String name;private int age;private List<Book> books;public Person() { super();this.books = new ArrayList<Book>();}public Person(String name, int age) { this();this.name = name;this.age = age;}public List<Book> getBooks() { return this.books;}@Overridepublic String toString() { return "姓名:" + this.name + ",年龄:" + this.age;}}因为现在根本就无法明确的知道一个人有多少本书。package org.lxh.demo01;public class Book { private String title;private Person person;public Book(String title) { this.title = title;}public Person getPerson() { return person;}public void setPerson(Person person) { this.person = person;}@Overridepublic String toString() { return "书名:" + this.title;}}在主方法中设置两者的关系。package org.lxh.demo01;import java.util.Iterator;public class Test { public static void main(String[] args) { Person per = new Person("张三", 20);Book b1 = new Book("Java");Book b2 = new Book("WEB");per.getBooks().add(b1);per.getBooks().add(b2);b1.setPerson(per);b2.setPerson(per);System.out.println(per);Iterator<Book> iter = per.getBooks().iterator();while (iter.hasNext()) { System.out.println("\t|- " + iter.next()) ;}}}3.8.2 、多 对多 多一个学生可以参加多门课程,一门课程有多个学生参加,现在要求通过一个学生可以找到他所参加的全部课程,也可以通过一门课程找到参加本课程的所有学生。package org.lxh.demo02;import java.util.List;public class Course { private List<Student> students ;}package org.lxh.demo02;import java.util.List;public class Student { private List<Course> courses ;}类集,当不知道有多少个元素的时候就使用类集。3.9 、集合的工具类:Collections (了解)从定义格式上看与 Collection 非常的类似,但是两者并没有任何的关系,此类定义如下:public class Collections extends Object是一个 Object 类的子类,并没有跟 Collection 有任何关系。package org.lxh.demo;import java.util.ArrayList;import java.util.Collections;import java.util.List;public class CollectionsDemo { public static void main(String[] args) { List<String> all = new ArrayList<String>();Collections.addAll(all, "A", "B", "C");System.out.println(all);}}4、 、 总结1、 类集就是动态对象数组2、 类集中的主要接口:Collection、List、Set、Map、Iterator、ListIterator、Enumeration3、 类集的主要目的就是为了保存数据和输出数据4、 所有的属性都依靠 Iterator 完成5、 就是各个子类的不同