Java集合

集合

集合概念

对象的容器,实现了对对象常用的操作,类似数组功能。

集合和数组的区别:

  • 数组长度固定,集合长度不固定
  • 数组可以存储基本数据类型和引用类型,集合不能直接存储基本数据类型另外集合也不能直接存储java对象(换句话按说,集合只能存储引用类型)。

位置都在 java.util包里。

java中集合分为两大类

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

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


Collection体系集合

Collection是可迭代的,怎么迭代呢?它继承了Iterable接口,通过调用 **iterator()**方法获得一个Iterator对象,这个Iterator也是个接口,它有诸如hasNext(),next(),remove()等方法可用于遍历集合。

在这里插入图片描述

  • ArrayList: 底层是数组。ArrayList是非线程安全的。

  • LinkedList: 底层是双向链表。

  • Vector: 底层也是数组。Vector是线程安全的,通过查看源码可知,Vector内部也是用数组实现的,并且它的方法都用synchronized修饰了。但是Vector效率较低,现在保证线程安全有别的方案,所有Vector慢慢被弃用了。

  • HashSet: 通过查看源码,实际上HashSet集合在new的时候,底层实际上new了一个HashMap集合。向HashSet集合中存储元素,实际上是存储到HashMap中的key部分了。HashMap集合底层是哈希表数据结构。

  • TreeSet: 通过查看源码,实际上TreeSet集合在new的时候,底层实际上new了一个TreeMap集合。向TreeSet集合中存储元素,实际上是存储到TreeMap中的key部分了。TreeMap集合底层是二叉树数据结构。


Map体系集合

在这里插入图片描述

  • HashMap: 底层是哈希表。非线程安全的。
  • Hashtable: 底层也是哈希表。是线程安全的,但是效率低,使用较少。
  • Properties:是线程安全的(因为继承了Hashtable),并且key和value只能存储字符串String
  • TreeMap:底层是自平衡二叉树。TreeMap集合的key可以自动按照大小顺序排序。

List集合存储元素的特点:有序,可重复。

​ 有序:存进去的顺序和取出的顺序相同,每个元素都有下标。(并不是值的大小有序)

​ 可重复:可以存储多个相同的元素。

Set(Map)集合存储元素的特点:无序,不可重复。

​ 无序:存进去的顺序和取出的顺序不一定相同,另外Set集合中元素没有下标。

​ 不可重复:不能存储2个及以上相同的元素。

SortedSet(SortedMap)是接口,这个集合存储元素特点:由于继承了set集合,所以它的特点也是无序不可重复。但是放在SortedSet集合中的元素可以按照值大小自动排序。我们称为可排序集合。放到该集合中的元素是自动按照大小顺序排序的。

永远要记住:Map集合的key就是一个Set集合。往Set集合放数据,实际上放到了Map集合的key部分。Set家族底层都是调用了Map家族

通过查看源码可知,set的add()方法内实际上是map.put()

在这里插入图片描述

注意,集合不止上面列出的那几种,这些只是常用的。它包括的东西很多很多,面试的时候只答这几个是不行的。

Collection接口

常用方法:

  1. boolean add(Object e): 向集合中添加元素。
//Collection c = new Collection();  接口是抽象的,无法实例化。
//多态
Collection c = new ArrayList();
c.add(1200);//自动装箱,实际上是放进去了一个对象的内存地址Integer x = new Integer(1200)
c.add(true);//自动装箱
c.add(3.14);//自动装箱
c.add(new Student());//自动装箱
System.out.println("集合中元素个数:"+c.size);
c.clear();//清空集合

//对Collection集合进行遍历/迭代
Interator it = c.iterator();//1.获取集合对象的迭代器对象Iterator
while(it.hasNext()){//2.判断有没有
    Object obj = it.next();//3.取对象。不管当初你存进去的是什么,取出来的都是Object
    System.out.println(obj);
}

集合结构只要发生改变,迭代器必须重新获取。否则迭代器会出现异常:java.util.ConcurrentModificationException

例如:

在这里插入图片描述

​ 我们不能在迭代过程中直接调用集合对象来改变集合,要想在迭代过程删除集合元素,只能用迭代器的remove()方法。

​ it2.remove();它会自动删除迭代器当前指向的元素。

在这里插入图片描述

  1. contains()方法:判断是否存在某个元素

在这里插入图片描述

答案是true。为什么? contains底层调了equals()方法,但equals比较的是内存地址啊,x和s1的内存地址不一样啊,为什么会相等?

这里的x是String类型,别忘了String类重写了equals方法,这里进行的是内容比较。所以才会返回true。

在这里插入图片描述

​ 说了这么多,我们要说的是什么?放在集合中的元素,你要重写它的equals方法。

  1. remove()方法

在这里插入图片描述

​ 说明remove()方法底层也调了equals()方法。String类又重写了equals方法。

List接口

  1. List集合存储元素特点:有序,可重复。

    ​ 有序:List集合中元素有下标,从0开始以1递增。

    ​ 可重复:存个1还可以再存1.

    ​ 因为List有下标,所以遍历的时候就不用获取迭代器了,直接通过下标遍历就可以。

  2. List特有常用的方法:(E表示泛型)

    ​ void add(int index,E element):往指定下标加元素

    ​ E set(int index, E element):修改指定下标的元素

    ​ E get(int index):获取指定下标的元素

    ​ int indexOf(Object o):返回集合中第一次改元素的下标

    ​ E remove(int index):删除指定下标的元素

ArrayList类 (重要*)
  • 特点:

    • ArrayList集合底层时Object类型的数组Object[]
    • ArrayList默认初始化容量是10
    • 非线程安全的
    • 数组的优点:检索效率高。
    • 数组缺点:随机增删效率较低,但向末尾添加元素,效率还是很高的。不能存储大数据量,因为很难找到一块足够大的连续的空间。
  • ArrayList集合的扩容,当集合达到设置容量,它会自动扩容。变为原容量的1.5倍

    • 因为ArrayList底层是数组,因为数组扩容效率较低,尽可能少扩容,建议使用Arraylist的时候预估元素个数给定初始化容量。这是ArrayList集合比较重要的优化策略。
  • 这么多的集合中,你用哪个最多?ArrayList

    • 因为大部分情况下我们做检索操作比较多,ArrayList检索效率比较高,并且往ArrayList末尾增删元素,效率不受影响。
  • ArrayList另一个构造方法:直接传一个集合对象

    • Collection c = new HashSet();
      c.add(1);
      c.add(2);
      List lst = new ArrayList(c);//通过这个方法就可以把set集合转换为list集合
      
  • 遍历ArrayList集合的三种方式:

在这里插入图片描述

LinkedList类

LinkedList底层是双向链表。尽管他是链表,因他继承了List,所以LinkedList也是有下标的。

注意:ArrayList之所以检索效率高,不单纯因为下标,而是底层数组发挥的作用。

LinkedList照样有下标,但是检索效率比较低,因为只能从头结点开始遍历。

在这里插入图片描述

  • 单链表

在这里插入图片描述

  • 双链表

在这里插入图片描述

Vector类
  • 底层也是数组
  • 初始化容量10
  • 满了后扩容,怎么扩容的?扩容后是原容量的2倍
  • Vector所有方法都是线程同步的,都带有Synchronized关键字,是线程安全的。
  • 效率较低,不常用。

在这里插入图片描述

泛型
  • 使用泛型的好处:
    • 集合中存储的元素类型同一了
    • 从集合取出的元素类型是泛型指定的类型,不需要进行大量的向下转型。
  • 泛型的缺点:
    • 导致集合中存储的元素缺乏多样性。

JDK1.8之后,支持钻石表达式,即右边new的时候不用重复指定泛型了

在这里插入图片描述

Map接口

  • Map和Collection没有继承关系

  • Map集合以key和value的方式存储数据:键值对

    • key和value都是引用数据类型
    • key和value都是存储对象的内存地址。
    • key起主导地位,value是key的一个附属品
  • Map接口常用方法:

    • V put(K key,V value) 向Map集合中添加键值对

    • V get (Object key) 通过key获取value

    • void clear() 清空集合

    • boolean containsKey(Object key) 判断Map是否含有key

    • boolean containsValue(Object value) 判断Map是否包含某value

    • boolean isEmpty() 判断Map是否为空

    • Set keySet() 获取Map中所有的key(是一个set集合)

    • Collection values() 获取Map集合中所有的value(返回一个collection)

    • V remove(Object key) 通过key删除键值对

    • int size() 获取Map集合中所有键值对的个数

    • Set<Map.Entry<K,V>> entrySet() 将Map集合转换成set集合

    在这里插入图片描述

  • 遍历Map集合

    • 第一种方式:先拿到map集合的所有key,通过遍历key来遍历map

      ​ 可以用迭代器或者增强for:
      在这里插入图片描述

    • 第二种方式: 把map集合直接全部转换成set集合

      在这里插入图片描述

      ​ 同样迭代器、foreach均可:

      在这里插入图片描述

HashMap类
  • HashMap底层数据结构是哈希表
  • 哈希表是一个怎样的数据结构呢?
    • 哈希表是一个数组和单向链表的结合体。
    • 数组在查询方面效率很高,增删方面效率很低。
    • 单向链表在增删方面效率很高,查询方面效率很低。
    • 哈希表将以上两种数据结构融合在一起,充分发挥他们各自的优点。

在这里插入图片描述

扩容之后的容量是原容量的2倍

  • HashMap底层结构图:

在这里插入图片描述

注意:JDK8之后,如果哈希表单向链表中元素个数超过8个,单向链表会变成红黑树,当红黑树上节点数量小于6时,会重新把红黑树变成单向链表。这种方式也是为了提高检索效率。

Hashtable
  • Hashtable和HashMap一样,底层数据结构都是Hash表
  • Hashtable方法都带有synchronized:是线程安全的。
  • Hashtable效率较低,使用较少
  • Hashtable的初始化容量是11,默认加载因子0.75扩容为原来的2倍 + 1
Properties
  • Properties是一个Map集合,继承Hashtable,因此是线程安全的
  • Properties的key和value都只能是String类型
  • Properties被称为属性类对象。

TreeSet

  • TreeSet集合底层实际上是一个TreeMap

  • TreeMap集合底层数据结构是自平衡二叉树

  • 放到TreeSet集合中的元素,等于放到TreeMap集合中key部分了

  • TreeSet集合中的元素:无序,不可重复,但是可以按照元素大小顺序自动排序。称为可排序集合.

  • 对于自定义类型的元素(如自定义的类)来说,TreeSet可以排序吗?

    • 无法排序!因为没有指定对象之间的比较规则,谁大谁小并未说明。
  • 如何让TreeSet对自定义元素也能自动排序呢?有两种方法。

    • ①你自定义的类就要实现Compareble接口,并重写compareTo方法来指明比较规则。equals方法就不用重写了。

在这里插入图片描述

  • calss Customer implements Comparable<Customer>{
        int age;
        public Customer(int age){
            this.age  = age;
        }
        /*
        需要在这个方法中编写比较规则,按照说明来比较
        k.compareTo(t.key)
        拿着k和集合中的每个key进行比较,返回值可能>0,<0,=0
        比较规则最终还是由程序员指定的。
        */
        @Override
        public int comparTo(Customer c){//c1.comparTo(c2)
            return this.age - c.age;
        }
        public String toString(){
        	return "Customer:age="+age;  
    	}
    }
    
  • 自平衡二叉树结构:

在这里插入图片描述

  • 这样通过中序遍历自平衡二叉树,得到的结果就是一个自动按照大小有序的集合。

  • ②第二种方式,使用比较器:

在这里插入图片描述

  • 也可以不写比较器类,直接用匿名内部类

在这里插入图片描述

  • 结论:让TreeSet对自定义类型元素也能自动排序有两种方式:

    • 第一种,放到TreeSet中的元素实现java.lang.Comparable接口。
    • 第二种,在构造TreeSet或者TreeMap集合的时候传一个比较器。(当然我们要手写一个比较器,比较器实现java.util.Comparator接口)

Collections (集合工具类)

集合工具类方便集合操作。

在这里插入图片描述

对List集合中元素排序,需要保证List集合中元素实现了:Comparable接口。

在这里插入图片描述

从sort方法我们可知sort()接受的参数是List,那Collections工具类对Set集合怎么排序呢?

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值