集 合 总 结

1、什么是集合?有什么用?

数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其它类型的数据。

集合为什么说在开发中使用较多?

集合是一个容器,是一个载体,可以一次容纳多个对象。在实际开发中,假设连接数据库,数据库当中有10条记录,那么假设把这10条记录查询出来,在java程序中会将10条数据封装成10个java对象,然后将10个java对象放到某一个集合当中,将集合传到前端,然后遍历集合,将一个数据一个数据展出来。

//不能放基本类型,可以存放object类型(即只能存放对象的引用)

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

//数组也是内存对象
//ArrayList  查询效率高,增删差
//LinkedList  增删效率高,查找效率低
//为null说明没对象
//为空说明有对象但是没赋值
//remove()方法会自动调用该对象的equals方法
//Collection是父类,所以里面的方法是子类都有的
public class Collection_1 {
    public static void main(String[] args) {
        //创建集合对象
        Collection c1 = new ArrayList();
        //判断是否为空即个数是否为0
        System.out.println(c1.isEmpty());//true
        // 集合中是不能保存基本类型的,需要转换为对应包装类才可以
        // 这里会进行自动装箱为Integer类型,然后发生多态转型为Object类型 进行存储
        c1.add(213);
        c1.add(new Integer(1));
        c1.add(new Collection_1());
        // 个数
        System.out.println(c1.size());//3
        //是否为空
        System.out.println(c1.isEmpty());//false
        // 删除,会调用要删除元素的equals方法,但是Integer覆写了,所以可以把1删掉
        c1.remove(1);
        A a = new A("李四");
        A a1 = new A("李四");
        c1.add(a);
        // 所以使用集合保存自定义类型的时候,要注意,是否要覆写equals方法,定义怎么算相等
        c1.remove(a1);
        Object[] arr = c1.toArray();
        for (Object object: arr){
            System.out.println(object);//213
            //Mouth_1_.Week_3_.Day_18._1_Collection.Collection_1@1540e19d
        }
        // 清空集合
        c1.clear();
        System.out.println(c1.size());//0
    }
}
class A {
    private String name;

    public String getName() {
        return name;
    }

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

    public A() {
    }

    public A(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        A a = (A) o;
        return Objects.equals(name, a.name);
    }

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

    @Override
    public String toString() {
        return "A{" +
                "name='" + name + '\'' +
                '}';
    }
}

 2、集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用。)

list.add(100) ; // 自动装箱Integer

注意:

集合在java中本身是一个容器,是一个对象
集合中任何时候存储的都是 “引用”

3、集合内存图示

 

4、在Java中每一个不同的集合,底层都会对应不同的数据结构

往不同的集合中存储元素,等于将数据放到了不同的数据结构当中。

什么是数据结构?

数据存储的结构就是数据结构。
不同的数据结构,数据存储方式不同

例如:
new ArrayList(); 创建一个集合,底层是数组。
new LinkedList(); 创建一个集合对象,底层是链表。
new TreeSet(); 创建一个集合对象,底层是二叉树。

5、集合在JDK的哪个包下?

java.util.*包下;
所有的集合类和集合接口都在java.util包下。

6、在Java中集合分为两大类

一类是单个方式存储元素:

单个方式存储元素,这一类集合中超级父接口: java.util.Collection;

 一类是以键值对的方式存储元素:

以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;

 collection方法

 

 7.集合的继承结构图

 8.Map的继承层次结构

 9.所有实现类总结

■ ArrayList:底层是数组。

■ LinkedList:底层是双向链表。

■ Vector:底层是数组,线程安全的,效率较低,使用较少。

■ HashSet:底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了。.

■ TreeSet: 底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了。

■ HashMap:底层是哈希表。线程不安全。

■ Hashtable:底层也是哈希表,只不过线程安全的,效率较低,使用较少。

■ Properties: 是线程安全的,并且key和value只能存储字符串String。

■ TreeMap: 底层是二叉树。TreeMap集合的key可以自动按照大小顺序排序。。

1、List集合存储元素的特点:

有序可重复。
有序:存进去的顺序和取出的顺序相同,每一个元素都有下标。
可重复:存进去1,可以再存储一个1。
2、Set集合存储元素的特点:

无序不可重复
无序:存进去的顺序和取出的顺序不一-定相同。 另外Set集合中元素没有下标。
不可重复:存进去1,不能再存储1了。
3、SortedSet (SortedMap) 集合存储元素特点:

首先是无序不可重复的,但是SortedSet集合中的元素是可排序的。
无序:存进去的顺序和取出的顺序不一定相同。另外Set集合中元素没有下标。
不可重复:存进去1,不能再存储1了。
可排序:可以按照大小顺序排列。
Map集合的key,就是一个set集合。
往set集合中放数据,实际上到了Map集合的key部分。

迭代器iterator

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
 * 在面向对象编程里 迭代器模式是一种设计模式,是一种最简单也是最常见的设计模式
 * 它可以让用户透过特定的接口巡防容器中的每个元素,而不用了解底层的实现
 * 获取迭代器对象
 * Iterator IT = 集合对象 .iterator();
 * 包括三个方法:
 *      1.boolean hasNext()判断下面还有没有元素,
 *      如果有就返回true,反之返回false
 *      2.E next():获取下一个元素并指向下一个元素
 *      3.remove():删除当前指向的元素
 *      三个方法的使用步骤,按照1,2,3顺序调用
 * 注意:迭代器一旦创建,集合中就不能添加和删除元素(长度不能更改了)
 *  如果添加或者删除了元素,那么迭代器必须重新生成)
 *  增强for循环  foreach,写起来更简单
 *  功能不太全,删除的时候还是用iterator来删除
 */
public class Collection_2_Iterator {
    public static void main(String[] args) {
        Collection c1 = new ArrayList();
        c1.add(1);
        c1.add("asd");
        //判断是否包含1
        System.out.println(c1.contains(1));//true
        //创建迭代器
        Iterator it = c1.iterator();
        //遍历元素,判断下面是否有元素
        while (it.hasNext()) {
            //获取并指向下一个元素
            Object obj = it.next();
            System.out.println(obj);//1   asd
        }
        // 使用完之后,想再次使用,需要重新创建迭代器
        it = c1.iterator();
        // 迭代器创建之后,不能添加和删除 , 必须重新生成迭代器
        c1.add(3);
        c1.add(4);
        c1.remove(1);
        it = c1.iterator();
        while (it.hasNext()){
            // 获取并指向下一个元素
            Object obj = it.next();
            System.out.println(obj);//asd   3   4
            // 使用迭代器的时候,不能更改集合个数,所以删除数据的时候不能使用集合的删除,应该使用迭代器的删除
            // c1.remove(obj);
            it.remove();
        }
        System.out.println(c1.size()+ "======");//0======
    }
}


10.contains方法解析

语法格式boolean contains(Object o)

判断集合中是否包含某个对象o,如果包含返回true,如果不包含返回false。

contain方法是用来判断集合中是否包含某个元素的方法。

那么他的底层是怎么判断集合中是否包含某个元素的呢?

 调用了equals方法进行比对
equals方法返回true,就表示

 所以存放在一个集合中的类型,一定要重写equals方法

package com.company.Collection;

import java.util.ArrayList;
import java.util.Collection;

public class CollectionText2 {
    public static void main(String[] args) {
        //创建集合对象
        Collection c = new ArrayList();

        //向集合中存储对象
        String s1 = new String("abc");
        c.add(s1);

        String s2 = new String("abc");
        c.add(s2);

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

        //新建的对象String
        String x = new String("abc");
        //c集合中是否包含x ? 结果猜测一下是true还是false ?
        System.out.println(c.contains(x));//判断集合中是否存在“abc” true
    }
}

 在这里插入图片描述

 在这里插入图片描述

 

11.remove方法解析

在上述代码基础上加入以下该行:

        c.remove(u2);
        System.out.println(c.size());//输出结果为:0

        Collection cc = new ArrayList();
        String s1 = new String("hello");
        cc.add(s1);
        String s2 = new String("hello");
        cc.remove(s2);
        System.out.println(cc.size());//输出结果为:0

 在这里插入图片描述

 去掉User类中的equals方法后,结果为:

 在这里插入图片描述

 

由此可知remove中也调用了equals方法

重点:当集合的结构发生改变的时候,迭代器必须重新获取

当集合的结构发生改变的时候,迭代器必须重新获取,如果还是用以前老的迭代器,会出现异常。

Collection c2 = new HashSet();

        Iterator it2 = c2.iterator();
        c2.add(1);
        c2.add(2);
        c2.add(3);
        c2.add(4);
        c2.add(1);
        c2.add(2);

 此时便会出现异常:
ConcurrentModificationException

package com.company.Collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionText4 {
    public static void main(String[] args) {

        Collection c2 = new ArrayList();
        c2.add("abc");
        c2.add("def");
        c2.add("xyz");

        Iterator it2 = c2.iterator();
        while (it2.hasNext()){
            Object o = it2.next();
            //删除元素
            //删除元素之后,集合的结构发生了变化,应该重新去获取迭代器
            //但是,循环下一次的时候并没有重新获取迭代器,所以会出现异常:ConcurrentModificationException
			//出异常根本原因:集合中元素删除了,但是没有更新迭代器
            c2.remove(o);//直接通过集合删除元素,没有通知迭代器。(导致迭代器的快照和原集合状态不同)
            System.out.println(o);
        }
    }
}

在这里插入图片描述

 

import java.util.ArrayList;
import java.util.List;

//List的特点:
//        有序可重复
//      有序:添加顺序和取出顺序一致
//      可重复:就是有可重复的数据
//ArrayList: 底层是个object数组,查改效率高,增删效率低
//LinkedList:底层是一个双向链表,增删效率高,查改效率低
public class Collection_3_List {
    public static void main(String[] args) {
//        创建对象
        List list = new ArrayList();
        list.add(100);
        list.add(123);
        //[100, 123]覆写了ToString方法
        System.out.println(list);
    }
}

在迭代集合元素的过程中,不能调用集合对象的remove方法,删除元素:c.remove(o);
迭代过程中不能这样,会出现:ConcurrentModificationException

注意:

迭代集合元素的过程当中,一定要使用迭代器Iterator的remove方法,删除元素,不要使用集合自带的remove方法删除元素。

可以使用Iterator的remove方法: 

it2.remove();//删除的一定是迭代器指向的当前元素。
 

 12.list接口的特点

list集合存储元素的特点:有序可重复

  • 有序:List集合中的元素有下标。从0开始,以1递增
  • 可重复:存储1,还可以再存储1

13.List接口的常用方法

1、在集合末尾添加元素:void add(Object element)

2、在指定下标添加元素:void add(int index , Object element)

 这个方法使用不多,因为对于ArrayList集合来说效率较低。

 3、根据下标获取元素:Object get(int index)

因为有下标,所以List集合有自己比较特殊的遍历方式。

通过下标遍历

for (int i = 0; i < List.size() ; i++){
	Object o = List.get(i);
	System.out.println(o); 
}

4、获取指定对象第一次出现处的索引(下标):int indexof(Object o)

5、获取指定对象最后一次出现处的索引(下标):int lastIndexOf(Object o)

6、删除指定下标位置的元素:Object remove(int index)

7、修改指定下标元素:Object set(int index,Object element)

三、ArrayList集合
ArrayList集合底层采用了数组这种数据结构,底层是Object类型的数组Object []

ArrayList集合是非线程安全的。

数组的优点:检索效率比较高。

数组的缺点:随机增删元素的效率比较低。(向数组末尾添加、删除元素、效率还是很高的)、数组无法存储大数据量(无法找到一块非常巨大的连续的内存空间。)

但是ArrayList集合是往数组末尾添加元素,效率不受影响。
List list1 = new ArrayList();//默认初始化容量为10
List list2 = new ArrayList(20);//指定初始化容量
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
//ArrayList底层是数组,下标从0开始
//默认初始化容量是10 扩大是初始化的1.5倍
//并且默认容量是第一次添加数据的时候设置的
//也就是说 我们 new ArrayList() 的时候,数组长度是为0的
public class Collection_4_List {
    public static void main(String[] args) {
//        创建对象
        List list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        // add(E e ) : 尾部添加
        // add(int index , E e ) : 添加到指定位置
        // set(int index, E e ) : 更改指定位置上的元素值
        // remove(Object object) : 根据元素内容删除
        // remove(int index) : 根据索引删除
        // get(int index) : 获取指定位置的数据
        list.add(1,4);
        list.set(3,44);
        System.out.println(list.get(2));
        list.remove(1);//根据索引删除
        list.remove(new Integer(1));//删除元素值为1
        System.out.println(list);
//        传统遍历
        for (int i = 0;i<list.size();i++){
            System.out.println(list.get(i));
        }
//        foreach遍历
        for (Object obj:list){
            System.out.println(obj);
        }
//        迭代器遍历
        Iterator it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }
}

1、ArrayList集合初始化容量

ArrayList集合默认初始化容量为:10(底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量为10)

 2、ArrayList集合扩容

源代码的grow方法中使用了位运算:int newCapacity = oldCapacity + (oldCapacity >> 1);

10的二进制位:00001010
10的二进制右移1位是:00000101【5】

 结论:一次扩容到原来的1.5倍

建议给定一个预估计的初始化容量,减少数组的扩容次数,这是ArrayList集合比较重要的优化策略。

 3、ArrayList集合的构造方法

第一种方法

List list1 = new ArrayList();
List list2 = new ArrayList(100);

第二种方法:

  • 1、先创建一个HashSet集合
  • 2、将HashSet集合转换为ArrayList集合:List list3 = new ArrayList(c);
Collection c = new HashSet();
c.add(100);
c.add(200);
c.add(300);
c.add(400);

List list3 = new ArrayList(c);

 ArrayList排序

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

//ArrayList排序
public class Collection_5_SortList {
    public static void main(String[] args) {
//        创建对象
        List list = new ArrayList();
        list.add(4);
        list.add(2);
        list.add(15);
        list.add(3);
        list.add(8);
        Collections.sort(list);//调用排序方法
        System.out.println(list);//[2, 3, 4, 8, 15]
    }
}

四、LinkedList集合

LinkedList集合没有初始化容量,且不需要扩容

ListedList底层是一个双向链表

 1、链表的优点

由于链表上的元素在空间存储上内存地址不连续
所以随机增删元素的时候不会有大量元素位移,因此随机增删元素的效率较高。(因为增删元素不涉及到大量元素位移)

 

在以后的开发中,如果遇到随机增删集合中的元素的业务比较多时,建议使用LinkedList。

2、链表的缺点

不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头结点开始遍历,直到找到为止。所以LinkList集合检索/查找的效率较低。 

 查阅效率较低,每一次查找某个元素的时候都需要从头结点开始往下遍历。

JDK5.0之后推出了一个新特性:叫做增强for循环,或者叫做foreach

1、普通遍历数组方法(普通for循环)

 

for(int i = 0 ; i < arr.length ; i++){
	System.out.println(arr[i]);
}

2、增强for(foreach)方法

语法:for(元素类型 变量名:数组或集合) {System.out.println(变量名) }

foreach有一个缺点:没有下标

在需要使用下标的循环中,不建议使用增强for循环。

 

for(int data : arr){
	//data就是数组中的元素(数组中的每一个元素)
	System.out.println(data);
}

 3、集合使用foreach方法

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class forEachText {
    public static void main(String[] args) {
        List<String> l = new ArrayList<>();
        l.add("hello");
        l.add("world!");
        l.add("kitty");

        //用迭代器方式遍历
        Iterator<String> it = l.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }

        //使用下标方式
        for ( int i = 0 ;i < l.size(); i++){
            System.out.println(l.get(i));
        }

        //使用foreach
        for (String s : l){ //因为泛型使用的是String类型,所以是String s
            System.out.println(s);
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

让火车在天上飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值