集合(Collection、List、Map)

集合

在编程时,可以使用数组来保存多个对象,但数组长度不可变化,一旦在初始化数组时指定了数组长度,这个数组长度就是不可变的。如果需要保存数量变化的数据,数组就有点无能为力了。而且数组无法保存具有映射关系的数据,如成绩表为语文——79,数学——80,这种数据看上去像两个数组,但这两个数组的元素之间有一定的关联关系。

为了保存数量不确定的数据,以及保存具有映射关系的数据(也被称为关联数组),Java 提供了集合类。集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。Java 所有的集合类都位于 java.util 包下,提供了一个表示和操作对象集合的统一构架,包含大量集合接口,以及这些接口的实现类和操作它们的算法。

集合类和数组不一样,数组元素既可以是基本类型的值,也可以是对象(实际上保存的是对象的引用变量),而集合里只能保存对象(实际上只是保存对象的引用变量,但通常习惯上认为集合里保存的是对象)。

Java 集合类型分为 Collection Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口或实现类。图 1 和图 2 分别为 Collection 和 Map 的子接口及其实现类。
图1|
—|–
|图 1 Collection接口基本结构|

在这里插入图片描述|
—|–
|图 2 Map接口基本结构|

在 图 1 和图 2 中,黄色块为集合的接口,蓝色块为集合的实现类。表 1 介绍了这些接口的作用。

表 1 Java集合接口的作用
接口名称作 用
Iterator 接口集合的输出接口,主要用于遍历输出(即迭代访问)Collection 集合中的元素,Iterator 对象被称之为迭代器。迭代器接口是集合接口的父接口,实现类实现 Collection 时就必须实现 Iterator 接口。
Collection 接口List、Set 和 Queue 的父接口,是存放一组单值的最大接口。所谓的单值是指集合中的每个元素都是一个对象。一般很少直接使用此接口直接操作。
Queue 接口Queue 是 Java 提供的队列实现,有点类似于 List。
Dueue 接口是 Queue 的一个子接口,为双向队列。
List 接口是最常用的接口。是有序集合,允许有相同的元素。使用 List 能够精确地控制每个元素插入的位置,用户能够使用索引(元素在 List 中的位置,类似于数组下标)来访问 List 中的元素,与数组类似。
Set 接口不能包含重复的元素。
Map 接口是存放一对值的最大接口,即接口中的每个元素都是一对,以key➡value的形式保存。

对于 Set、List、Queue 和 Map 这 4 种集合,Java 最常用的实现类分别是 HashSet、TreeSet、ArrayList、ArrayDueue、LinkedList 和 HashMap、TreeMap 等。表 2 介绍了集合中这些常用的实现类。

表 2 Java集合实现类的作用
类名称作用
HashSet 为优化査询速度而设计的 Set。它是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,实现比较简单
TreeSet实现了 Set 接口,是一个有序的 Set,这样就能从 Set 里面提取一个有序序列
ArrayList一个用数组实现的 List,能进行快速的随机访问,效率高而且实现了可变大小的数组
ArrayDueue 是一个基于数组实现的双端队列,按“先进先出”的方式操作集合元素
LinkedList对顺序访问进行了优化,但随机访问的速度相对较慢。此外它还有 addFirst()、addLast()、getFirst()、getLast()、removeFirst() 和 removeLast() 等方法,能把它当成栈(Stack)或队列(Queue)来用
HsahMap按哈希算法来存取键对象
TreeMap可以对键对象进行排序

1、Collection接口

Java语言的java.util包中提供了一些集合类,这些集合类又称之为容器
提到容器不难想到数组,集合类与数组最主要的不同之处是,数组的长度是固定的,集合的长度是可变的,而数组的访问方式比较单一,插入/删除等操作比较繁琐,而集合的访问方式比较灵活
在这里插入图片描述在这里插入图片描述

1.1集合间的继承关系在这里插入图片描述

Collection和Map最大的区别就是Collection存储的是一组对象;Map是以“键值对”的形式对对象进行的管理。

1.2 Collection方法

返回值方法方法描述
booleanadd(E e)确保此集合包含指定的元素(可选操作)。
booleanaddAll(Collection<? extends E> c)将指定集合中的所有元素添加到此集合 (可选操作)
voidclear()从此集合中删除所有元素(可选操作)。
booleancontains(Object o)如果此集合包含指定的元素,则返回 true 。
booleancontainsAll(Collection<?> c)如果此集合包含指定 集合中的所有元素,则返回true。
booleanequals(Object o)将指定的对象与此集合进行比较以获得相等性。
inthashCode()返回此集合的哈希码值。
booleanisEmpty()如果此集合不包含元素,则返回 true 。
Iteratoriterator()返回此集合中的元素的迭代器。
default StreamparallelStream()返回可能并行的 Stream与此集合作为其来源。
booleanremove(Object o)从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
booleanremoveAll(Collection<?> c)删除指定集合中包含的所有此集合的元素(可选操作)。
default booleanremoveIf(Predicate<? super E> filter)删除满足给定谓词的此集合的所有元素。
booleanretainAll(Collection<?> c)仅保留此集合中包含在指定集合中的元素(可选操作)。
intsize()返回此集合中的元素数。
Object[]toArray()返回一个包含此集合中所有元素的数组。

1.3测试Collection接口

package cn.tedu.collection;

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

/*本类用于测试Collection接口*/
public class TestCollection {
    public static void main(String[] args) {
        Collection<Integer> c=new ArrayList();
        c.add(100);
        c.add(200);
        c.add(300);
        c.add(400);
        c.add(500);
        System.out.println(c);
        /*clear()--清空集合*/
        //c.clear();
        System.out.println(c.hashCode());//打印集合的哈希码值
        System.out.println(c.equals(200));//false 集合对象与集合中的某个元素
        System.out.println(c);//打印的是集合中的具体元素
        
        /*contains()--判断是否包含指定元素*/
        System.out.println(c.contains(200));//判断集合中是否包含指定元素200
        /*isEmpty()--判断集合是否为空*/
        System.out.println(c.isEmpty());//判断集合是否为空
        /*remove()--删除集合中的指定元素*/
        System.out.println(c.remove(100));//删除集合中的指定元素
        /*size()--集合中元素的个数*/
        System.out.println(c.size());//集合中元素的个数
        /*toArray()--返回一个包含此集合中所有元素的数组。*/
        Object[] array= c.toArray();
        System.out.println(Arrays.toString(array));

        Collection<Integer> c2=new ArrayList<>();
        c2.add(66);
        c2.add(99);
        c2.add(88);
        System.out.println(c2);
        
        /*addAll()--将指定集合中的所有元素添加到此集合*/
        c.addAll(c2);//将c2集合中的所有元素添加到c集合中
        System.out.println(c);
        System.out.println(c2);
        /*containsAll()--如果此集合包含指定集合中的所有元素,则返回true。*/
        System.out.println(c.containsAll(c2));//判断c集合中是否包含c2集合中的所有元素
        /*removeAll()--删除指定集合中包含的所有此集合的元素*/
        System.out.println(c.removeAll(c2));

        System.out.println(c2);//[66, 99, 88]
        System.out.println(c.add(66));//[200, 300, 400, 500, 66]
        System.out.println(c.retainAll(c2));//保留c中属于c和c2集合的公共元素。取其交集
        System.out.println(c);//[66]

        /*集合迭代步骤:
        * 1.获取迭代器 集合名.iterator();
        * 2.通过迭代器判断集合中是否有下一个元素可以迭代  迭代器.hasNext()
        * 3.获取当前迭代到的元素
        * 注意:迭代器的泛型取决于要迭代的集合泛型,比如c2是Integer
        * */
        Iterator<Integer> it = c2.iterator();
        while (it.hasNext()){
            Integer num = it.next();
            System.out.println(num);
        }
    }
}

泛型

Collection<Integer> c=new ArrayList();
Iterator<Integer> it = c2.iterator();

<?>的部分就是泛型,泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。

也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

2 List接口

有序的colletion(也称为序列).此接口的用户可以对列表中的每个元素的插入位置进行精确的控制,用户可以根据元素的整数索引(在列表中的位置)来访问元素,并搜索列表中的元素.

List 是一个有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List 集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。List 集合默认按元素的添加顺序设置元素的索引,第一个添加到 List 集合中的元素的索引为 0,第二个为 1,依此类推。

List 实现了 Collection 接口,它主要有两个常用的实现类:ArrayList 类和 LinkedList 类。

2.1 ArrayList类

2.1.1特点:

  1. List接口的实现类
  2. 底层的数据结构是数组,内存空间是连续
  3. 内部数组默认的初始容量是10,如果不够会以1.5倍的容量增长
  4. 元素有下标、有序、允许存放重复的元素
  5. 可以根据下标进行操作
  6. 增删操作比较慢,查询操作比较快 [数据量比较大时]

2.1.2构造方法

  1. ArrayList()----构造一个初始容量为10的空列表
  2. ArrayList(Collection<? extends E> c) ----构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
  3. ArrayList(int initialCapacity) ----构造具有指定初始容量的空列表。

2.1.3方法摘要

返回值方法方法描述
booleanadd(E e)将指定的元素追加到此列表的末尾。
voidadd(int index, E element)在此列表中的指定位置插入指定的元素。
booleanaddAll(Collection<? extends E> c)按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。
booleanaddAll(int index, Collection<? extends E> c)按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。
voidclear()从列表中删除所有元素。
booleancontains(Object o)如果此集合包含指定的元素,则返回 true 。
Eget(int index)返回此列表中指定位置的元素。
intindexOf(Object o)返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
booleanisEmpty()如果此列表不包含元素,则返回 true 。
Iteratoriterator()以正确的顺序返回该列表中的元素的迭代器。
intlastIndexOf(Object o)返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
ListIteratorlistIterator()返回列表中的列表迭代器(按适当的顺序)。
ListIteratorlistIterator(int index)从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。
Eremove(int index)删除该列表中指定位置的元素。
booleanremove(Object o)从列表中删除第一个出现的指定元素(如果存在)。
booleanremoveAll(Collection<?> c)从此列表中删除指定集合中包含的所有元素。
booleanremoveIf(Predicate<? super E> filter)删除此集合与给定集合的元素相同的所有元素。
protected voidremoveRange(int fromIndex, int toIndex)从这个列表中删除所有索引在 fromIndex (含)和 toIndex之间的元素。
booleanretainAll(Collection<?> c)仅保留此列表中包含在指定集合中的元素。
Eset(int index, E element)用指定的元素替换此列表中指定位置的元素。
intsize()返回此列表中的元素数
voidsort(Comparator<? super E> c)使用提供的 Comparator对此列表进行排序以比较元素。
Object[]toArray()以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。
voidtrimToSize()修改这个 ArrayList实例的容量是列表的当前大小。

2.1.4方法测试

package cn.tedu.collection;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

/*本类用于ArrayList的相关测试*/
public class TestArrayList {
    public static void main(String[] args) {
        /*底层会自动帮我们创建数组用于存放对象,并且数组的初始容量为10*/
        ArrayList<Integer> list=new ArrayList<>();
        //LinkedList<Integer> list=new LinkedList<>();
        list.add(100);
        list.add(200);
        list.add(300);
        list.add(400);
        list.add(300);
        System.out.println(list);
        //常用方法
        //list.clear();//清空集合
        /*contains(Object o)--如果此列表包含指定的元素,则返回 true 。 */
        System.out.println(list.contains("100"));//是否包含String类型的元素

        /*get(int index)--返回此列表中指定位置的元素。 */
        System.out.println(list.get(0));//获取下标为0的元素

        /*indexOf(Object o)--返回此列表中指定元素的第一次出现的索引,如果此列表不包含该元素,则返回-1。 */
        System.out.println(list.indexOf(300));//获取该元素第一次出现的位置

        /*lastIndexOf(Object o)--返回此列表中指定元素的最后一次出现的索引,如果此列表不包含该元素,则返回-1。*/
        System.out.println(list.lastIndexOf(300));//获取该元素最后一次出现的位置

        /*remove(int index)--删除该列表中指定下标的元素。 */
        System.out.println(list.remove(1));//根据下标删除集合中的指定元素

        /*remove(Object o)--从列表中删除指定的第一个出现的元素(如果存在).*/
        list.remove(Integer.valueOf(300));//如果想要根据指定元素删除数据,需要把int类型的数据手动装箱成Integer

        System.out.println(list.size());//获取集合的元素个数
        list.set(2,777);//修改下标为2的元素,值为777

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

        for (Integer a:
             list) {
            System.out.println(a);
        }

        Iterator<Integer> it=list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

        ListIterator<Integer> lit=list.listIterator();
        while (lit.hasNext()){
            System.out.println(lit.next());
        }
    }
}

2.2LinkedList类

2.2.1 特点:

  1. List接口的实现类
  2. 底层数据结构是链表,内存空间不连续
  3. 元素有下标、有序、允许存放重复的元素
  4. 通常进行首尾操作比较多
  5. 增删操作比较快,查询操作比较慢[数据量比较大时]
    注:LinkedList的查询操作并不都慢,首尾操作比较快

2.2.2构造方法:

  1. LinkedList() ---- 构造一个空列表
  2. LinkedList(Collection<? extends E> c) ---- 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。

2.2.3 结构图

在这里插入图片描述

2.2.4方法测试

package cn.tedu.collection;

import java.util.LinkedList;
/*本类用于测试List接口的子实现类LinkedList*/
public class TestLinkedList {
    public static void main(String[] args) {
        LinkedList<String> list =new LinkedList<>();
        list.add("孙悟空");
        list.add("猪八戒");
        list.add("唐三藏");
        list.add("沙师弟");
        list.add("白龙马");
        System.out.println(list);

        /*addFirst(E e)--在该列表开头插入指定的元素。*/
        list.addFirst("蜘蛛精");//添加一个头结点

        /*addLast(E e)--将指定的元素追加到此列表的末尾。*/
        list.addFirst("玉兔精");//向链表添加尾元素
        System.out.println(list.getFirst());//获取头元素
        System.out.println(list.getLast());//获取尾元素

        System.out.println(list.removeFirst());//删除链表的首元素并返回被删元素
        System.out.println(list.removeLast());//删除链表的尾元素并返回被删元素

        LinkedList<String> list2=new LinkedList<>();
        list2.add("水浒传");
        list2.add("三国演义");
        list2.add("西游记");
        list2.add("石头记");
        System.out.println(list2);
        System.out.println(list2.element());//获取首元素

        /*别名:查询系列*/
        System.out.println(list2.peek());//获取首元素
        System.out.println(list2.peekFirst());//获取首元素
        System.out.println(list2.peekLast());//获取尾元素

        /*别名:新增系列*/
        System.out.println(list2.offer("斗罗大陆"));//添加尾元素
        System.out.println(list2.offerFirst("三体"));//添加首元素
        System.out.println(list2.offerLast("蛙"));//添加尾元素
        System.out.println(list2);

        /*别名:移除系列*/
        System.out.println(list2.poll());//删除首元素
        System.out.println(list2.pollFirst());//删除首元素
        System.out.println(list2.pollLast());//删除尾元素
        System.out.println(list2);
    }
}

3 Map接口

3.1 概述

Java.util接口Map<K,V>
类型参数 : K - 表示此映射所维护的键 V – 表示此映射所维护的对应的值
也叫做哈希表、散列表. 常用于键值对结构的数据.其中键不能重复,值可以重复
在这里插入图片描述

3.2 特点

  1. Map可以根据键来提取对应的值

  2. Map的键不允许重复,如果重复,对应的值会被覆盖

  3. Map存放的都是无序的数据

  4. Map的初始容量是16,默认的加载因子是0.75

    在这里插入图片描述

TIPS:源码摘抄:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
初始容量1<<4,相当于1*(2^4),也就是16
static final float DEFAULT_LOAD_FACTOR = 0.75f;
默认的加载因子是0.75f,也就是存到75%开始扩容,按照2的次幂进行扩容

3.3 继承结构

在这里插入图片描述

3.4 常用方法

学习Map接口中的方法即可

  • void clear() 从此映射中移除所有映射关系(可选操作) boolean containsKey(Object key) 如果此映射包含指定键的映射关系,则返回 true
  • boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true
  • Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的 Set 视图
  • boolean equals(Object o) 比较指定的对象与此映射是否相等
  • V get(Object key) 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null
  • int hashCode() 返回此映射的哈希码值
  • boolean isEmpty() 如果此映射未包含键-值映射关系,则返回 true
  • Set keySet() 返回此映射中包含的键的 Set 视图
  • V put(K key, V value) 将指定的值与此映射中的指定键关联(可选操作)
  • void putAll(Map<? extends K,? extends V> m)从指定映射中将所有映射关系复制到此映射中(可选操作)
  • V remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)
  • int size() 返回此映射中的键-值映射关系数
  • Collection values() 返回此映射中包含的值的 Collection 视图

3.5 练习:Map常用方法测试

创建包: cn.tedu.map
创建类: MapDemo.java

package cn.tedu.list;

import java.util.*;

/**本类用于测试Map接口*/
public class MapDemo {
    public static void main(String[] args) {
        //1.创建Map对象
        /**Map中的数据要符合映射规则,一定注意要同时指定K和V的数据类型
         * 至于这个K和V具体要指定成什么类型,取决于具体的业务需求*/
        Map<Integer,String> map = new HashMap<>();//注意导包:java.util
        //2.向map集合存入数据,注意方法是put(),并且需要存入一对<K,V>的值
        map.put(9527,"白骨精");
        map.put(9528,"黑熊精");
        map.put(9529,"鲤鱼精");
        map.put(9530,"黄毛怪");
        map.put(9531,"黑熊精");
        map.put(9527,"女儿国国王");
        /**1.map中存放着的都是无序的数据
         * 2.map中的value可以重复-比如我们可以存两个黑熊精
         * 3.map中的key不允许重复,如果重复,后面的value会把前面的value覆盖掉
         * 比如女儿国国王和白骨精都是9527,白骨精就被覆盖掉了*/
        System.out.println(map);//查看map集合中的数据是否存入成功

        //3.进行方法测试
        //map.clear();//清空集合
        System.out.println(map.hashCode());//获取集合的哈希码
        System.out.println(map.equals("黄毛怪"));//判断“黄毛怪”是否与集合对象相等
        System.out.println(map.isEmpty());//判断集合是否为空
        System.out.println(map.size());//获取集合中元素的个数

        //判断当前map集合中是否包含指定的Key键
        System.out.println(map.containsKey(9527));//true
        //判断当前map集合中是否包含指定的Value
        System.out.println(map.containsValue("白骨精"));//false,因为已被覆盖
        //根据key值获取到对应的value值
        System.out.println(map.get(9530));
        //根据此key值对应的键值对,K与V都删了
        System.out.println(map.remove(9529));
        System.out.println(map.containsKey(9529));
        System.out.println(map.containsValue("鲤鱼精"));

        //将map集合中的所有value取出,放入Collection集合中
        //Collection<Type>中Type的类型,取决于map中value的类型
        Collection<String> values = map.values();
        System.out.println(values);//[女儿国国王, 黑熊精, 黄毛怪, 黑熊精]

        //4.map集合的迭代方式一
        /**方式一:
         * 遍历map中的数据,但是map本身没有迭代器,所以需要先转换成set集合
         * Set<Key>:把map中的所有key值存入到set集合当中--keySet()*/
        //4.1将map集合中的key值取出存入set集合中,集合的泛型就是key的类型Integer
        Set<Integer> keySet = map.keySet();
        //4.2想要遍历集合就需要获取集合的迭代器
        Iterator<Integer> it = keySet.iterator();
        //4.3循环迭代集合中的所有元素
        while(it.hasNext()){//判断是否有下一个元素可以迭代
            Integer key = it.next();//拿到本轮循环中获取到的map的key
            String value = map.get(key);
            System.out.println("{"+key+","+value+"}");
        }

        /**方式二:
         * 遍历map集合,需要把map集合先转成set集合
         * 是把map中的一对键值对key&value作为一个Entry<K,V>整体放入set
         * 一对K,V就是一个Entry*/
        Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
        //获取迭代器
        Iterator<Map.Entry<Integer, String>> it2 = entrySet.iterator();
        while(it2.hasNext()){//判断是否有下一个元素可迭代
            //本轮遍历到的一个Entry对象
            Map.Entry<Integer, String> entry = it2.next();
            Integer key = entry.getKey();//获取Entry中的key
            String value = entry.getValue();//获取Entry中的value
            System.out.println("{"+key+","+value+"}");
        }
    }
}

在这里插入图片描述

4 HashMap

4.1 前言

HashMap的键要同时重写hashCode()和equlas()
hashCode()用来判定二者的hash值是否相同,重写后根据属性生成
equlas()用来判断属性的值是否相同,重写后,根据属性判断
–equlas()判断数据如果相等,hashCode()必须相同
–equlas()判断数据如果不等,hashCode()尽量不同

4.2 HashMap的存储过程:

  1. HashMap的结构是数组+链表 或者 数组+红黑树 的形式
  2. HashMap底层的Entry[ ]数组,初始容量为16,加载因子是0.75f,扩容按约为2倍扩容
  3. 当存放数据时,会根据hash(key)%n算法来计算数据的存放位置,n就是数组的长度,其实也就是集合的容量
  4. 当计算到的位置之前没有存过数据的时候,会直接存放数据
  5. 当计算的位置,有数据时,会发生hash冲突/hash碰撞
  6. 解决的办法就是采用链表的结构,在数组中指定位置处以后元素之后插入新的元素
  7. 也就是说数组中的元素都是最早加入的节点
  8. 如果链表的长度>8且数组长度>64时,链表会转为红黑树,当链表的长度<6时,红黑树会重新恢复成链表
    在这里插入图片描述

4.3 练习:获取HashMap的数据

创建包: cn.tedu.map
创建类: TestHashMap.java

package cn.tedu.collection;

import java.util.HashMap;

/**本类用于HashMap的练习*/
public class TestHashMap {
	public static void main(String[] args) {
		//创建HashMap对象
		HashMap<Integer,String> map = new HashMap();
		/**
		 * 源码摘抄:
		 * static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
		 * 初始容量为1<<4,相当于1*(2^4)=16
		 * static final float DEFAULT_LOAD_FACTOR = 0.75f;
		 * 默认的加载因子是0.75,也就是说存到75%开始扩容,按照2的次幂进行扩容
		 */
		/*
		 * 达到容量的加载因子后,就会重新开辟空间,重新计算所有对象的存储位置,也叫做rehash
		 * 设置初始容量与加载因子要讲求相对平衡,如果加载因子过低,则rehash过于频繁,影响性能
		 * 如果初始容量设置太高或者加载因子设置太高,影响查询效率
		 */
	}
}

4.4 练习:字符串中字符统计

创建包: cn.tedu.map
创建类: TestMap.java

package cn.tedu.map;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/*本类用于练习map案例:统计字符串中字符的个数
* 需求效果:用户输入aabbbcc,输出:a=2,b=3,c=2*/
public class TestMap2 {
    public static void main(String[] args) {
        //1.接收用户输入的字符串
        System.out.println("请您输入要统计的字符串:");
        String input = new Scanner(System.in).nextLine();
        //2.准备一个map集合,用来存放出现的字符Character与字符的个数Integer
        //为什么字符类型Character作为map中的KEY?因为key不允许重复,而次数是可以重复的
        Map<Character,Integer> map = new HashMap<>();

        //3.准备要存入map中的数据:K和V
        //3.1 遍历用户输入的字符串,统计每个字符
        for (int i = 0; i < input.length(); i++) {
            //3.2获取本轮循环中遍历到的字符
            char key = input.charAt(i);
            //System.out.println(key);//打印查看每轮循环获取到的字符,没有问题
            //3.2根据获取到的key拿到对应的value
            Integer value = map.get(key);//根据字符,获取map中这个字符保存的次数
            if(value == null){//之前这个字符没有出现过,次数还是Integer的默认值null
                map.put(key,1);//没有出现过,次数就设置为1
            }else {//value不是null走else
                map.put(key,value+1);//之前这个字符出现过,次数变为之前的次数+1
            }
        }
        System.out.println("各个字符出现的次数为:"+map);
    }
}

5 set接口

在这里插入图片描述

5.1 概述

  1. Set是一个不包含重复数据的Collection
  2. Set集合中的数据是无序的(因为Set集合没有下标)
  3. Set集合中的元素不可以重复 – 常用来给数据去重

5.2 Set集合的特点

  1. 数据无序且数据不允许重复
  2. HashSet : 底层是哈希表,包装了HashMap,相当于向HashSet中存入数据时,会把数据作为K,存入内部的HashMap中。当然K仍然不许重复。
  3. TreeSet : 底层是TreeMap,也是红黑树的形式,便于查找数据

5.3 常用方法

学习Collection接口中的方法即可

5.4 HashSet

5.4.1 概述

底层是哈希表,包装了HashMap,相当于向HashSet中存入数据时,会把数据作为K存入内部的HashMap中,其中K不允许重复,允许使用null.
在这里插入图片描述

在这里插入图片描述

5.5 练习: Set相关测试

创建包: cn.tedu.collection
创建类: TestSet.java

package cn.tedu.collection;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/*本类用于测试Set*/
public class TestSet {
    public static void main(String[] args) {
        //1.创建对应的集合对象
        Set<String> set = new HashSet<>();
        //2.存入数据
        set.add("紫霞仙子");
        set.add("至尊宝");
        set.add("蜘蛛精");
        set.add("紫霞仙子");
        set.add(null);
        /*1.set集合中的元素都是没有顺序的
        * 2.set集合中的元素不能重复
        * 3.set集合可以存null值,但是最多只有一个*/
        System.out.println(set);//[蜘蛛精, null, 至尊宝, 紫霞仙子]

        //3.常用方法测试
        System.out.println(set.contains("唐僧"));//false,判断是否包含指定元素
        System.out.println(set.isEmpty());//false,判断是否为空
        System.out.println(set.remove(null));//true,移除指定的元素
        System.out.println(set);//[蜘蛛精, 至尊宝, 紫霞仙子]
        System.out.println(set.size());//3,获取集合中元素的个数
        System.out.println(Arrays.toString(set.toArray()));//[蜘蛛精, 至尊宝, 紫霞仙子],将集合转为数组

        //4.1创建set2集合,并向集合中存入数据
        Set<String> set2 = new HashSet<>();
        set2.add("小兔纸");
        set2.add("小脑斧");
        set2.add("小海疼");
        set2.add("小牛犊");
        System.out.println(set2);//[小兔纸, 小海疼, 小牛犊, 小脑斧]
        System.out.println(set.addAll(set2));//将set2集合的所有元素添加到set集合中
        System.out.println(set);//[蜘蛛精, 小兔纸, 小海疼, 至尊宝, 小牛犊, 小脑斧, 紫霞仙子]
        System.out.println(set.containsAll(set2));//判断set2集合的所有元素是否都在set集合中
        System.out.println(set.removeAll(set2));//删除set集合中属于set2集合的所有元素
        System.out.println(set);//[蜘蛛精, 至尊宝, 紫霞仙子]
        System.out.println(set.retainAll(set2));//只保留set集合中属于set和set2集合的公共元素
        System.out.println(set);//[]

		//5.集合的迭代
		Iterator<String> it = set2.iterator();//5.1获取集合的迭代器
		while(it.hasNext()) {//5.2判断集合是否有下个元素
			String s = it.next();//5.3如果有,进循环获取当前遍历到的元素
			System.out.println(s);
		}
    }
}

5.6 练习: Set相关测试2

创建包: cn.tedu.collection
创建类: Student.java

package cn.tedu.collection;

import java.util.Objects;

//1.创建自定义引用类型Student
public class Student {
    //2.创建属性
    String name;//姓名
    int id;//学号

    //3.提供本类的全参构造
    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }
    //3.2提供学生类的toString()
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
    //3.3添加学生类重写的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 id == student.id && Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, id);
    }
}

5.6 练习: Set相关测试2

创建包: cn.tedu.collection
创建类: TestSet2.java

package cn.tedu.collection;

import java.util.HashSet;
import java.util.Set;

/*本类用于进一步测试set*/
public class TestSet2 {
    public static void main(String[] args) {
        //4.创建集合对象set
        Set<Student> set = new HashSet<>();

        //5.创建自定义类Student的对象
        Student s1 = new Student("张三",3);
        Student s2 = new Student("李四",4);
        Student s3 = new Student("李四",4);
        //6.将创建好的学生对象存入set集合中
        set.add(s1);
        set.add(s2);
        set.add(s3);
        /*如果set中存放的是我们自定义的类型
        * 需要给自定义类中添加重写的equals()与hashCode(),才会去重
        * 不然会认为s2和s3的地址值不同,是两个不同的对象,不会去重*/
        System.out.println(set);
    }
}

6 拓展

HashMap扩容
成长因子:
static final float DEFAULT_LOAD_FACTOR = 0.75f;
前面的讲述已经发现,当你空间只有仅仅为10的时候是很容易造成2个对象的hashcode 所对应的地址是一个位置的情况。
这样就造成 2个 对象会形成散列桶(链表)。
这时就有一个加载因子的参数,值默认为0.75 ,
如果你hashmap的 空间有 100那么当你插入了75个元素的时候 hashmap就需要扩容了,
不然的话会形成很长的散列桶结构,对于查询和插入都会增加时间,因为它要一个一个的equals比较。
但又不能让加载因子很小,如0.01,这样显然是不合适的,频繁扩容会大大消耗你的内存。
这时就存在着一个平衡,jdk中默认是0.75,当然负载因子可以根据自己的实际情况进行调整。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

java小鲤鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值