1、解决的问题

        实现批量对象的存储,集合比数组更加灵活。数组长度、类型都固定。可将集合看做一个可变长度的Object数组。               

2、Java集合框架

        框架一般意味着类,接口,抽象类等各种东西都很多。当学习一个框架时,要清楚有接口,接口下面有抽象类,抽象类下面有具体类。当面对一个框架时,首要任务是去学习这个框架的接口。

3、Collection接口API

        Collection集合:保存一个一个的对象,特点是 无序可重复

                无序:不按照顺序存放元素,并不按照物理存储空间的连续存储,并且重复的元素也可以添加。一般不用,使用的是它的两个实现:

                Set 子接口:无序 不可重复

                        HashSet :又称散列表,基于数组使用哈希算法实现的set集合,使用频率最高。每次添加元素时,使用哈希函数计算出哈希码,哈希码即为要插入的位置,当两个不同的数据哈希码相同时,称为冲突,当发生冲突时,解决冲突即可。底层实现就是HashMap。

                                优缺点:除了对内存要求高外,其余全是优点。插入、删除、遍历性能都为最优。

                                去重规则:两个对象的equals为true,并且两个对象的哈希码(hashcode)相同。

                        TreeSet : 使用二叉搜索树(平衡二叉树)结构实现的set集合,可以达到数字的自然排序。

                                去重规则:两个对象的比较结果(compareTo)等于0,即比较的部分相同,就去重。

                                优点:对内存要求低,和链表一样,只需要有一个节点(非线性)就足够了。检索性能很优秀。

                                缺点:插入删除速度慢。

                List 子接口:有序可重复 有序(按照添加顺序依次存放)

                        ArrayList:使用数组实现的List集合,线程不安全,但是没关系,有其他方法保证其安全。

                                缺点:对内存要求高,内存必须是一片连续的存储空间,插入和删除的时间复杂度很高,有大量元素的移动。

                                适用场景:存档数据,很少进行插入和删除,主要用于查询检索。

                        Vector:和ArrayList一模一样,是一个古老的实现,线程安全。

                        LinkedList:使用链表实现的List集合,对于频繁的插入和删除元素操作,建议使用LinkedList,效率较高。

                                优点:对内存要求低,插入删除时间复杂度很低。

                                缺点:检索速度慢。

                                适用场景:频繁修改数据,很少进行检索。
        泛型:类型安全问题,在集合中使用泛型的好处是约束集合中的元素数据类型,类型可以是确定的,不再是模糊的Object。

                在运行的角度来讲是没有泛型的,底层只是一个ArrayList集合,加入泛型可以让编译器进行检查。

        Map集合:保存一对一对的对象,用于保存一对映射关系的数据key-value(y = f(x))。通过指定的key可以找到唯一确定的value。可以简化的看做一个set集合,只不过其中存储的元素是Entry。其中key为一个set集合,无序不可重复。

                常见的实现:

                        HashMap:

                                存放key的集合是HashSet。典型实现,使用哈希算法实现的Map集合。

                        LinkedHashMap:

                                是HashMap的子类,可以维护Map的迭代顺序,迭代顺序与key-value对的插入顺序一致

                        TreeMap:

                                存放key的集合是TreeSet。基于二叉树实现的Map集合,针对key可以进行排序。自然排序,定制排序。判断两个key相等的标准:compareTo()方法返回0。

                        HashTable:是古老的实现,和HashMap一样,他是线程安全,效率低,一般不用。

                                Properties是HashTable的子类,配置文件。

4、Iterator迭代器接口   

          遍历:增强for

                for(元素数据类型 临时变量 : 集合){}

         迭代器:Iterator对象称为迭代器(是一种设计模式),主要便利Collection集合中的元素。其中hasNext()方法用来检测当前游标后面是否有下一个元素,如有返回true,反之返回false,当返回true时,调用next()方法可以访问游标后面的下一个元素并且移动游标,如果调用next()方法前,没有使用hasNext()方法进行检测,会抛出异常。

        必须从集合对象获取迭代器,不可以new。

    @Test
    public void test(){
        List<Integer> list = new ArrayList<Integer>();
        for(int i = 0; i < 10; i++){
            list.add((int)(Math.random() * 20));
        }
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            Integer next = iterator.next();
            System.out.print(next + " ");
        }
    }

        注意:

                (1)迭代器一旦获取到,就应该马上使用,如果中间出现了对象集合的修改,都会导致迭代器失效。

                (2)在循环中只能调用一次next()方法。

                (3)迭代器是一次性使用,使用完就作废。

        迭代器逻辑性很强,增强for则不然,是为了统一数组和集合的遍历而出现,迭代器只用于对于集合的遍历。

5、Collection子接口:Set接口

        无序不可重复

        HashSet

         创建HashSet集合,添加,删除,查找(是否包含),遍历操作

class Student{
    private String name;
    private int grade;
    private double score;

    public Student() {
    }

    public Student(String name, int grade, double score) {
        this.name = name;
        this.grade = grade;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getGrade() {
        return grade;
    }

    public void setGrade(int grade) {
        this.grade = grade;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", grade=" + grade +
                ", score='" + score + '\'' +
                '}';
    }
}
    
    @Test
    public void test(){
        HashSet hashSet = new HashSet();
        hashSet.add("abc");
        hashSet.add("zsd");
        hashSet.add(new Integer(100));
        hashSet.add(new Student("小明",4,73.0));
        hashSet.add(200);   //自动装箱,set.add(Integer.valueOf(100));
        boolean b1 = hashSet.add(100);   //添加失败,重复元素不能添加
        System.out.println(b1);
        boolean b2 = hashSet.add("abc"); //添加失败,重复元素不能添加
        System.out.println(b2);

        System.out.println(hashSet.size());

        System.out.println(hashSet);
        System.out.println(hashSet.contains("hfd"));
        hashSet.remove(100);    //删除
        System.out.println(hashSet);

        //增强for循环
        for(Object i : hashSet){
            System.out.println(i);
        }
    }

        练习:创建set集合,添加10个20以内的随机整数。

    @Test
    public void exer(){
        Set set = new HashSet();
        while(set.size() < 10){
            int rand = (int)(Math.random() * 20);
            set.add(rand);
        }
        System.out.println(set);
    }

        注意:

        HashSet去重时的依据是两个对象equals是否为true,并且两个对象的哈希码也相同。在没有重写equals()时,比较的是两个学生对象的地址。

    @Test
    public void test2(){
        HashSet hashSet = new HashSet();    //无序不可重复
        Student s1 = new Student("小明", 3, 88);
        Student s2 = new Student("小明", 3, 88);
        Student s3 = new Student("小王", 3, 98);

        hashSet.add(s1);
        hashSet.add(s2);    //添加成功
        hashSet.add(s3);    
        hashSet.add(s3);    //添加失败

        for(Object object : hashSet){
            System.out.println(object);
        }
    }

        此时若想保留去重功能,则需要重写equals()和hashCode()

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return grade == student.grade &&
                Double.compare(student.score, score) == 0 &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, grade, score);
    }
}

        LinkedHashSet

        

        TreeSet(二叉树)

        无序不可重复,其中无序指的是添加的顺序,并不是数字本身代表大小的顺序。使用此种数据结构,会在其内部实现自然排序。因为会实现排序,所以如果在添加的数据中包含两种不同的数据类型,则会抛出异常(类型转化异常)。

    @Test
    public void test3(){
        Set set = new TreeSet();

        set.add(50);
        set.add(40);
        set.add(60);
        set.add(30);
        set.add(90);
        set.add(80);
        set.add(10);

        for(Object object : set){
            System.out.println(object);
        }

         想要把数据放到TreeSet中,需要使数据具备可比较的能力。

        去重规则:两个对象的compareTo返回0,即比较的部分相同,就去重。

    //在Student类中实现Compareable接口,重写compareTo方法
    @Override
    public int compareTo(Object o) {    //父类中此方法没有抛出异常,所以重写后也不能抛出受检异常
        if(o instanceof Student){
            return this.grade - ((Student) o).grade;
        }
        throw new RuntimeException("对象不可比");    //抛出非受检异常
    }
    @Test
    public void test4(){
        Set set = new TreeSet();

        Student s1 = new Student("小明", 3, 88);
        Student s2 = new Student("小明", 4, 88);
        Student s3 = new Student("小王", 1, 98);

        set.add(s1);
        set.add(s2);
        set.add(s3);

        for(Object object : set){
            System.out.println(object);
        }

    }

        当对象内部无法自己比较大小,或者是谁大谁小有争议时,可以使用第三方机构,当Student类不实现Comparable接口,不能比较时,就可以请出第三方的比较机构,称为比较器Comparator,专门用来比较对象,里面的方法为int compare(T o1, T o2),o1和o2去比较。在jdk中没有现成的比较器,需要手工去写。

class MyComparator implements Comparator{

    @Override
    public int compare(Object o1, Object o2){
        if(o1 instanceof Student && o2 instanceof Student){
            return ((Student) o1).getGrade() - ((Student) o2).getGrade();
        }
        throw new RuntimeException("对象不可比");
    }
}

    @Test
    public void test5(){
        MyComparator myComparator = new MyComparator();
        //定制排序
        Set set = new TreeSet(myComparator);//对象关联,大部分是通过构造器来关联
                                            //TreeSet内部拥有了Comparator比较器

        Student s1 = new Student("小明", 3, 88);
        Student s2 = new Student("小明", 4, 88);
        Student s3 = new Student("小王", 1, 98);

        set.add(s1);
        set.add(s2);
        set.add(s3);

        for(Object object : set){
            System.out.println(object);
        }
    }

        通过比较器进行排序(定制排序)更加灵活,可以根据任意规则进行排序。

        当类内部拥有比较功能并且也有定制排序,则优先使用定制排序,因为定制排序更加高级。

        因为MyComparator类只使用一次。所以更加常用的方式是使用匿名内部类。

        //定制排序
        Set set = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof Student && o2 instanceof Student){
                    return ((Student) o1).getGrade() - ((Student) o2).getGrade();
                }
                throw new RuntimeException("对象不可比");
            }
        });//对象关联,大部分是通过构造器来关联,TreeSet内部拥有了Comparator比较器

6、Collection子接口:List接口

        有序可重复

        ArrayList

        对ArrayList的增删改查,遍历

    @Test
    public void test1(){
        List List = new ArrayList();    //有序可重复
        List.add(199);
        List.add(new Student("小明",5,43));
        List.add(199);
        List.add(new Integer(43));

        System.out.println(List);
        System.out.println(List.size());

        List.add(4,"插入的元素");   //在指定位置插入元素
        System.out.println(List);

        Object o = List.get(4);    //获取指定下标的元素
        System.out.println(o);      

        List.remove(4);     //删除指定下标的元素
        System.out.println(List);

        //遍历
        for(int i = 0; i < List.size(); i++){
            System.out.println(List.get(i));
        }
    }

        创建List集合,存储10个20以内的随机整数,不要重复的

    @Test
    public void exer1(){
        List list = new ArrayList();
        for(int i = 0; i < 10; i++){
            int rand = (int)(Math.random() * 20);
            if(list.contains(rand)){
                i--;
            }else{
                list.add(rand);
            }
        }
        for(int i = 0; i < 10; i++){
            System.out.print(list.get(i));
            System.out.print(" ");
        }
    }

        ArrayList非常灵活,可以存储任意数据类型的元素,那么当对ArrayList中的元素进行某一操作时,如整数求和,会非常麻烦。所以使用泛型技术,可以约束集合中能够保存的元素的类型,在类名后面加一对<>,<>内部填写元素数据类型。

        泛型解决的是类型安全的问题,因为默认的Object类型太模糊了。一旦在集合中使用了泛型,简化了集合的使用,向数组靠拢,但又不是数组,不同数据类型的元素不能添加。

     @Test
    public void test6(){
        List<Integer> list = new ArrayList<Integer>();

        list.add(3);
        list.add(5);
        //list.add("444");  //添加失败
    }

        练习:创建一个List集合,保存随机的10个整数,对其进行排序。再将所有的元素保存在另一个HashSet中,找出最大值。

    //创建List集合,保存随机的10个整数,并对其进行排序
    //再将List中所有元素存储到HashSet中,找出最大值
    @Test
    public void work(){
        List<Integer> list = new ArrayList<>();
        for(int i = 0; i < 10; i++){
            list.add((int)(Math.random() * 20));
        }
        System.out.println(list);
        for(int i = 0; i < list.size() - 1; i++){
            for(int j = 0; j < list.size() - 1 - i; j++){
                if(list.get(j) > list.get(j + 1)){
                    Integer temp = list.get(j);
                    list.set(j,list.get(j+1));
                    list.set(j + 1,temp);
                }
            }
        }
        System.out.println(list);

        Set<Integer> set = new HashSet<>();

        for(int i = 0; i < list.size(); i++){
            set.add(list.get(i));
        }
        System.out.println(set);

        int max = 0x80000000;
        for(Integer integer : set){
            if(integer > max){
                max = integer;
            }
        }
        System.out.println("max:" + max);
    }

7、Map接口

        Map集合:保存的是一对一对的对象,是具有映射关系的健值对象,健值对象都可以是任意对象,健到值是单向一对一映射。

        常用方法:   

                Object put(Object key,Object value);// 写入条目

                Object remove(Object key);// 根据健删除一个条目

                Object get(Object key);// 根据健查找值

                Set keySet();// 获取一个保存所有健对象的Set子集合

                Set entrySet();// 获取保存所有条目对象的Set集合

                int size();// 条目个数

        HashMap

                HashMap集合的增删查

     @Test
    public void test1(){
        Map<Integer, String> map = new HashMap<Integer, String>();
        map.put(1,"one");
        map.put(10,"ten");
        map.put(0,"zero");
        map.put(11,"eleven");
        map.put(2,"two");
        map.put(2,"TWO"); //当key重复时,会刷新value
        map.put(3,"three");
        map.put(1,"one");//key,value不可以重复,添加失败

        System.out.println(map.size());

        map.remove(1);
        //System.out.println(map);

        System.out.println(map.get(2));
        //遍历一,获取所有健
        Set<Integer> keySet = map.keySet();
        Iterator<Integer> iterator = keySet.iterator();
        while(iterator.hasNext()){
            Integer key = iterator.next();
            String value = map.get(key);
            System.out.print(key + "=" + value + " ");
        }
        System.out.println();
        //遍历二,获取所有条目
        Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
        for(Map.Entry<Integer,String> entry : entrySet){
            System.out.print(entry.getKey() + "=" + entry.getValue() + " ");
        }
    }

        练习:创建Map集合,存放圆的半径和面积,将半径为1-50的面积保存在其中,将Map中的半径数据截取至Set集合中,遍历Set集合,逐一取出对应的value。

    @Test
    public void test2(){
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for(int i = 1; i < 51; i++){
            map.put(i, (int)(Math.PI * i * i));
        }
        Set<Integer> set = map.keySet();
        Iterator<Integer> iterator = set.iterator();
        while(iterator.hasNext()){
            Integer key = iterator.next();
            Integer value = map.get(key);
            System.out.println(key + "=" + value);
        }
    }

        HashMap判断两个key(value)相等的标准是两个key(value)的equals()方法返回true,hashCode相等。

        TreeMap

        Hashtable

                Properties

                        是Hashtable的子类,专门用于处理配置文件(文本文件,内容是健=值),使用频率极高

        创建配置文件test.properties.

url=http://www.baidu.com
user=root
password=123456
password=hello
    @Test
    public void test3() throws IOException {
        Properties properties = new Properties();
        properties.load(new FileInputStream("test.properties"));
        System.out.println(properties);

        String password = properties.getProperty("password");
        System.out.println(password);
    }

练习:将学生姓名与考试分数录入到map中,按照分数显示前三名的成绩与姓名。

public class HomeWork {

    @Test
    public void test(){
        //将学生姓名与考试分数录入到map中,按照分数显示前三名的成绩与姓名
        //创建HashMap存储学生信息,key为学生姓名,value为学生考试成绩
        Map<String, Integer> map1 = new HashMap<>();
        map1.put("张三",80);
        map1.put("李四",100);
        map1.put("王五",90);
        map1.put("赵六",100);
        map1.put("小明",99);
        //创建比较器,并且不允许去重,修改compare内部代码
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                int n = o2 - o1;
                if(n == 0){
                    n = 1;
                }
                return n;
            }
        };
        //创建TreeMap集合,将HashMap集合中的学生信息key,value调换位置进行存储,完成学生成绩的排序
        Map<Integer, String> map2 = new TreeMap<>(comparator);
        //将key value在HashMap中取出
        Set<String> keySet = map1.keySet();
        Iterator<String> iterator = keySet.iterator();
        while(iterator.hasNext()){
            String key = iterator.next();
            Integer value = map1.get(key);
            map2.put(value,key);
        }
        //将取出的数据,存入到TreeMap中
        Set<Map.Entry<Integer, String>> entrySet = map2.entrySet();
        Iterator<Map.Entry<Integer, String>> iterator1 = entrySet.iterator();
        //取出成绩前三名的同学信息
        int count = 0;
        while(iterator1.hasNext()){
            Map.Entry<Integer, String> entry = iterator1.next();
            System.out.println(entry.getKey() + entry.getValue());
            if(++count == 3){
                break;
            }
        }
    }

}

练习:给定一个字符串,统计每个字符出现的次数

思路一:使用HashMap

    @Test
    public void test1(){
        //给定一个字符串,统计每个字符出现的次数
        //字符作为key,出现的次数作为value
        String s = "aaabbbcccdddeeefffshkgswl我是汉字烦死了这么长女女女女女女你妈妈可抵扣积分";
        Map<Character, Integer> map = new HashMap<>();
        for(int i = 0; i < s.length(); i++){
            char ch = s.charAt(i);  //获取到字符
            Integer count = map.get(ch);    //记录出现次数
            if(count == null) {     //之前没有put过,返回值是null,
                count = 0;
            }
            map.put(ch, count + 1);
        }
        System.out.println(map);
    }

思路二:使用数组

    @Test
    public void test2() {
        //给定一个字符串,统计每个字符出现的次数
        String s = "aaabbbcccdddeeefffshkgswl我是汉字烦死了这么长女女女女女女你妈妈可抵扣积分";
        int[] arr = new int[65535];
        for(int i = 0; i < s.length(); i++){
            char ch = s.charAt(i);
            arr[ch]++;
        }
        for(int i = 0; i < arr.length; i++){
            if(arr[i] != 0){
                System.out.println((char)i + ":" + arr[i]);
            }
        }

8、Collections工具类

        是一个操作Set,List和Map等集合的工具类,内部均为静态方法。

        对List集合的排序,翻转,洗牌。

    @Test
    public void test4(){
        List<Integer> list = new ArrayList<Integer>();
        for(int i = 0; i < 10; i++){
            list.add((int)(Math.random() * 20));
        }
        System.out.println(list);

        Collections.sort(list);
        System.out.println(list);

        Collections.reverse(list);
        System.out.println(list);

        Collections.shuffle(list);
        System.out.println(list);
    }

        查找最大值最小值

        Integer max = Collections.max(list);
        System.out.println(max);

        Set<Integer> set = new HashSet<Integer>(list);
        Integer min = Collections.min(set);
        System.out.println(min);

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐