Java 集合

1.常用集合的分类:

Collection 接口的接口 对象的集合(单列集合)
├——-List 接口:元素按进入先后有序保存,可重复
│—————-├ LinkedList 接口实现类, 链表, 插入删除, 没有同步, 线程不安全
│—————-├ ArrayList 接口实现类, 数组, 随机访问, 没有同步, 线程不安全
│—————-└ Vector 接口实现类 数组, 同步, 线程安全
│ ———————-└ Stack 是Vector类的实现类
└——-Set 接口: 仅接收一次,不可重复,并做内部排序
├—————-└HashSet 使用hash表(数组)存储元素
│————————└ LinkedHashSet 链表维护元素的插入次序
└ —————-TreeSet 底层实现为二叉树,元素排好序

Map 接口 键值对的集合 (双列集合)
├———Hashtable 接口实现类, 同步, 线程安全
├———HashMap 接口实现类 ,没有同步, 线程不安全-
│—————–├ LinkedHashMap 双向链表和哈希表实现
│—————–└ WeakHashMap
├ ——–TreeMap 红黑树对所有的key进行排序
└———IdentifyHashMap

集合和数组的区别:


List接口下面有很多的集合,他们存储元素的时候,使用的结构方式是不同的,这样导致
每一个集合有着不同的特点
    数据存储的常用的结构有:堆栈,队列,数组,链表。
    堆栈:采用这个结构的集合,对元素的存取的特点是:
        先进后出(即,先存进去的元素,要在它后面的元素依次被取出来之后,才会被取出)
        比如:子弹压进弹夹,先放进去的子弹,在最下面,等开枪的时候,最后一粒被压进去的子弹第一个打出
        特点:
            栈的入口和出口都在顶端位置
        压栈:
            就是存储元素,即把元素存储到站顶端的位置,栈中已有的元素依次向栈底的方向移动一个位置
        弹栈:
            就是取元素,即,把栈顶的元素取出来,栈中已有的元素依次向上移动一个位置

 

/**
 * 使用LinkedList进行栈的模拟(栈的特点,先进后出)
 */
public class MyStack {
    //存储元素的集合,底层使用双向链表进行实现
    LinkedList<String> list = new LinkedList<String>();
    //模拟进栈
    public void push(String e){
        list.addFirst(e);//将新的元素添加到栈顶
    }

    //模拟出栈
    public String pop(){
        return list.removeFirst();//删除栈顶元素
    }

    public static void main(String[] args) {
        MyStack ms = new MyStack();
        ms.push("张三");//张三进栈
        ms.push("李四");//李四进栈
        ms.push("王五");//王五进栈

        //出栈
        while (ms.list.size() != 0){
            System.out.println(ms.pop());
        }

    }
}
    队列,采用这个结构的集合
        先进先出(即,先存进去的元素,会先被取出来)
        安检的时候,只有前面的人都被检查完了,当前位置的人才能检查
        队列的入口和出口在不同的位置

/**
 * 进行队列的模拟
 */
public class MyQueue {
    private LinkedList<String> list = new LinkedList<String>();

    //进队列,队尾进行插入操作
    public boolean offer(String element){
        return list.offer(element);
    }

    //出队列,对头进行删除操作
    public String poll(){
        return list.poll();
    }

    public static void main(String[] args) {
        MyQueue myQueue = new MyQueue();
        myQueue.offer("a");
        myQueue.offer("b");
        myQueue.offer("c");

        while (myQueue.list.size() != 0){
            System.out.println(myQueue.poll() + "出队列");
        }
    }
}
    数组:
        特点:
            查找元素的时候比较快:是通过索引进行快速访问指定位置的元素
            增删比较慢:
                指定索引位置增加元素,需要创建一个新的数组,将指定的新元素存储在指定索引位置,
                再把原来数组元素根据索引赋值到新数组对应的索引位置

                删除指定索引位置的元素,需要先创建一个新的数组,把原来的数组根据索引赋值到新数组
                对应的索引的位置,原数组中指定索引位置的元素,不进行新的赋值

public class Demo_01 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList(100);
        arrayList.add("1");
        arrayList.add(3.33);
        System.out.println(arrayList.size());

        ArrayList a = new ArrayList();
        a.add(1);
        a.add(2);
        a.add(3);
        a.add(4);
        a.add(1);
        a.add(2);
        a.add(3);

        ArrayList b = new ArrayList(a);
        b.add(9);

        System.out.println(b.size());

    }
}
    链表:
        多个节点之间,通过地址进行连接.
            举例:多个人手拉手,每个人使用自己的右手拉住下一个人的左手,以此类推将元素连接在一起
        特点:
            查找元素比较慢
                想要查找某一个元素,需要通过连接的节点,依次向后查找指定的元素
            增删元素比较快
                增删元素只需要修改下一个元素的地址就可以了
/**
 * HashSet是保证元素的唯一性,可以将元素放入到集合中但是没有顺序,我们现在如果想要
 * 元素有顺序
 * LinkedHashSet:可以帮我们完成set集合有序的操作
 * 底层:链表 + hash
 */
public class LinkedHashSetDemo {
    public static void main(String[] args) {
        //原始元素:{11,22,33,11,16,11,19,51,44,11,66,77}
        //得到元素:{11,22,33,16,19,51,44,66,7}
        //要求去掉重复之后保留原来的顺序
        //首先将信息给到List集合中
        List<Integer> hashSet = new ArrayList<Integer>();
        hashSet.add(11);hashSet.add(22);
        hashSet.add(33);hashSet.add(11);
        hashSet.add(16);hashSet.add(11);
        hashSet.add(19);hashSet.add(51);
        hashSet.add(44);hashSet.add(11);
        hashSet.add(66);hashSet.add(77);
        System.out.println(hashSet);

        //将List集合中的元素放入到LinkedHashSet中
        LinkedHashSet<Integer> set = new LinkedHashSet<Integer>(hashSet);
        System.out.println(set);

        LinkedHashSet<Integer> set1 = new LinkedHashSet<Integer>();
        set1.add(111);
        set1.add(121);
        set1.add(122);
        set1.add(131);
        set1.add(101);
        set1.add(1);
        set1.add(11);
        System.out.println(set1);



    }
}

Collection(单列集合 单身) 一个元素
Map(双列集合 情侣) 元素是成对出现的,每个元素有键和值两部分组成

map存储元素的时候以键值对的形式
    键 key 不可以重复
    值 value 可以重复

查看API可以发现Map有很多实现类,学习中常见的实现类是:
    1、HashMap<K,V>
    2、Hashtable<K,V>
    3、LinkedHashMap<K,V>:是HashMap的子类,在HashMap的基础上保存了元素的链式存储记录存储顺序
    4、TreeMap<K,V>:需要对存储的数据进行自定义的排序

    注意:
        Map有两个泛型<K,V> 在使用的时候需要为它们提供指定的数据类型
        K,V数据类型可以一样,也可以不一样

    get(Object key) 根据键来获取对应的值
    put(K key,V value) 向map集合中存入值
    remove(Object key) 根据键来删除键值对
    replace(K key,V value) 使用新的值替换指定的key的值
    size() map集合中的键值对数
    boolean containsKey(Object key) 如果此映射包含指定键的映射,则返回 true 。
    boolean containsValue(Object value) 如果此地图将一个或多个键映射到指定的值,则返回 true 。
    boolean isEmpty() 如果此地图不包含键值映射,则返回 true。

    遍历map集合中的数据
    方式1:
        先获取所有的key,在调用get根据key获取值
        Set<K> keySet() 返回此地图中包含的键的Set视图。
    方式2:
        直接获取键值对:
         Set<Map.Entry<K,V>> entrySet() 返回此地图中包含的映射的Set视图。
    方式3:
        不能获取key,只能获取所有的值的方法
        Collection<V> values() 返回此地图中包含的值的Collection视图。
public class MapDemo {
    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<Integer, String>();
        map.put(1,"哈士奇");
        map.put(2,"泰迪");
        map.put(3,"藏獒");
        map.put(4,"博美");
        System.out.println(map);
        //key重复,后面的key的值会覆盖掉前面的相同的key的值
        map.put(2,"中华田园犬");
        System.out.println(map);
        //value可以重复
        map.put(5,"藏獒");
        System.out.println(map);

        //获取指定的键对应的值
        //如果键不存在,则输出null
        String v1 = map.get(6);
        System.out.println(v1);

        //清除集合中的元素
        //map.clear();
        System.out.println(map);

        //将5改成拉布拉多
        map.replace(5,"拉布拉多");
        System.out.println(map);

        //获取集合中的所有的键值对
        System.out.println(map.size());

        //判断map集合中是否包含key为3的键值对
        boolean f = map.containsKey(3);
        System.out.println(f);

        boolean b = map.containsValue("比熊");
        System.out.println(b);


        //如何遍历map集合
        //方式1:
        //        先获取所有的key,在调用get根据key获取值
        //        Set<K> keySet() 返回此地图中包含的键的Set视图。
        System.out.println("---------第一种方式----------");
        Set<Integer> set = map.keySet();
        //对集合进行遍历
        for(Integer key : set){
            //根据键来找值
            String value = map.get(key);
            System.out.println(key + " ==== " + value);
        }

        //方式2:
        //        直接获取键值对:
        //         Set<Map.Entry<K,V>> entrySet() 返回此地图中包含的映射的Set视图。
        System.out.println("---------第二种方式----------");
        Set<Map.Entry<Integer,String>> set1 = map.entrySet();
        for(Map.Entry<Integer,String> entry : set1){
            System.out.println(entry);
            Integer key = entry.getKey();
            String value = entry.getValue();
        }

        //方式3:
        //      不能获取key,只能获取所有的值的方法
        //        Collection<V> values() 返回此地图中包含的值的Collection视图。
        System.out.println("---------第三种方式----------");
        Collection<String> value = map.values();
        System.out.println(value);

    }
}

    Hashtable
    HashMap、Hashtable
        相同点:
            实现的原理相同,功能相同,底层都是哈希表的结构
            同样每个元素都是key - value,其内部也是通过链
            表解决冲突问题,当容量不足的时候,会自动进行增加
        不同点:
            1、jdk1.0版本开始的时候 Hashtable    基本已经废弃使用了
               jdk1.2HashMap出现                 常用HashMap
            2、Hashtable 继承 Dictionary类  是一个抽象类,已经过时了
               HashMap 实现了Map接口
            3、Hashtable 线程安全
               HashMap 线程不安全,用在单线程的情况下
            4、Hashtable 不允许有null键和null值,如果有会抛出空指针异常
               HashMap中可以存储null键和null值
            5、Hashtable 比 HashMap多了一种遍历的方式
public class HashtableDemo {
    public static void main(String[] args) {
        Hashtable<String,String> table = new Hashtable<String, String>();
        table.put("admin","123456");
        //凡是出现了空键或者空值,就会出现空指针异常
        //table.put("admin2",null);
        //table.put(null,"123456");
        System.out.println(table);

        //Hashtable使用枚举遍历
        Enumeration<String> e = table.elements();
        while (e.hasMoreElements()){//判断是否有更多的元素
            String key = e.nextElement();//取出这个元素
            String value = table.get(key);
            System.out.println(key + " ===== " + value);
        }
    }
}
/**经典题目
 * 键盘输入一个字符串,统计该字符串中各个字符的个数
 * 比如:
 *      输入:aaaabbbcc
 *      输出:a(4)b(3)c(2)
 */
public class Demo_01 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("键盘输入:");
        String input = scanner.nextLine();
        //aaaabbbcc
        //创建了一个集合用来存储字符和出现的次数
        HashMap<Character,Integer> map = new HashMap<Character, Integer>();
        for(int i = 0; i < input.length();i++){
            char key = input.charAt(i);
            //根据ket找到这个字符原来的个数
            //调用get方法如果key不存在就返回为null
            //如果key存在就获取到key所对应的value值
            int oldCount = map.getOrDefault(key,0);
            //如果有这样一个元素,我就将集合中的固定的key后面对应的值加1
            map.put(key,oldCount+1);
            System.out.println(map);
        }
        //获取到map集合中所有的键集
        Set<Character> set = map.keySet();
        //遍历集合中的键然后根据键去找值
        for(Character c : set){
            System.out.println(c + "(" + map.get(c) + ")");
        }
    }
}

总结:

List小结:
(1)ArrayList:底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素
(2)LinkedList 底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素
(3)Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素这里写图片描述

List和Set总结:
(1)、List,Set都是继承自Collection接口,Map则不是
(2)、List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)
(3).Set和List对比:
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
(4)、ArrayList与LinkedList的区别和适用场景
Arraylist:
优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。

LinkedList:
优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景
缺点:因为LinkedList要移动指针,所以查询操作性能比较低。
适用场景分析:
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。

Map小结:
HashMap 非线程安全
HashMap:基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()],为了优化HashMap空间的使用,您可以调优初始容量和负载因子。

TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。

适用场景分析:
HashMap和HashTable:HashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。HashMap允许空键值,而HashTable不允许。

HashMap:适用于Map中插入、删除和定位元素。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。

5.线程安全集合类与非线程安全集合类
LinkedList、ArrayList、HashSet是非线程安全的,Vector是线程安全的;
HashMap是非线程安全的,HashTable是线程安全的;
StringBuilder是非线程安全的,StringBuffer是线程安全的。

数据结构
ArrayXxx:底层数据结构是数组,查询快,增删慢
LinkedXxx:底层数据结构是链表,查询慢,增删快
HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals()
TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小猿king

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

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

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

打赏作者

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

抵扣说明:

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

余额充值