JAVA中的集合类是一种工具类,就像是容器,储存任意数量的具有共同属性的对象。
集合的作用:
如果一个类的内部有很多相同类型的属性,并且他们的作用与意义是一样的,比如说学生能选课学生类就有很多课程类型的属性,或者工厂类有很多机器类型的属性,我们用一个类似于容器的集合去盛装他们,这样在类的内部就变的井然有序---------这就是:
*在类的内部,对数据进行组织的作用。
*简单而快速的搜索查找其中的某一条元素
*有的集合接口,提供了一系列排列有序的元素,并且可以在序列中间快速的插入或者删除有关元素。
*有的集合接口在其内部提供了映射关系的结构,可以通过关键字(key)去快速查找对应的唯一对象,而这个关键可以是任意类型的。
集合其实就时用来盛装其他对象的容器,我们之前学过数组,从这点功能来讲,他们的功能似乎差不多,我们为什么要使用集合?
集合与数组的对比:
*数组的长度固定,集合长度可变。
*数组只能通过下标访问元素,类型固定,而有的集合可以通过任意类型关键字去查找所映射的具体对象。
JAVA集合框架体系结构:
Collection接口,子接口以及实现类:
Collection接口是List,Set和Queue接口的父接口
定义了可用于操作List,Set和Queue的方法
增、删、改、查。
(1) List接口及其实现类 ---ArrayList
List是元素有序并且可以重复的集合,被称为序列
List可以精确的控制每个元素的插入位置,或删除某个位置的元素
ArrayList ---数组序列,是List的一个重要实现,ArrayList底层是由数组实现的。
案例:
实现功能---模拟学生选课功能
*选择课程(向集合中添加课程)
*删除所选的某门课程(删除集合中的元素)
*查看所选课程
*修改所选课程
1 package com.lx; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 //学生类 7 public class Student { 8 private String name; 9 private String id;10 private Setcourses;11 12 public Student(String name, String id) {13 this.courses = new HashSet ();14 this.name = name;15 this.id = id;16 }17 18 public Set getCourses() {19 return courses;20 }21 22 public void setCourses(Set courses) {23 this.courses = courses;24 }25 26 public String getName() {27 return name;28 }29 30 public void setName(String name) {31 this.name = name;32 }33 34 public String getId() {35 return id;36 }37 38 public void setId(String id) {39 this.id = id;40 }41 }
1 package com.lx; 2 3 //课程类 4 public class Course { 5 private String id; 6 private String name; 7 8 public Course(String newId, String newName) { 9 // TODO Auto-generated constructor stub10 this.id = newId;11 this.name = newName;12 }13 14 public String getId() {15 return id;16 }17 18 public void setId(String id) {19 this.id = id;20 }21 22 public String getName() {23 return name;24 }25 26 public void setName(String name) {27 this.name = name;28 }29 }
1 package com.lx; 2 3 import java.util.ArrayList; 4 import java.util.Arrays; 5 import java.util.Iterator; 6 import java.util.List; 7 8 //备选课程类 9 public class ListTest { 10 // 存放备选课程的容器 11 public ListcoursesToSelect; 12 13 public ListTest() { 14 // TODO Auto-generated constructor stub 15 this.coursesToSelect = new ArrayList (); 16 } 17 18 public static void main(String[] args) { 19 ListTest l1 = new ListTest(); 20 l1.testAdd(); 21 Course cr1 = l1.coursesToSelect.get(0); 22 if (l1.coursesToSelect.contains(cr1)) { 23 System.out.println("课程" + cr1.getName() + "的索引位置" + l1.coursesToSelect.indexOf(cr1)); 24 } 25 } 26 27 // 用于向coursesToSelect中添加备选课程 28 public void testAdd() { 29 Course cr1 = new Course("1", "数据结构"); 30 /** 31 * 添加方法① 创建一个课程对象,并通过调用add方法 添加到备选课程List中 32 */ 33 coursesToSelect.add(cr1); 34 35 /** 36 * 添加方法② 向集合指定位置添加课程对象 37 */ 38 Course cr2 = new Course("2", "C语言"); 39 coursesToSelect.add(0, cr2); 40 41 /** 42 * 添加方法③ 使用数组一次性添加多个课程对象 43 */ 44 Course[] course = { new Course("3", "离散数学"), new Course("4", "汇编语言") }; 45 coursesToSelect.addAll(Arrays.asList(course)); 46 47 /** 48 * 添加方法④ 使用数组一次性添加多个课程对象到指定集合位置 49 */ 50 Course[] course2 = { new Course("5", "高等数学"), new Course("6", "大学英语") }; 51 coursesToSelect.addAll(2, Arrays.asList(course2)); 52 } 53 54 /** 55 * 使用get(i)方法 取出List中的元素 56 */ 57 public void testGet() { 58 // size()返回列表中的元素数 59 int size = coursesToSelect.size(); 60 System.out.println("有如下课程待选:"); 61 for (int i = 0; i < size; i++) { 62 Course cr = coursesToSelect.get(i); 63 System.out.println("课程:" + cr.getId() + cr.getName()); 64 } 65 } 66 67 /** 68 * 使用迭代器来遍历List 69 */ 70 71 public void testIterator() { 72 Iterator it = coursesToSelect.iterator(); 73 System.out.println("有如下课程待选:"); 74 while (it.hasNext()) { 75 Course cr = it.next(); 76 System.out.println("课程:" + cr.getId() + cr.getName()); 77 } 78 } 79 80 /** 81 * 使用foreach方法访问集合元素: 82 */ 83 public void testForeach() { 84 for (Course cr : coursesToSelect) { 85 System.out.println("课程:" + cr.getId() + cr.getName()); 86 } 87 } 88 89 /** 90 * 修改List中的元素,实现学生选课中的课程修改 set() 用来指定元素替换列表中指定元素的位置 91 */ 92 93 public void testModify() { 94 coursesToSelect.set(4, new Course("7", "毛概")); 95 } 96 97 /** 98 * 删除List中的元素,实现学生选课中的课程删除 在remove()方法里可以写一个集合中对象的位置,也可以写一个集合中对象的引用, 99 * 更可以传入一个数组的引用来删除多个集合中存放的对象100 */101 public void testRemove() {102 Course cr = coursesToSelect.get(1);103 coursesToSelect.remove(cr);104 coursesToSelect.remove(1);105 106 Course[] course = { coursesToSelect.get(2), coursesToSelect.get(3) };107 // 同时删除位置4和位置5上的元素108 coursesToSelect.removeAll(Arrays.asList(course));109 }110 111 }
(2) 泛型
集合的元素,可以是任意类型对象的引用,如果把某个对象放入集合,则会忽略它的类型,就会把它当做Object类型处理
泛型则是规定了某个集合只可以存放特定类型的对象的引用,会在编译期间进行类型检查,可以直接指定类型来获取集合元素
1 package com.lx; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 //测试泛型 7 public class TestGeneric { 8 // 带有泛型 Course的 List类型的属性 9 public Listcourse;10 11 public TestGeneric() {12 // TODO Auto-generated constructor stub13 this.course = new ArrayList ();14 }15 16 public void testAdd() {17 // 测试添加18 Course cr1 = new Course("1", "大学语文");19 course.add(cr1);20 /**21 * 泛型集合中不能添加泛型固定的类型以外的对象,否则会报错22 */23 }24 25 }
在泛型集合和中出了能够存入泛型类型的对象实例还可以存入泛型的子类型的对象实例
注意:
1 泛型集合中的限定类型,不能使用基本数据类型
2 可以通过使用包装类限定允许存放基本数据类型
(3) 通过Set集合管理课程
Set接口及其实现类----HashSet
Set的元素是无序并且不可以重复的集合,被称为集
HashSet哈希集,是Set的一个重要实现类
案例功能说明:
*提供备选课程
*创建学生对象,并给该学生添加三门可能(添加在学生的Courses---Set类型的属性中)
*显示备选课程
*循环三次,每次输入课程ID
*向学生的Course属性中添加与输入的ID匹配课程
*输出学生选择的课程
1 package com.lx; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 //学生类 7 public class Student { 8 private String name; 9 private String id;10 private Setcourses;11 12 public Student(String name, String id) {13 this.courses = new HashSet ();14 this.name = name;15 this.id = id;16 }17 18 public Set getCourses() {19 return courses;20 }21 22 public void setCourses(Set courses) {23 this.courses = courses;24 }25 26 public String getName() {27 return name;28 }29 30 public void setName(String name) {31 this.name = name;32 }33 34 public String getId() {35 return id;36 }37 38 public void setId(String id) {39 this.id = id;40 }41 }
1 package com.lx; 2 3 // 课程类 4 public class Course { 5 private String id; 6 private String name; 7 8 public Course(String newId, String newName) { 9 // TODO Auto-generated constructor stub10 this.id = newId;11 this.name = newName;12 }13 14 public String getId() {15 return id;16 }17 18 public void setId(String id) {19 this.id = id;20 }21 22 public String getName() {23 return name;24 }25 26 public void setName(String name) {27 this.name = name;28 }29 }
循环遍历Set中的每个元素只能用forecach方法和Iterator方法,而不能像List一样调用get方法,这是因为Set本身是无序的,所以不可能去查询指定的索引位置上的某个元素,只能使用foreach循环和iterator来循环来一个个的迭代出来,而这个迭代出来的显示结果,他是无序的,所以每次执行他的迭代,结果顺序都不太一样
Map和HashMap
和Collection存储单个元素不同,Map接口提供了一种映射关系,Map中的元素都是以键值对(key---value)的形式存储的,能够实现根据key快速查找value这个key和value可以是任意类型对象
Map中的键值对以Entry类型的对象实例形式存在,Entry类型的对象实例它包括key和value
在Map中(key值)不可重复,value可以重复,一个value值可以和很多key值形成对应关系,每个键(key)值最多只能映射一个value值
Map支持泛型,形式如:Map<key类型,value类型>
常用方法:
添加 put(k,y)
删除:remove(key)....
HashMap类:
HashMap是Map的一个重要实现类,也是最常用的基于哈希表的实现。
HashMap中的Entry对象是无序排列的
key和value值都可以为NULL,但是一个HashMap只有个key值为null的映射(key值不可重复)
案例:
*学生选课--使用Map添加学生
*通过Map<String,Student>进项学生信息管理,其中key为学生ID,value为学生对象。
通过键盘输入学生信息,对集合中的学生信息进行增删改查操作:
Map增删改查:
增:map的put(key,value)方法添加。
查:1.利用keyset()方法获得Map中key的集合,再遍历key的集合,利用Map的get(key)方法得到key对应的value值。
2.利用EntrySet方法获取May中Entry键值对:然后用foreach键值对,再用Entry的getkey()和getvalue()方法得到每一个key值和value值。
删:remove(object key)
改:put(原有的key,新的value)
通过entrySet可以返回Map中的所有键值对 Set<Entry<String,Student>>entrySet = students.entrySet();
思考:
* 在课程序列中,如何判断是否包含某门或者某几门课程?
*如果课程序列包含某门课程,如何判断该课程的索引位置?
*在学生映射表 中,如何判断是否包含某个学生id,又该如何判断是否包含某个学生对象?
*如果想把课程或者学生对象按照课程名称或者学生排序与该怎么办,按照id排序呢?
1在课程序列中,如何判断是否包含某门或者某几门课程?
测试List的contains方法
1 //备选课程类 2 public class ListTest { 3 // 存放备选课程的容器 4 public ListcoursesToSelect; 5 6 public ListTest() { 7 // TODO Auto-generated constructor stub 8 this.coursesToSelect = new ArrayList (); 9 }10 11 public static void main(String[] args) {12 ListTest l1 = new ListTest();13 l1.testAdd();14 l1.testListContains();15 }16 17 // 用于向coursesToSelect中添加备选课程18 public void testAdd() {19 Course cr1 = new Course("1", "数据结构");20 /**21 * 添加方法① 创建一个课程对象,并通过调用add方法 添加到备选课程List中22 */23 coursesToSelect.add(cr1);24 25 /**26 * 添加方法② 向集合指定位置添加课程对象27 */28 Course cr2 = new Course("2", "C语言");29 coursesToSelect.add(0, cr2);30 31 /**32 * 添加方法③ 使用数组一次性添加多个课程对象33 */34 Course[] course = { new Course("3", "离散数学"), new Course("4", "汇编语言") };35 coursesToSelect.addAll(Arrays.asList(course));36 37 /**38 * 添加方法④ 使用数组一次性添加多个课程对象到指定集合位置39 */40 Course[] course2 = { new Course("5", "高等数学"), new Course("6", "大学英语") };41 coursesToSelect.addAll(2, Arrays.asList(course2));42 }43 44 /**45 * 测试List的contains方法46 */47 public void testListContains() {48 49 // 取得备选课程的第1个元素50 Course cr1 = coursesToSelect.get(0);51 System.out.println("取得课程" + cr1.getName());52 System.out.println("判断备选课程中是否包含课程" + cr1.getName() + ":" + coursesToSelect.contains(cr1));53 54 // 创建一个新的课程对象,id和name和cr1对象完全相同55 Course cr2 = new Course(cr1.getId(), cr1.getName());56 System.out.println("新创建课程:" + cr2.getName());57 System.out.println("判断备选课程中是否包含课程" + cr2.getName() + ":" + coursesToSelect.contains(cr2));58 }59 }
运行结果:
当我们调用List.contains()方法时,其实就是相当于遍历List中的每个元素,然后再调用每个元素的equals()方法,去和contains()方法中的参数进行比较,如果一个元素的equals方法返回一个true值,那么contains()方法也就返回一个true值。
重写课程类的equals方法
1 @Override 2 public boolean equals(Object obj) { 3 if (this == obj) 4 return true; 5 if (obj == null) 6 return false; 7 if (getClass() != obj.getClass()) 8 return false; 9 Course other = (Course) obj;10 if (id == null) {11 if (other.id != null)12 return false;13 } else if (!id.equals(other.id))14 return false;15 if (name == null) {16 if (other.name != null)17 return false;18 } else if (!name.equals(other.name))19 return false;20 return true;21 }
我们重新测试List的contains方法
运行结果:
Collection接口为List接口和Set接口都提供了Contains()方法和ContainsAll()方法
Set的Contains()方法
运行结果:
false的原因是因为咱们用的HashSet实现的Set接口,所以不得从HashSet它的Contains方法的实现机制出发来解决这个问题:
hashCode()方法它返回的是对象的哈希码的值,当我们调用set.contains()方法时,其实是先调用每一个元素它的hashCode方法来返回哈希码,如果他的哈希码相等的情况下,再调用equals方法去判断是否相等,只有在这两个方法所返回值都相等的情况下,才认定这个hashSet包含某个元素,所以我们要要重写他的hashCode方法。
2 如果课程序列包含某门课程,如何判断该课程的索引位置:
List.indexOf()方法
1 public static void main(String[] args) {2 ListTest l1 = new ListTest();3 l1.testAdd();4 Course cr1 = l1.coursesToSelect.get(0);5 if (l1.coursesToSelect.contains(cr1)) {6 System.out.println("课程" + cr1.getName() + "的索引位置" + l1.coursesToSelect.indexOf(cr1));7 }8 }9 }
实现机制:
indexOf()方法的实现机制和contains()方法类似,从序列的第零个位置开始,一次循环并且调用每个元素的equals()方法,去和参数对象对比,如果某个元素的equals()方法返回值为true,那么就把当前元素的索引位置返回,假如序列中又多个重复的元素,那么只返回这个元素第一次出现时所在的那个索引位置的值。
在List中还定义了lastIndexOf()方法,它和indexOf()相反,它返回的是某个元素最后一次出现的索引位置
如果,他们的参数对象都没有在序列中出现,那么这两个方法都会返回-1。
3 在学生映射表中,如何判断是否包含某个学生id,又如何判断是否包含某个学生对象?
Map.containskey(); Map.containsValue();
students.containskey(id);
students.containsValue(Value)
containsValue会调用equals方法,重写equlas()方法和hashCode方法
List中的contains()和Map.containsValue()方法一样。
4 如果想把课程或者学生对象按照课程名称或者学生排序与该怎么办,按照id排序呢?
应用Collections.sort()实现List排序:
JAVA.util.Arrays类,提供了很多静态的方法可以用来操作数组。
在JAVA中还有另一个工具类Collections,JAVA.util.Collections和Arrays类似是JAVA集合框架中用来操作集合对象的工具类,也是JAVA集合框架的成员,与Map和Contains并列
1.通过Collections.sort()方法,对Integer泛型的List进行排序。
2.对String泛型的List进行排序。
3.对其他类型List进行排序,以Student为实例
*对Integer泛型的List进行排序:
*对String泛型List进行排序:
输出结果:
排序按照每个字符串的首字母去排序:
排列顺序:
数字:0--9
大写字母:A-Z
小写字母:a--z
*学生选课,尝试对学生序列排序
对于,List<Integer>,List<包装类>,List<String>这样的包装类都是非常好使的,我们尝试进行其他类型List排序:
*根据元素自然顺序,对指定列表进行升序排序,列表中的所有元素都必须实现Comparable接口
Comparable接口简介:
在JAVA中如果两个对象想要进行排序,那么他们都必须是可以比较的,Comparable接口用于表示可比较的。
Comparable接口就相当于给对象定义了一个默认的比较规则,而Compator是临时比较规则
实现该接口表示,这个类的实例是可以比较大小,可以进行自然排序
定义了默认的比较规则
其实现类需要实现CompareTo()方法
CompareTo()方法返回正数表示大,负数表示小,0表示相等
Compacrator接口:
用于定义临时比较规则,而不是默认比较规则。
其实现类需要实现Compare()方法
Comparable和Compacrator都是JAVA集合框架的成员:
当o对象和Student对象相等时返回0,小就返回正整数,大就返回负整数
定义了一个默认的排序规则,按照学生id进行排序,id是一个String类型的属性,String类型实现了Comparable接口,所以对String字符串类型List可以正常
this.id.compareTo(o.id)用当前id和比较参数对象的id进行比较,将两个对象的id的比较结果作为两个对象的比较结果返回。
compare和compareto的返回值是一样的
等于0两个对象相等,小于0 o1比o2小,大于0 o1比o2大
Comparator接口的使用:
我们可以调用Collections.sort(),和Arrays.sort()方法来使用Comparator接口的具体事例
Collections.sort(l1,new StudentComparator());