Java 集合框架

Java 集合框架


转载自:https://www.shiyanlou.com/courses/document/1120


实验介绍

  本实验讲学习 Java 集合框架里的接口、具体类和算法的相关知识

一、集合框架的介绍

  我们在超市买东西的时候,如果没有购物车是不是会很麻烦呢?Java 中集合类是一种工具类,就是像购物车一样的容器,存储任意数量的具有共同属性的对象。

  我们为什么要用集合呢?一个类的内部有许多相同类型的属性,并且他们的作用与意义是一样的,我们最好用一个类似容器的东西去盛放他们,在类的内部就变得井然有序。所以集合便是在类的内部,对数据进行组织的作用。这样我们便可以简单而快速地搜索大量的条目。有的集合接口,提供了一系列排列有序的元素,并且可以在序列中快速地插入或者删除有关元素。还有一些集合接口,提供了映射关系,可以通过关键字(key)去快速查找到对应的唯一对象,而这个关键字可以是任意类型。

  集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大内容:对外的接口、接口的实现和对集合运算的算法。
  
两大接口  

二、接口

  因为集合框架中的很多类功能是相似的,所以我们用接口来规范类。Collextion 接口是 java 集合框架里的一个根接口。它也是 List、Set 和 Queue 接口的父接口。Collection 接口中定义了可用于操作 List、Set 和 Queue 的方法——增删改查。

方法返回值说明
add(E e)boolean向列表的尾部追加指定的元素(可选操作)
add(int index, E element)void在列表的指定位置插入指定元素(可选操作)
addAll(Collection c)boolean追加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序(可选操作)
addAll(int index, Collection c)boolean将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)
clear()void从列表中移除所有元素(可选操作)
contains(Object o)boolean如果列表包含指定的元素,则返回 true
containsAll(Collection c)boolean如果列表包含指定 collection 的所有元素,则返回 true
equals(Object o)boolean比较指定的对象与列表是否相等
get(int index)返回列表中指定位置的元素
hashCode()int返回列表的哈希码
indexOf(Object o)int返回列表中首次出现指定元素的索引,如果列表不包含此元素,则返回 -1
isEmpty()boolean如果列表不包含元素,则返回true
iterator()Iterator返回以正确顺序在列表的元素上进行迭代的迭代器
lastIndexOf(Object o)int返回列表中最后出现指定元素的索引,如果列表不包含此元素,则返回-1
listIterator()ListIterator返回列表中元素的列表迭代器(以正确的顺序)
listIterator(int index)ListIterator返回列表中元素的列表迭代器(以正确的顺序),从列表的指定位置开始
remove(Object o)boolean移除列表中出现的首个指定元素(可选操作)
removeAll(Collection c)boolean从列表中移除指定 collection 中包含的所有元素(可选操作)
retainAll(Collection c)boolean仅在列表中保留指定 collection 中包含的元素(可选操作)
set(int index, E element)E用指定元素替换列表中指定位置的元素(可选操作)
size()int返回列表中的元素数
subList(int fromIndex, int toIndex)List返回列表中指定的 fromIndex(包括)和 toIndex(不包括)之间的部分视图
toArray()Object[]返回以正确顺序包含列表中的所有元素的数组
toArray() T[]返回以正确顺序包含列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型

  上面有这么多的方法,我究竟应该怎么运用呢?不要着急,我们在后面讲解具体类的时候,会用到上面的许多方法,到时候我们再来详细地学习,当然如果你不自己动手运用一次,是永远都不可能掌握的。

  Map 接口也是一个非常重要的集合接口,用于存储键/值对。Map 中的元素都是成对出现的,键值对就像数组的索引与数组的内容的关系一样,将一个键映射到一个值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。我们可以通过键去找到相应的值。

Map 映射

  value 可以存储任意类型的对象,我们可以根据 key 值快速查找 value。Map 中的键值对以 Entry 类型的对象实例形式存在

看一看 Map 中的方法吧

方法返回值说明
clear()void从映射中移除所用映射关系(可选操作)
containsKey()boolean如果此映射将一个或多个键映射到指定值,则返回true
entrySetSet

三、具体类

1、List 接口与 ArrayList 类

  List 是一个接口,不能实例化,需要一个具体类来实现实例化。List 集合中的对象按照一定的顺序排放,里面的内容可以重复。 List 接口实现的类有:ArrayList(实现动态数组),Vector(实现动态数组),LinkedList(实现链表),Stack(实现堆栈)。

  今天我们主要来学习 java.util.ArrayList,ArrayList 类实现一个课增长的动态数组,它可以存储不同类型的对象,而数组则只能存放特定数据类型的值。

  我们通过实际的例子来学习ArrayList吧!学校的教务系统会对学生进行统一的管理,每一个学生都会有一个学号和学生姓名,我们在维护整个系统的时候,大多数操作是对学生的添加、插入、删除、修改等操作。

先创建一个学生类:

package com.shiyanlou.test_collection_demo;

/*
 * 学生类
 */

public class Student {

    public String id;
    public String name;
    public Student(String id, String name){
        this.id = id;
        this.name = name;
    }
}

再创建一个学生列表,来管理学生

package com.shiyanlou.test_collection_demo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/*
 * 管理学生类
 */
public class ListTest {

    /*
     * 用于存放学生的List
     */
    public List students;
    public ListTest() {
        this.students = new ArrayList();
    }

    /*
     * 用于往students中添加学生
     */
    public void testAdd() {
        //创建一个学生对象,并通过调用add方法,添加到学生管理List中
        Student st1 = new Student('1', '张三');
        students.add(st1);

        //添加到List中的类型均为Object,所以取出时还需要强转
        Student temp = (Student)students.get(0);
        System.out.println('添加了学生:' + temp.id + ':' + temp.name);

        Student st2 = new Student('2','李四');
        students.add(0, st2);
        Student temp2 = (Student)students.get(0);
        System.out.println('添加了学生:' + temp2.id + ':' +temp2.name);

        Student[] student = {new Student('3', '王五'),new Student('4', '马六')};
        students.addAll(Arrays.asList(student));
        Student temp3 = (Student)students.get(2);
        Student temp4 = (Student)students.get(3);
        System.out.println('添加了学生:' + temp3.id + ':' +temp3.name);
        System.out.println('添加了学生:' + temp4.id + ':' +temp4.name);
        Student[] student2 = {new Student('5', '周七'),new Student('6', '赵八')};
        students.addAll(2,Arrays.asList(student2));
        Student temp5 = (Student)students.get(2);
        Student temp6 = (Student)students.get(3);
        System.out.println('添加了学生:' + temp5.id + ':' +temp5.name);
        System.out.println('添加了学生:' + temp6.id + ':' +temp6.name);

    }

    /*
     * 取得List中的元素的方法
     */
    public void testGet() {
        int size = students.size();
        for(int i = 0;i<size;i++){
            Student st = (Student)students.get(i);
            System.out.println('学生:' + st.id+':'+ st.name);

        }
    }

    /*
     * 通过迭代器来遍历
     */
    public void testIterator() {
        //通过集合的iterator方法,取得迭代器实例
        Iterator it = students.iterator();
        System.out.println('有如下学生(通过迭代器访问):');
        while(it.hasNext()){

            Student st = (Student)it.next();
            System.out.println('学生' + st.id + ':' +st.name);
        }
    }

    /**
     * 通过for each 方法访问集合元素
     * @param args
     */
    public void testForEach() {
        System.out.println('有如下学生(通过for each):');
        for(Object obj:students){
            Student st = (Student)obj;
            System.out.println('学生:' + st.id + ':' + st.name);
        }
    }

    /**
     * 修改List中的元素
     * @param args
     */
    public void testModify(){
        students.set(4,new Student('3','吴酒'));
    }

    /**
     * 删除List中的元素
     * @param args
     */
    public void  testRemove() {
        Student st = (Student)students.get(4);
        System.out.println('我是学生:' + st.id + ':' + st.name + ',我即将被删除');
        students.remove(st);
        System.out.println('成功删除学生!');
        testForEach();

    }

    public static void main(String[] args) {
        ListTest lt =  new ListTest();
        lt.testAdd();
        lt.testGet();
        lt.testIterator();
        lt.testModify();
        lt.testForEach();
        lt.testRemove();

    }
}

  大家看懂了吗?自己实操一下吧。

  LinkedList 类是用于创建链表数据结构,使用 LinkList 的好处在于它具有访问、检索和删除数据的方法,特别是添加或移除对象时,LinkedList 的表现更佳。但是底层依然必须遍历去查找随机访问的对象,因此性能依然有限。它与 ArrayList 有许多相似之处,在这里便不详细讲解了

2、Set 接口和 HashSet 类

  Set接口也是 Collection 接口的子接口,它有一个很重要也是很常用的实现类——HashSet,Set 是元素无序并且不可以重复的集合(List 可以重复),被称为集。

  接下来我们同样通过代码的形式来详细看一看吧!

  在上面我们实现了学生的管理,现在学生要做项目,每个项目有一个组长,由组长来组织组员,我们便来实现项目组的管理吧。(接上面的程序实例)

因为项目组的组长由一个老师担任,首先我们来创建一个 PD 类

package com.shiyanlou.test_collection_demo;

import java.util.HashSet;
import java.util.Set;
/*
 * 项目组长类
 */
public class PD {

    public String id;
    public String name;
    //集合后面的<>代表泛型的意思
    //泛型是规定了集合元素的类型
    //我们以后会详细讲到
    public Set<Student> students;
    public PD(String id, String name){
        this.id = id;s
        this.name = name;
        this.students = new HashSet<Student>();
    }
}

接下来我们便创建一个SetTest 类,用来管理项目成员

package com.shiyanlou.test_collection_demo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class SetTest {

    public List<Student> students;

    public SetTest() {
        students = new ArrayList<Student>();
    }

    /*
     * 用于往students中添加学生
     */
    public void testAdd() {
        //创建一个学生对象,并通过调用add方法,添加到学生管理List中
        Student st1 = new Student('1', '张三');
        students.add(st1);

        //添加到List中的类型均为Object,所以取出时还需要强转

        Student st2 = new Student('2','李四');
        students.add(st2);

        Student[] student = {new Student('3', '王五'),new Student('4', '马六')};
        students.addAll(Arrays.asList(student));

        Student[] student2 = {new Student('5', '周七'),new Student('6', '赵八')};
        students.addAll(Arrays.asList(student2));

    }

    /**
     * 通过for each 方法访问集合元素
     * @param args
     */
    public void testForEach() {
        System.out.println('有如下学生(通过for each):');
        for(Object obj:students){
            Student st = (Student)obj;
            System.out.println('学生:' + st.id + ':' + st.name);
        }
    }

    public static void main(String[] args){
        SetTest st = new SetTest();
        st.testAdd();
        st.testForEach();
        PD pd = new PD('1','张老师');
        System.out.println('请:' + pd.name + '选择小组成员!');
        //创建一个 Scanner 对象,用来接收从键盘输入的课程 ID
        Scanner console = new Scanner(System.in);

        for(int i = 0;i < 3; i++){
            System.out.println('请输入学生 ID');
            String studentID = console.next();
            for(Student s:st.students){
                if(s.id.equals(studentID)){
                    pd.students.add(s);
                }
            }
        }
        st.testForEachForSer(pd);
    }
    //打印输出,老师所选的学生!Set里遍历元素只能用foreach 和 iterator 
    //不能使用 get() 方法,因为它是无序的,不能想 List 一样查询具体索引的元素
    public void testForEachForSer(PD pd){
        for(Student s: pd.students) {
        System.out.println('选择了学生:' + s.id + ':' + s.name);
        }
    }

}

  同学们上面的代码看得懂吗?多在 Eclipse 上写一写,然后学会举一反三哦。
  

3、HashMap 类

  HashMap 是 Map 的一个重要实现类,也是最常用的,基于哈希表实现。HashMap 中的 Entry 对象那个是无序排列的,Key 值和 value 值都可以为 null,但是一个 HashMap 只能一个 key 值为 null 的映射(key 值不可重复)

  下面我们通过代码来学习 Map 中的方法吧。同学们都有过选课经历吧,我们就用 Map 来管理课程吧。

创建一个 Course 类:

package com.shiyanlou.test_collection_demo;

public class Course {
    public String id;
    public String name;
    public Course(String id, String name){
        this.id = id;
        this.name = name;
    }
}

创建一个 MapTest 类:

package com.shiyanlou.test_collection_demo;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;

public class MapTest {

    /**
     * 用来承装课程类型对象
     */
    public Map<String, Course> courses;

    /**
     * 在构造器中初始化 courses 属性
     * @param args
     */
    public MapTest() {
        this.courses = new HashMap<String, Course>();
    }

    /**
     * 测试添加:输入课程 ID,判断是否被占用
     * 若未被占用,输入课程名称,创建新课程对象
     * 并且添加到 courses 中
     * @param args
     */
    public void testPut() {
        //创建一个 Scanner 对象,用来获取输入的课程 ID 和名称
        Scanner console = new Scanner(System.in);

        for(int i = 0; i < 3; i++) {
            System.out.println('请输入课程 ID:');
            String ID = console.next();
            //判断该 ID 是否被占用
            Course cr = courses.get(ID);
            if(cr == null){
                //提示输入课程名称
                System.out.println('请输入课程名称:');
                String name = console.next();
                //创建新的课程对象
                Course newCourse = new Course(ID,name);
                //通过调用 courses 的 put 方法,添加 ID-课程映射
                courses.put(ID, newCourse);
                System.out.println('成功添加课程:' + courses.get(ID).name);
            }
            else {
                System.out.println('该课程 ID 已被占用');
                continue;
            }
        }
    }

    /**
     * 测试 Map 的 keySet 方法
     * @param args
     */

    public void testKeySet() {
        //通过 keySet 方法,返回 Map 中的所有键的 Set 集合
        Set<String> keySet = courses.keySet();
        //遍历 keySet,取得每一个键,在调用 get 方法取得每个键对应的 value
        for(String crID: keySet) {
            Course cr = courses.get(crID);
            if(cr != null){
                System.out.println('课程:' + cr.name);
            }
        }
    }

    /**
     * 测试删除 Map 中的映射
     * @param args
     */
    public void testRemove() {
        //获取从键盘输入的待删除课程 ID 字符串
        Scanner console = new Scanner(System.in);
        while(true){
            //提示输出待删除的课程 ID
            System.out.println('请输入要删除的课程 ID!');
            String ID = console.next();
            //判断该 ID 是否对应的课程对象
            Course cr = courses.get(ID);
            if(cr == null) {
                //提示输入的 ID 并不存在
                System.out.println('该 ID 不存在!');
                continue;
            }
            courses.remove(ID);
            System.out.println('成功删除课程' + cr.name);
            break;
        }
    }

    /**
     * 通过 entrySet 方法来遍历 Map
     * @param args
     */
    public void testEntrySet() {
        //通过 entrySet 方法,返回 Map 中的所有键值对
        Set<Entry<String,Course>> entrySet = courses.entrySet();
        for(Entry<String,Course> entry: entrySet) {
            System.out.println('取得键:' + entry.getKey());
            System.out.println('对应的值为:' + entry.getValue().name);
        }
    }

    /**
     * 利用 put 方法修改Map 中的已有映射
     * @param args
     */
    public void testModify(){
        //提示输入要修改的课程 ID
        System.out.println('请输入要修改的课程 ID:');
        //创建一个 Scanner 对象,去获取从键盘上输入的课程 ID 字符串
        Scanner console = new Scanner(System.in);
        while(true) {
            //取得从键盘输入的课程 ID
            String crID = console.next();
            //从 courses 中查找该课程 ID 对应的对象
            Course course = courses.get(crID);
            if(course == null) {
                System.out.println('该 ID 不存在!请重新输入!');
                continue;
            }
            //提示当前对应的课程对象的名称
            System.out.println('当前该课程 ID,所对应的课程为:' + course.name);
            //提示输入新的课程名称,来修改已有的映射
            System.out.println('请输入新的课程名称:');
            String name = console.next();
            Course newCourse = new Course(crID,name);
            courses.put(crID, newCourse);
            System.out.println('修改成功!');
            break;
        }
    }

    public static void main(String[] args) {
        MapTest mt = new MapTest();
        mt.testPut();
        mt.testKeySet();
        mt.testRemove();
        mt.testModify();
        mt.testEntrySet();

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值