由于 Java 中的集合框架的内容比较多,在这里分为三个部分介绍 Java 的集合框架,内容是从浅到深,如果已经有 java 基础的小伙伴可以直接跳到 <浅入深出之 Java 集合框架(下)>。
目录:
浅入深出之 Java 集合框架(上)
浅入深出之 Java 集合框架(中) 努力赶制中。。关注后更新会提醒哦!
浅入深出之 Java 集合框架(下)努力赶制中。。关注后更新会提醒哦!
现实生活中的集合:很多事物凑在一起。
数学中的集合:具有共同属性的事物的总体。
Java 中的集合类:是一种工具类,就像是容器,储存任意数量的具有共同属性的对象。
如果一个类的内部有多相同类型的属性,并且它们的作用和意义是一样的。比如说,一个学生可以选多个课程,对于一个学生类来说,XX 课程就是他的一个属性,而 xx 课程通常不只有一个。对于像这种情况,如果把每一个课程都定一个属性就太繁琐了,这里我们就要用到集合的概念。
综上所述,集合的作用有以下几点:
可以看出集合和数组的功能类似,都是把一系列的数据放入到一个容器中,但是在类的内部我们为什么要用集合而不是数组呢?
我们来简单看一下 java 集合框架:(还有很多接口和类没有列出,这里只列出常用的接口和类)
如图所示,JAVA 集合框架体系结构:Collection 与 Map 是两个根接口。
Collection 接口:内部存储的是一个个独立的对象。包含:
1、List 接口:序列,存储元素排列有序且可重复。实现类: ArrayList,数组序列;实现类:LinkedList,链表。
2、Queue 接口:队列,存储元素排列有序且可重复。实现类:LinkedList,链表。
3、Set 接口:集,存储元素无序且不可重复。实现类:HashSet,哈希集。
Map 接口:内部以 <Key,Value>(任意类型)的一个映射去存储数据,这一个映射就是 Entry 类(Map 的内部类)的实例。包括:实现类:HashMap,哈希表。
Collection 接口是 List、Set、Queue 接口的父接口,Collection 接口定义了可用于操作 List、Set 和 Queue 的方法 -- 增删改查。(具体的 Collection 接口的方法可以通过查 API,这里就不列举了。)
其中,ArrayList、HashSet 和 HashMap 是使用最多的三个实现类,这里我们将逐个介绍这三个实现类。
在这篇文章中将先介绍 ArrayList 的用法。
List 接口及其实现类 --ArrayList
List 可以精确的控制每个元素的插入位置,或删除某个位置元素;
List 有 add() 插入方法和 get() 获取方法;
ArrayList-- 数组序列,是 List 的一个重要实现类
ArrayList 底层是由数组实现的,这也是其名字的由来。
那么如何使用这些集合呢?我们来通过一个小例子,写一个小程序来更直观的学习集合的使用方法。(之后的文章的例子也是基于此的)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
程序功能——模拟学生选课功能
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
以下是该程序的代码片段,因为是用于测试来介绍集合的使用,所以请不要在意细节,代码会一步步改进的。
- 1
- /**
- 2 * 学生类
- 3 * @author hysum
- 4 *
- 5 */
- 6 public class Student implements {
- 7 private String name; //学生姓名
- 8 private String id; //学生id
- 9 private Set courses; //所选课程的set集合
- 10 11 public Student() {}
- 12 public Student(String id, String name) {
- 13 this.id = id;
- 14 this.name = name;
- 15 this.courses = new HashSet(); //初始化集合
- 16
- }
- 17 public String getName() {
- 18
- return name;
- 19
- }
- 20 public void setName(String name) {
- 21 this.name = name;
- 22
- }
- 23 public String getId() {
- 24
- return id;
- 25
- }
- 26 public void setId(String id) {
- 27 this.id = id;
- 28
- }
- 29 public Set getCourses() {
- 30
- return courses;
- 31
- }
- 32 public void setCourses(Set courses) {
- 33 this.courses = courses;
- 34
- }
- 1
- /**
- 2 * 课程类
- 3 * @author hysum
- 4 *
- 5 */
- 6 public class Course {
- 7 private String id; //课程id
- 8 private String name; //课程名称
- 9 10 public Course() {
- 11 12
- }
- 13 public Course(String name) {
- 14 this.name = name;
- 15
- }
- 16 public String getId() {
- 17
- return id;
- 18
- }
- 19 public void setId(String id) {
- 20 this.id = id;
- 21
- }
- 22 public String getName() {
- 23
- return name;
- 24
- }
- 25 public void setName(String name) {
- 26 this.name = name;
- 27
- }
- 28 public Course(String id, String name) {
- 29 this.id = id;
- 30 this.name = name;
- 31
- }
- 32
- }
- 1
- /**
- 2 * 备选课程类
- 3 *
- 4 * @author hysum
- 5 *
- 6 */
- 7 public class ListCourse {
- 8 private List CoresesToSelect; // 备选课程
- 9 private Student stu;
- 10 private static Scanner in ;
- 11 {
- 12 in =new Scanner(System. in );
- 13
- }
- 14 public ListCourse() {
- 15 this.CoresesToSelect = new ArrayList(); // 初始化List集合
- 16
- }
- 17 public List getCoresesToSelect() {
- 18
- return CoresesToSelect;
- 19
- }
- 20 21 public void setCoresesToSelect(List coresesToSelect) {
- 22 CoresesToSelect = coresesToSelect;
- 23
- }
- 26
- }
注意:
List 是接口,所以在构造方法中不能直接实例化,而通过 ArrayList() 实例化!!!
例:public List coursesToSelect = new ArrayList();
Set、Map 都类似,不可以直接对他实例化,要借助相应的实例化类如 HashSet(),HashMap();
(添加元素)List 下总共有 4 个为 List 插入元素的方法 :
1.add(element);
2.add(index,element);
3.addAll(Arrays.asList(对象数组名));
4.addAll(index,Arrays.asList(对象数组名));
以下用代码示例:
- 1
- /*
- 2 * 添加备选课程
- 3 */
- 4 public void AddCourse() {
- 5 Course cr1 = new Course("1", "数据结构"); //创建课程对象
- 6 this.CoresesToSelect.add(cr1); //用add(element)添加
- 7 Course temp = (Course) this.CoresesToSelect.get(0); //用get方法取出,注意类型转换
- 8 System.out.println("添加了课程:" + temp.getId() + " " + temp.getName());
- 9 10 Course cr2 = new Course("2", "C语言"); //创建课程对象
- 11 this.CoresesToSelect.add(0, cr2); //用add(index,element)添加
- 12 temp = (Course) this.CoresesToSelect.get(0);
- 13 System.out.println("添加了课程:" + temp.getId() + " " + temp.getName());
- 14
- }
- 1 Course[] course = {
- new Course("1", "数据结构"),
- new Course("2", "C语言"),
- new Course("3", "汇编语言"),
- 2 new Course("4", "离散数学")
- };
- 3 this.CoresesToSelect.addAll(Arrays.asList(course)); //用addAll(Arrays.asList(对象数组名))添加
注意:
1. 对象被存入集合都变成 object 类型了 取出时需要类型强转。(之后会用泛型来解决这个问题)
例:Course temp = (Course)coursesToSelect.get(0);
2. 添加进 list 中的位置(index)介于 [0,length] 之间;0 代表插到队头,length 代表插到队尾。
3. 如果添加到 List 中的长度大于他目前的长度,则系统会出现异常,即数组下表越界异常, 如:
- 1 Course cr2 = new Course("2", "C语言"); //创建课程对象
- 2 this.CoresesToSelect.add(2, cr2); //用add方法添加,超出集合现有长度 temp=(Course)
以下三种方法都是用来取出 List 中元素的方法:
-----for 循环 -----
- 1 public void testGet() {
- 2 int size = CoursesToSelect.size();
- 3
- for (int i = 0; i) {
- 4 Course cr = (Course) CoursesToSelect.get(i);
- 5 System.out.println("取出的课程:" + cr.getId() + ":" + cr.getName());
- 6
- }
- 7
- }
----- 迭代器 -----
Iterator 是一个接口, 依赖于集合存在的。
- 1 Iterator it = CourseToSelect.iterator();
- 2
- while (it.hasNext()) {
- 3 Course cr = (Course) it.next();
- 4 System.out.println("课程:" + cr.id + ":" + cr.name);
- 5
- }
-----for each(推荐使用)-----
- 1
- for (Object obj: CoursesToSelect) { //遍历集合中的每一个元素,作为每一个Object变量
- 2 Course cr = (Course) obj;
- 3 System.out.println("课程:" + cr.id + ":" + cr.name);
- 4
- }
使用 set(index,Object element)修改元素,index 表示索引位置,element 表示新对象。
- 1
- /*
- 2 * 修改备选课程
- 3 */
- 4 public void Modify(int index, Course c) { // 传入要修改的参数
- 5 this.CoresesToSelect.set(index, c);
- 6
- }
List 中有 remove(index),remove(对象值) 和 removeAll(Arrays.asList(对象数组名)) 方法来删除容器中元素的值 (用法和 add 类似)。
Course 是信息课程类,有 id 和 name 属性;courseToSelect 是 list 的序列容器对象。
- 1 /*
- 2 * 删除备选课程,跟添加方法类似
- 3 */
- 4 public voidRemove(intindex) {// 通过索引位置删除
- 5 this.CoresesToSelect.remove(index);
- 6 }
- 7
- 8 public voidRemove(Course c) {// 通过课程对象删除
- 9 this.CoresesToSelect.remove(c);
- 10
- 11 }
- 12
- 13 public voidRemove(Course[] c) {// 通过集合对象删除
- 14 this.CoresesToSelect.removeAll(Arrays.asList(c));
- 15
- 16}
注意:
1.remove(index); 删除位置要大于 0 并且小于 List(序列容器) 的长度。如果要删除全部可以用 for 循环嵌套此方法。
2.remove(object); 先要获得删除的值,用法是先定义一个信息变量通过 get() 来存放要删除的值, 然后用 remove(删除的对象值);
3.removeAll(Arrays.asList()); 要删除指定的多个位置 Arrays.asLIst(对象数组名); 作用是把数组转换为集合。用法是先创建信息对象数组存放删除元素的值,然后再用 removeAll(Arrays.asList(对象数组名)) 方法, 删除集合数组的元素。
在上面的几个例子中,小伙伴是否发现对于集合的取出和遍历都要将 Object 对象进行强制转换后才能使用,每次这样做不仅增加了编程难度还使代码特别繁琐,这里我们可以利用泛型来帮助我们更加方便地使用 java 集合。
首先,我们要知道没有使用泛型的话,集合中的元素, 可以是任意类型的对象 (对象的引用),如果把某个对象放入集合, 则会忽略他的类型把他当做 Object 处理。
那么我们就在刚才的例子里往备选课程类里的 CoresesToSelect 的 List 集合添加一些奇怪的东西会发什么有趣的事呢?
- 1
- /*
- 2 * 往List中添加一些奇怪的东西
- 3 */
- 4 public void testType() {
- 5 System.out.println("能否往List中添加一些奇怪的东西呢?");
- 6 this.CoresesToSelect.add("我不是课程,我是字符串!");
- 7
- }
当调用取出课程方法取出该元素时,运行时出错:
这是因为取出该元素时 String 类型不能强制转换为 Course 类型,那有什么办法来避免集合中被添加不希望添加的类型呢?
泛型则是规定了某个集合只可以存放特定类型的对象,会在编译期间进行类型检查,可以直接指定类型获取的集合元素。
泛型:指规定了某个集合只能存放特定类型的对象。
- 语法:ArrayList array = new ArrayList(); //规定array中只能存放String类型的对象
那么,了解了泛型之后,上面的例子里都可以加上泛型了,修改如下(只列出修改的部分):(自行对比)
- 1 private Set courses; //所选课程的set集合
- 2 this.courses = new HashSet(); //初始化集合
- 3 public Set getCourses() {
- 4
- return courses;
- 5
- }
- 6 public void setCourses(Set courses) {
- 7 this.courses = courses;
- 8
- }
- 1 private List CoresesToSelect; // 备选课程
- 2 public ListCourse() {
- 3 this.CoresesToSelect = new ArrayList(); // 初始化List集合
- 4
- }
- 5 public List getCoresesToSelect() {
- 6
- return CoresesToSelect;
- 7
- }
- 8 9 public void setCoresesToSelect(List coresesToSelect) {
- 10 CoresesToSelect = coresesToSelect;
- 11
- }
foreach 循环的修改:
- 1
- for (Course obj: CoresesToSelect) {
- 2 System.out.println("添加了课程:" + obj.getId() + " " + obj.getName());
- 4
- }
运用了泛型的话,用 foreach 语句时 存储变量应该为泛型的类型。for(Course a:courseToSelect), 不必再用 Object 取出再强转,因为已经规定容器里装的都是 Course 类型。
使用泛型要注意:
1. 泛型集合中,不能添加泛型规定的类型和其子类以外的对象,否则会报错!
2. 泛型中可以添加规定的类型的子类型的对象。如:
- 1 public void testChild() {
- 2 ChildCourse ccr = new ChildCourse();
- 3 ccr.id = "3";
- 4 ccr.name = "我是子类型的课程对象实例~~";
- 5 courses.add(ccr);
- 6
- }
3. 不能直接添加基本类型(int,float 等)的对象,如果要添加,需要使用其包装类。如:
- 1 public void testBasicType() {
- 2 List list = new ArrayList();
- 3 list.add(1);
- 4 System.out.println("基本类型必须使用包装类作为泛型!" + list.get(0));
- 5
- }
Set 集合和 List 一样是 Collection 接口的子接口。它的方法跟 List 类似,但有稍许不同,因为 Set 集合是无序且不重复的。
add 方法跟 ArrayList 一样
- 1 li.stu = new Student("1", "小明");
- 2 System.out.println("欢迎" + li.stu.getName() + "同学选择课程");
- 3
- for (int i = 0; i < 3; i++) { //循环三次添加选课
- 4 System.out.println("请选第" + (i + 1) + "门课程:");
- 5 String Id = in.next();
- 6
- for (Course c: li.getCoresesToSelect()) {
- 7
- if (c.getId().equals(Id)) {
- 8 li.stu.getCourses().add(c);
- 9
- }
- 10
- }
- 11 12
- }
注意:Set 中添加某个对象,无论添加多少次,最终只会保留一个该对象(的引用)。同时,保留的是第一次添加的那一个。Set 集合是无序的不可重复的。
- 1 //输出学生选的课程
- 2
- for (Course c: li.stu.getCourses()) {
- 3 System.out.println(c.getId() + " " + c.getName());
- 4 5
- }
注意:循环遍历 Set 中的每一个元素只能用 foreach 或 iterator,不能像 List 一样用 get() 方法。因为是无序的每次的输出结果都有些差别。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
总结:
1、Set 没有像 List 中 set() 方法一样就修改,因为 List 是有序的,可以指定位置,而 Set 是无序的,可以用循环遍历方式修改。
2、查询遍历时,Set 不能用 get() 方法去获取,因为无序没有指定索引 ID,但可以使用 foreach 和 iterator 来遍历,但是每次遍历出来可能顺序都不一样,还是因为无序造成的。
3、Set 中的 size(),add(),addAll(),remove(),removeAll() 与 List 类似。
4、Set 还可以添加 null(但只能添加一个 null,因为不重复);
本篇主要讲述了 List 和 Set 的基本操作:增删改查,下一篇我将介绍 Map 接口的基本操作,有兴趣的小伙伴可以加一下方的 "关注" 哦!博主正在努力加载中。。。。。。
来源: http://www.cnblogs.com/hysum/p/7136480.html