Java集合之Collection接口

Java集合之Collection接口,第1张

Java集合之Collection接口

文章目录

集合概述

Java集合概览集合的由来集合与数组的区别如何选用集合?为什么要使用集合? Collection集合

Collection集合的方法 List

List接口的实现类ArrayList与linkedList区别?ArrayList的自动扩容机制List接口的方法 Set

Set接口的实现类

HashSetlinkedHashSetTreeSet

集合概述 Java集合概览

Java集合,也叫做容器,主要是由两大接口派生而来:

一个是Collection接口,主要用于存放单一元素;下面也有三个主要的子接口:List、Set,Queue。另一个是Map接口,主要用于存放键值对。

Java集合框架如下图:

集合的由来

Java是面对对象的语言,我们在编程的时候自然需要存储对象的容器,数组可以满足这个需求,但是数组初始化时长度是固定的,但是我们需要一个长度可变化的容器,因此,集合诞生了。

集合与数组的区别

长度区别:集合长度可变,数组长度固定。内容区别:集合可存储不同类型元素,数组存储只可单一类型元素。元素区别:集合只能存储引用类型元素,数组可存储引用类型,也可存储基本类型。 如何选用集合?

主要根据集合的特点来选用,比如我们需要根据键值获取到元素值时就选用 Map 接口下的集合,需要排序时选择 TreeMap,不需要排序时就选择 HashMap,需要保证线程安全就选用 ConcurrentHashMap。

当我们只需要存放元素值时,就选择实现Collection 接口的集合,需要保证元素唯一时选择实现 Set 接口的集合比如 TreeSet 或 HashSet,不需要就选择实现 List 接口的比如 ArrayList 或 linkedList,然后再根据实现这些接口的集合的特点来选用。

为什么要使用集合?

当我们需要保存一组类型相同的数据的时候,我们应该是用一个容器来保存,这个容器就是数组,但是,使用数组存储对象具有一定的弊端, 因为我们在实际开发中,存储的数据的类型是多种多样的,于是,就出现了“集合”,集合同样也是用来存储多个数据的。

数组的缺点是一旦声明之后,长度就不可变了;同时,声明数组时的数据类型也决定了该数组存储的数据的类型;而且,数组存储的数据是有序的、可重复的,特点单一。 但是集合提高了数据存储的灵活性,Java 集合不仅可以用来存储不同类型不同数量的对象,还可以保存具有映射关系的数据。

Collection集合 Collection集合的方法

Collection接口是单列集合的的最顶层接口,拥有如下的方法。

public class CollectionTest01 {
    
    public static void main(String[] args) {
        
        //创建一个集合对象
        //Collection c = new  Collection(); 接口是抽象的,无法实例化。
        Collection c = new ArrayList();

        
        c.add(1200);
        //自动装箱,实际上是放进去了一个对象的内存地址。
        //Integer x = new Integer(1200)
        c.add(new Object());
        c.add(3.14);
        c.add(true);//自动装箱

        
        System.out.println(c.remove(1200));//true

        
        System.out.println("集合中元素的个数是:"+c.size());//3

        
        c.clear();
        System.out.println("集合中元素的个数是:"+c.size()); //0

        
        c.add("钢铁侠");
        c.add("蜘蛛侠");
        c.add("美国队长");
        System.out.println(c.contains("钢铁侠"));//true
        System.out.println(c.contains("蜘蛛侠"));//true

        
        System.out.println(c.isEmpty());//false
        c.clear();
        System.out.println(c.isEmpty());//true

        
        c.add("abc");
        c.add("def");
        c.add(100);
        Object[] objs=c.toArray();
        for(int i=0;i 

Iterator:迭代器,它是Java集合的顶层接口(不包括 map 系列的集合,Map接口 是 map 系列集合的顶层接口)

public class CollectionTest02 {
    public static void main(String[] args) {
        
        
        //创建集合
        Collection c=new ArrayList();   
        //如果没有重新获取,调用next()方法时会发生异常:java.util.ConcurrentModificationException
        
        //添加元素
        c.add(1);
        c.add(2);
        c.add(3);
      
        //获取迭代器
        Iterator it=c.iterator();
        while (it.hasNext()){
            Object obj=it.next();
            System.out.println(obj); //1 2 3
        }
    }
}
List List接口的实现类

List接口是有序列表,允许存放重复的元素。

List接口的三个典型实现:

List list1 = new ArrayList();

List list2 = new Vector();

List list3 = new linkedList();
List接口实现类ArrayListlinkedListVector底层数据结构Object[ ]数组双向链表Object[ ]数组查询速度快慢快查询效率高高低增删速度慢快慢线程安全性不安全不安全安全可否存储重复元素可以可以可以

数组可以理解为:

被编号站成一排的人,找第10个人很容易,根据编号就很快找到。但是插入、删除慢,因为在任何一个位置插入或删除后,在此位置之后的人编号都需要改变。

链表可以理解为:

手牵手站成一个圈的人,找第10个人不容易,必须从第1个人一个个的数过去。但是插入、删除快。插入或删除任意位置的时候只需要解开对于位置的俩个人的手即可。

ArrayList与linkedList区别?
    是否保证线程安全: ArrayList 和 linkedList 都是不同步的,也就是不保证线程安全。底层数据结构: Arraylist 底层使用的是 Object 数组;linkedList 底层使用的是 双向链表 数据结构。是否支持快速随机访问: linkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。内存空间占用: ArrayList 的空间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 linkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。List接口的方法插入和删除是否受元素位置的影响:

    ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述 *** 作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的 *** 作。linkedList 采用链表存储,所以,如果是在头尾插入或者删除元素不受元素位置的影响(add(E e)、addFirst(E e)、addLast(E e)、removeFirst() 、 removeLast()),近似 O(1),如果是要在指定位置 i 插入和删除元素的话(add(int index, E element),remove(Object o)) 时间复杂度近似为 O(n) ,因为需要先移动到指定位置再插入。

ArrayList的自动扩容机制

待定完成

List接口的方法
public class ListTest {

    public static void main(String[] args) {
        //创建List类型集合
        //List mylist = new Vector();
        //List mylist = new linkedList();
        List mylist = new ArrayList();

        
        //添加元素
        mylist.add("A");
        mylist.add("B");
        mylist.add("C");
        mylist.add("D");
        mylist.add("D");
        mylist.add(1,"Weirdo");

        //迭代
        Iterator it = mylist.iterator();
        while (it.hasNext()){
            Object elt = it.next();
            System.out.println(elt);
        }

        
        Object firstObj = mylist.get(0);
        System.out.println(firstObj);

        
        System.out.println(mylist.indexOf("Weirdo"));//1

        
        System.out.println(mylist.lastIndexOf("D"));//输出结果:5

        
        mylist.remove(0);
        System.out.println(mylist); //[Weirdo, B, C, D, D]

        
        mylist.set(1,"zhn");
        System.out.println(mylist);//[Weirdo, zhn, C, D, D]

    }
}

Set Set接口的实现类

Set接口是无序集合,不允许存放重复的元素,允许使用null元素。

HashSet
Set set = new HashSet();
for(int i= 0;i<5;i++){
    set.add(i+"");
}
set.add("4");       //重复数据,不会写入  
set.add(null);      //可以写入空数据  
Iterator iter = set.iterator();
while(iter.hasNext()){
    System.out.println(iter.next()); //输出是无序的        
}   

HashSet注意点:

    HashSet中不能出现重复数据,元素唯一。HashSet中可以出现空数据,即null。HashSet中的数据是无序的。
linkedHashSet
Set set = new linkedHashSet();  
for(int i= 0;i<5;i++){  
    set.add(i+"");  
}  
set.add("4");       //重复数据,不会写入  
set.add(null);      //可以写入空数据  
Iterator iter = set.iterator();  
while(iter.hasNext()){  
    System.out.println(iter.next()); //输出是有序的  
}  

linkedHashSet注意点:

    linkedHashSet不同于HashSet,linkedHashSet是有序的linkedHashSet在迭代访问Set中全部元素时,性能比HashSet好,但是插入时就差于HashSet
TreeSet
public class TreeSetTest01 {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet<>();
        treeSet.add(90);
        treeSet.add(83);
        treeSet.add(45);
        treeSet.add(50);
        treeSet.add(78);
        treeSet.add(45); //重复元素只会输出一次
        //treeSet.add(null); //不可以写入空元素
        treeSet.add(24);
        treeSet.add(27);
        for (Integer integer : treeSet) {
            System.out.println(integer);
        }
    }
}

上述代码中,集合的元素唯一且进行了排序

使用TreeSet集合进行元素的自然排序,对元素有一定要求,并且这个元素必须实现Comparable接口并重写comparseTo方法,上诉代码为什么没有实现Comparable接口?因为Inreger类实现了该接口,并且重写了里面的方法,如果是自定义类那么必须重写该接口。

//Integer类的源码,里面重写了Comparable接口
public final class Integer extends Number implements Comparable

//TreeSet中的部分源码
public TreeSet(Comparator comparator) {
    this(new TreeMap<>(comparator));
}

上面,我们实现了自然排序的方式,接下来我们来看看实现自定义排序:

public class TreeSetTest02 {
    public static void main(String[] args) {
        //按照学生的年龄大小来排序
        Student s1 = new Student("张三", 21);
        Student s2 = new Student("张三", 21);
        Student s3 = new Student("张三3", 25);
        Student s4 = new Student("张三4", 25);
        Student s5 = new Student("张三5", 23);
        Student s6 = new Student("张三6", 25);
        Student s7 = new Student("张三7", 26);
        Student s8 = new Student("李四1", 28);
        Student s9 = new Student("李四2", 28);
        Student s10 = new Student("李四3", 25);
        TreeSet treeSet = new TreeSet<>();
        treeSet.add(s1);
        treeSet.add(s2);
        treeSet.add(s3);
        treeSet.add(s4);
        treeSet.add(s5);
        treeSet.add(s6);
        treeSet.add(s7);
        treeSet.add(s8);
        treeSet.add(s9);
        treeSet.add(s10);
        for (Student student : treeSet) {
            System.out.println(student);
        }
    }
}

class Student implements Comparable{
    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student s) {
        //比较按照 年龄大小来排序
        int result1 = this.age - s.age;
        //如果年龄相同,不能说明是一个对象,在比较下姓名
        int result2 = result1 == 0 ? this.name.compareTo(s.name) : result1;
        return result2;
    }
}


上述代码,我们自定义了一个Student类,并且实现了Comparable接口,还重写了compareTo方法。

TreeSet底层实现是二叉树(红黑树),那么是如何存储元素的呢?

待定完成

简单理解一下TreeSet的特点:

    不能写入空数据写入数据是有序的不会写入重复元素

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zaji/5710132.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存