Java基础知识(二十六)集合(一)

目录

一、集合的概述:

1、集合与数组的不同点:

2、集合的特点:

二、Collection接口:

1、Collection中的各种功能:

二、集合的遍历:

 1、使用获取功能实现遍历:

三、 List接口(继承自Collection接口)

1、List接口的特点:

2、List相关集合拥有的功能:


一、集合的概述:

引例:利用数组存储三个学生信息,遍历数组获取每个学生信息。

该例的实现较为简单,但是当数组中突然需要加入一个新同学的信息时,则需要重新创建一个长度为四的数组重新实现,若是数据过多则需要不断的创建新的数组去存放,这样的操作非常繁琐,于是Java可以根据元素的不同,元素的特点和存储的方式不同提供一个集合继承机制供使用。

1、集合与数组的不同点:

1、数组的长度是不可变的,集合的长度是可变的

2、数组可以存放同一种基本数据类型或引用数据类型的元素,而集合只能存放引用数据类型的元素,但集合可以存放不同引用数据类型的元素。(实际开发中一个集合只存放一种引用数据类型元素)

2、集合的特点:

集合只用于存储对象;集合长度是可变的;集合可以存放不同类型的对象。

集合不是单一的,针对不同的需求,使用Java提供的不同的集合。这些不同的集合应该有某种共性,根据他们之间的共性不断向上提取,最终形成一个继承机制。

集合的继承体系(机制)

 简略图:

二、Collection接口:

是集合的顶层接口,它存在由他展开而来的继承体系

由于Collection是一个接口,所以无法被实例化,我们需要找它一个子类来进行接口多态的方式实例化,暂时使用ArrayList来举例

1、Collection中的各种功能:

1、添加功能:

boolean add(Object e)  确保此集合包含指定的元素(可选操作)

boolean addAll(Collection c) 将指定集合的所有元素添加到此集合(可选操作)

2、删除功能:

boolean remove(Object o)  从该集合中删除指定元素的单个实例(如果存在)

boolean removeAll(Collection c)  删除指定集合中包含的所有此集合的元素

void clear()从此集合中删除所有元素

3、获取功能:

Iterator iterator()  返回此集合中的元素的迭代器

4、判断功能:

boolean contains(Object o) 如果此集合包含指定元素,返回true

boolean containsAll(Collection c)  如果此集合包含指定集合中的所有元素,则返回true

boolean isEmpty()  如果此集合不包含元素,则返回true

5、获取长度方法:

int size()  返回此集合中的元素数

6、求交集功能:

boolean retainAll(Collection c)  仅保留此集合中包含在指定集合中的元素

7、将集合转为数组:

Object[] toArray()  返回一个包含此集合中的所有元素的数组

具体部分实现:

import java.util.ArrayList;
import java.util.Collection;
 
public class Test1 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
//        Collection的添加功能:
        c.add("hello");
        c.add("world");
        c.add("java");
        c.add("bigdata");
        System.out.println("添加后的集合:"+c);
//        Collection的删除功能remove:
        c.remove("world");
        System.out.println("删除后的集合:"+c);
//      Collection的判断功能:
        System.out.println("判断是否含有world:"+c.contains("world"));
//        判断是否为空:
        System.out.println("判断是否为空:"+c.isEmpty());
//        获取长度:
        System.out.println("集合的长度为"+c.size());
//        Collection的删除功能clear:
        c.clear();
        System.out.println("清除后的集合:"+c);
 
    }
}

输出结果:

 对于使用在两个集合之间的功能实现如下:

import java.util.ArrayList;
import java.util.Collection;
/*
        boolean addAll(Collection c) 将指定集合中的所有元素添加到此集合(可选操作)
        boolean removeAll(Collection c) 删除指定集合中包含的所有此集合的元素(可选操作)。
        boolean containsAll(Collection c) 如果此集合包含指定 集合中的所有元素,则返回true。
        boolean retainAll(Collection c) 仅保留此集合中包含在指定集合中的元素(可选操作)。
 */
public class Test2 {
    public static void main(String[] args) {
        Collection c1 = new ArrayList();
        c1.add("hello");
        c1.add("world");
        c1.add("java");
        c1.add("bigdata");
        System.out.println(c1);
        Collection c2=new ArrayList();
        c2.add("hello");
        c2.add("world");
        c2.add("superman");
        System.out.println(c2);
        System.out.println("==============================================");
        System.out.println("将c2添加到c1:" );
        c1.addAll(c2);
        System.out.println(c1);
        System.out.println(c2);
        System.out.println("==============================================");
        System.out.println("判断c1是否包含c2:");
        boolean b = c1.containsAll(c2);
        System.out.println(b);
        System.out.println("==============================================");
        System.out.println("c1仅保留c2中的元素(取交集):");
//        取交集功能
        c1.retainAll(c2);
        System.out.println(c1);
        System.out.println(c2);
//        c1对c2交集,结果保存在c1中,c2不变,且c1删除与c2不是共同的元素
        System.out.println("==============================================");
        System.out.println("将c1中删除包含c2中的元素:");
        c1.removeAll(c2);
        System.out.println(c1);
        System.out.println(c2);
 
    }
}

输出结果:

二、集合的遍历:

目的就是将集合中的元素依次提取出来

使用到功能7:将集合转为数组 : toArray()方法

 具体实现为将集合转为数组,再对数组进行遍历即可:

import java.util.ArrayList;
import java.util.Collection;
 
public class Test3 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        c.add("hello");
        c.add("world");
        c.add("java");
        c.add("bigdata");
//        使用toArray()将集合转为数组
        Object[] objects = c.toArray();
//        对数组进行遍历
        for(int i=0;i< objects.length;i++){
            System.out.println(objects[i]);//Object o = objects[i](String类型的)
/*        这里使用Object类型接收,但是实际上是String类型
          这就形成了一个多态
*/
        }
    }
}

 输出结果:

若是想要获取每一个字符串元素的长度,直接加入一行语句:

System.out.println(objects[i].length());

 会报错:因为这里使用的是多态,编译看左,运行看右,Object类中没有length()方法

所以需要向下转型,具体代码:

import java.util.ArrayList;
import java.util.Collection;
 
public class Test3 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        c.add("hello");
        c.add("world");
        c.add("java");
        c.add("bigdata");
//        使用toArray()将集合转为数组
        Object[] objects = c.toArray();
//        这里由于不清楚该集合转为数组后是什么数据类型,因此使用Object[]类型接收
//        对数组进行遍历
        for(int i=0;i< objects.length;i++){
//            System.out.println(objects[i]);
//            获取每个字符串元素的长度:
//            向下转型:
            String s=(String)objects[i];
            System.out.println(s+"---"+s.length());
        }
    }
}

 输出结果:

 学生实例:

import java.util.ArrayList;
import java.util.Collection;
 
/*
    需求:向集合中添加3个学生对象,并遍历学生学生信息
 */
public class Test3a {
    public static void main(String[] args) {
//        创建集合对象
        Collection c=new ArrayList();
//        创建学生对象
        Student s1=new Student("马超",18);
        Student s2=new Student("关羽",17);
        Student s3=new Student("张飞",16);
//        将学生对象添加到集合中
        c.add(s1);
        c.add(s2);
        c.add(s3);
//        将集合转换为数组
        Object[] objects = c.toArray();
//        遍历数组
        for (int i=0;i<objects.length;i++){
//            向下转型
            Student s=(Student)objects[i];
            System.out.println(s.getName()+"---"+s.getAge());
        }
 
    }
}

 输出结果:

 1、使用获取功能实现遍历:

Iterator iterator() 返回此集合中的元素的迭代器。 它是Collection集合遍历的专有方式

迭代器是一个接口

两个主要方法:

boolean hasNext() 判断迭代器中是否还有元素

Object next() 返回迭代器中的元素

使用迭代器实现遍历:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
public class Test4 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        c.add("hello");
        c.add("world");
        c.add("java");
        c.add("bigdata");
//        获取迭代器对象
        Iterator iterator = c.iterator();//Iterator iterator = new Itr();
//        该接口的具体实现是类Itr()
//        System.out.println(iterator);//java.util.ArrayList$Itr@4554617c
//        使用next()获取下一个元素
        Object next = iterator.next();
        System.out.println(next);//获取hello
        System.out.println(iterator.next());//获取world
        System.out.println(iterator.next());//获取java
        System.out.println(iterator.next());//获取bigdata
//        System.out.println(iterator.next());//NoSuchElementException
        /*
        当无意中多使用一次next方法时,报错
        原因是该遍历已经执行到最后一个元素了,不应该再指向下一个元素,是多余的
         */
    }
}

输出结果:

上述代码中出现的问题的解决办法:在执行next方法前加入判断:hasnext()

以下为改进代码:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
public class Test4 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        c.add("hello");
        c.add("world");
        c.add("java");
        c.add("bigdata");
//        获取迭代器对象
        Iterator iterator = c.iterator();//Iterator iterator = new Itr();
//        该接口的具体实现是类Itr()
//        System.out.println(iterator);//java.util.ArrayList$Itr@4554617c
 
//        解决办法:在执行next方法前加入判断:hasnext()
        if(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        if(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        if(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        if(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        if(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

输出结果同上面相同,但这里加入了判断之后,使用了五次if判断和next方法,但不影响最终结果。若是添加到集合中的数据量过于庞大,使用if语句的次数便不明确,这里使用while循环进一步进行改进。

最终改进代码为:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
public class Test4 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        c.add("hello");
        c.add("world");
        c.add("java");
        c.add("bigdata");
//        获取迭代器对象
        Iterator iterator = c.iterator();//Iterator iterator = new Itr();
//        该接口的具体实现是类Itr()
//        System.out.println(iterator);//java.util.ArrayList$Itr@4554617c
 
//        使用while循环改进:
         while(iterator.hasNext()){
            Object next = iterator.next();
            String s=(String)next;
            System.out.println(s+"---"+s.length());
        }
    }
}

最终输出结果:

1、 能否将while循环改为for循环?

可以,但是一般情况下不推荐使用普通for循环遍历

2、java为什么要将iterator定义为一个接口而不是一个类?

将来需要根据不同的数据创建不同的集合去存储,每个集合都有自身特点,很有可能每一个集合遍历的顺序和方式都不一样 所以将来取值的时候,使用的方式也不一定是一样的,所以迭代器不应该直接实现如何遍历,而是提供一个接口 将来特有的集合类去实现这个接口中的取值方法,来实现自身的取值特点。

相关案例:

存储自定义对象并遍历:

首先定义一个Student类:

public class Student {
    private String name;
    private int age;
 
    public Student() {
    }
 
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}

 其次相关代码如下: 

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
/*
    存储自定义对象并遍历
 */
public class CollectionTest2 {
    public static void main(String[] args) {
        //1、创建集合对象
        Collection c = new ArrayList();
 
        //2、创建学生对象
        Student s1 = new Student("张飞", 17);
        Student s2 = new Student("关羽", 18);
        Student s3 = new Student("赵云", 19);
        Student s4 = new Student("黄忠", 20);
        Student s5 = new Student("马超", 21);
 
        //3、将学生对象添加到集合中
        c.add(s1);
        c.add(s2);
        c.add(s3);
        c.add(s4);
        c.add(s5);
 
        //4、遍历集合
        //获取迭代器对象
        Iterator iterator = c.iterator();
 
        //遍历迭代器获取元素
        while (iterator.hasNext()) {
            Student s = (Student) iterator.next();
            System.out.println(s.getName() + "---" + s.getAge());
        }
 
    }
}

输出结果:

三、 List接口(继承自Collection接口)

1、List接口的特点:

1、List集合中的元素是有序的(存储和取出顺序相同)存储1,2,3,4,5,输出1,2,3,4,5

2、List集合包含了索引的概念

3、List集合中的元素是可以重复的

相关案例:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
public class ListTest1 {
    public static void main(String[] args) {
//        创建List集合对象
        List list=new ArrayList();
//        添加元素
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("bigdata");
//        遍历
        Iterator iterator=list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

输出结果:

2、List相关集合拥有的功能:

 因为List集合拥有下标索引的概念,故根据这个概念衍生出特有方法:

1、添加功能:

void add(int index, Object element)

将指定的元素插入此列表中的指定位置(可选操作)。

2、删除功能:

Object remove(int index) 删除该列表中指定位置的元素(可选操作)。

3、获取功能:

Object get(int index) 返回此列表中指定位置的元素。

4、修改功能:

Object set(int index, Object element) 用指定的元素(可选操作)替换此列表中指定位置的元素。

5、List集合特有的迭代器

ListIterator listIterator() 返回列表中的列表迭代器(按适当的顺序)。

功能1到4的实现:
 

import java.util.ArrayList;
import java.util.List;
 
public class ListTest2 {
    public static void main(String[] args) {
        List list=new ArrayList();
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("bigdata");
        System.out.println(list);
//        添加功能:
        list.add(0,"hadoop");
        System.out.println(list);
        list.add(2,"hive");
        System.out.println(list);
        list.add(6,"spark");
        System.out.println(list);
//        list.add(10,"flink");
//        System.out.println(list);//IndexOutOfBoundsException
//        这里会有索引越界异常,因此得出添加索引范围为:
//        0<=index<=size(),一旦超出该范围则会异常
        System.out.println("============================================");
        System.out.println("删除前:\r\n"+list);
//        删除功能:
        System.out.println(list.remove(3));
        System.out.println("删除后:\r\n"+list);
        System.out.println("============================================");
//        获取功能:
        System.out.println("获取元素:"+list.get(4));
        System.out.println(list);
        System.out.println("============================================");
//        修改功能:
        Object o = list.set(4, "Superman");
        System.out.println("被修改的元素:"+o);
        System.out.println(list);
 
    }
}

 输出结果:

 List特有的迭代器:

ListIterator listIterator() 返回列表中的列表迭代器(按适当的顺序)。

public interface ListIterator extends Iterator

由于继承自Iterator接口,故内部一定具有hasNext()和next()方法

其中还含有的方法:

Object previous()  返回列表的上一个元素,并向后移动光标位置

 可以反复调用此方法以向后方遍历列表,或者与调用next()进行混合来回。

1、该方法是获取集合中前一个元素

2、该方法获取元素的指针与next()获取元素的指针是同一个

注意:要想倒着遍历,就必须先正着遍历,先将指针移动到末尾。在开发中不常用,但是在面试中可能会问到。

boolean hasPrevious() 返回 true如果遍历反向列表,列表迭代器有多个元素。 判断上一个位置是否有元素,如果有元素返回true,如果没有元素,返回false。

代码举例:

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
 
public class ListDemo3 {
    public static void main(String[] args) {
        //1、创建List集合对象
        List list = new ArrayList();
 
        //2、添加元素到集合中
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("bigdata");
 
        //3、遍历
//        Object previous = listIterator.previous();
//        System.out.println(previous); //NoSuchElementException
//        若是直接使用previous会报错,因为此时光标是在第一个位置,没有上一个元素
        ListIterator listIterator = list.listIterator();
        while (listIterator.hasNext()) {
            String s = (String) listIterator.next();
            System.out.println(s + ",字符串的长度为:" + s.length());
        }
        System.out.println("==============使用previous================");
        while (listIterator.hasPrevious()){
            Object previous = listIterator.previous();
            System.out.println(previous);
        }
    }
}

输出结果:

List集合特有的遍历方式:size()与get()方法结合使用:

具体实现:三种方法一同实现:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
public class ListTest3 {
    public static void main(String[] args) {
        List list=new ArrayList();
        Student s1=new Student("刘备",51);
        Student s2=new Student("曹操",45);
        Student s3=new Student("孙权",40);
        list.add(s1);
        list.add(s2);
        list.add(s3);
 
//        遍历
//        a:转成数组遍历
        Object[] obj = list.toArray();
        for(int i=0;i< obj.length;i++){
            Student s=(Student)obj[i];
            System.out.println(s.getName()+"---"+s.getAge());
        }
        System.out.println("===============================================");
//        b:迭代器遍历:
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            Student s=(Student)iterator.next();
            System.out.println(s.getName()+"---"+s.getAge());
        }
        System.out.println("===============================================");
//        c:size()与get()方法结合使用
        for(int i=0;i< list.size();i++){
            Student s=(Student)list.get(i);
            System.out.println(s.getName()+"---"+s.getAge());
        }
    }
}

输出结果:

现在有一个需求:有一个集合,集合中存储着一些字符串类型的元素,我想判断一下里面有没有"bigdata"这个字符串 如果有,我们就添加一个"yes"。

按照我们上述所学知识,使用Iterator迭代器遍历即可:

但实际上当我们使用迭代器遍历时,会报错:

ConcurrentModificationException: 并发修改异常 当不允许这样的修改的时候,java就检测到该对象出现了并发修改异常。

原因:

迭代器是依赖于集合而存在的,在遍历迭代器中的元素的时候,当我们判断成功后,往集合中添加一个元素,但是这时候,迭代器并不知道已经添加了元素,所以迭代器依然不变,但此时迭代器的元素和集合就不一致了,所以就报错了。

简单描述:在迭代器遍历的时候,不能通过集合去修改元素

解决办法:迭代器遍历,迭代器修改;集合遍历,集合修改

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
 
 
public class ListDemo6 {
    public static void main(String[] args) {
        //1、创建一个集合对象
        List list = new ArrayList();
 
        //2、向集合中添加元素
        list.add("hello");
        list.add("world");
        list.add("java");
        list.add("bigdata");
        list.add("hive");
 
        //遍历
//        Iterator iterator = list.iterator();
//        while (iterator.hasNext()){
//            Object next = iterator.next();
//            String s = (String) next;
//            if("bigdata".equals(s)){
//                list.add("yes");
//            }
//        }
//        以下为两种解决办法:
        //迭代器遍历,迭代器修改
//        ListIterator listIterator = list.listIterator();
//        while (listIterator.hasNext()){
//            Object next = listIterator.next();
//            String s = (String) next;
//            if("bigdata".equals(s)){
//                listIterator.add("yes"); //在bigdata后面添加,因为此时指针正好指到这里
//            }
//        }
 
        //集合遍历,集合修改
        for(int i=0;i<list.size();i++){
            String s = (String) list.get(i);
            if("bigdata".equals(s)){
                list.add("yes"); //在集合末尾添加
            }
        }
 
 
        System.out.println(list);
    }
}

输出结果:两种输出结果:

迭代器遍历输出结果:yes加在当前光标所处位置

集合遍历输出结果:yes加在末尾

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值