Java集合

目录

一、集合的概述

二、集合与数组的区别

1、长度区别

2、内容区别

3、元素区别

4、集合结构

三、集分的分类

1.Java中集合分为两类:

四、集合结构图 

1、Conllection集合结构图

2、Map集合结构图

五、Interator迭代器 

1、迭代器Interator作用

2、迭代器Interator常用方法 

3、迭代器注意事项 

六、Collection(接口)集合常用方法

七、List集合(接口)

 1、List接口特有方法

2、List接口中实现类

2.1 、ArrayList集合

2.2、LinkedList集合

2.3、Vector 集合

八、Set集合(接口)

1、HashSet集合

2、TreeSet集合

九、Map集合(接口)

1、Map中常用方法

   2、HashMap集合

3、Properties集合 

4、TreeMap集合

十、总结(可忽略)


一、集合的概述

  1. 集合实际上就是一个容器、一个载体,可以用来容纳其他类型的数据,属于引用数据类型
  2. 集合当中不能直接存储基本数据类型,也不能直接存储java对集合当中存储的都是java对象的内存地址(及存储的都是引用);
  3. 集合在java.util.*包下

二、集合与数组的区别

1、长度区别

  •  数组长度固定,定义过大会造成内存空间的浪费,定义过小不够用。
  •  集合大小可以变,用多少空间拿多少空间。

2、内容区别

  • 数组可以存储基本数据类型引用数据类型
  • 集合中能存储引用数据类型(存储的为对象的内存地址)

3、元素区别

  • 数组中只能存储同一种基本数据类型元素
  • 集合中可以存储不同类型数据(一般情况下也只存储同一种类型的数据)

4、集合结构

  •  java中每个不同的集合,底层对应的都是不同的数据结构(数据存储的结构:数组、链表、二叉树等)

三、集分的分类

1.Java中集合分为两类:

  1. 一类是以单个方式存储元素(单列集合),超级父类接口为:java.util.Collection;
  2. 一类是以键值对方式存储元素(双列集合) ,超级父类接口为:java.util.Map;

四、集合结构图 

1、Conllection集合结构图

总结: 

(1)、List集合存储元素特点:有序不可重复

  • ArrayList:底层是数组
  • LinkedList:底层是双向列表
  • Vector:底层是数组,线程安全的,效率较低,使用较少;

(2)、Set(对应Map)集合存储元素特点:无序不可重复

  • HashSet:底层是HashMap,放到HashMap集合中的元素等同于放到HashMap集合中的key部分;

(3)、SortedSet(对应SortedMap)集合存储元素特点:无序不可重复,但是SortedSet集合中的元素是可排序的,且Set集合中的元素没有下标

  • TreeSet:底层是TreeMap,放到TreeMap集合中的元素等同于放到了TreeMap集合中的Key部分;

Map集合的key,就是一个Set集合,在Set集合中存放数据,实际上放到Map集合总的Key部分

2、Map集合结构图

总结:

(1)、Map集合存储元素特点:以键值对方式存储元素,特点是无序不可重复。Map集合的key与Set集合存储元素特点相同

  • HashMap:底层是哈希表;
  • Hashtable:底层是哈希表,底层是线性安全的,效率较低,使用较少; 
  • Properties:是线性安全的,并且key和value只能存储字符串String;

(2)、SortedMap集合存储元素特点:无序不可重复,但是放入SortedMap集合key部分的元素会按照大小顺序排序

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

<以下为详解部分 >

五、Interator迭代器 

1、迭代器Interator作用

  • 对集合进行遍历,是所有Collection遍历的一种方式(Set集合中不能使用)

2、迭代器Interator常用方法 

方法名说明
boolean hasNext()如果仍有元素,则返回true
Objict next()返回迭代的下一个元素
void remove()删除迭代的元素

3、迭代器注意事项 

  • 当集合结构发生改变,迭代器必须重新获取;若迭代器没有重新获取时,调用next()方法时,就会发生异常;
  • 在迭代集合元素删除的过程中,不能直接调用集合自身的remove()方法删除元素,否则会发生异常
  • 在迭代元素的过程中,一定要使用迭代器对象Interator的remove()方法,删除元素

六、Collection(接口)集合常用方法

方法名说明
boolean add(E e) 添加元素到集合的末尾(追加)
int size()返回集合中元素个数
void clear()清空集合中的元素(底层调用equles)
boolean contains(Object o)  判断集合中是否包含某个元素(底层调用equles)
boolean isEmpty()判断集合是否为空

Object[] toArray()

将集合转为数组
boolean remove(Object o) 删除指定的元素(底层调用equles)

附加:

  • Conllection集合是一个接口 
  • contains()/remove()方法,底层调用的是equals()方法
  • 存放在一个集合中的元素,需要重写equals()方法,
  • equals()方法比较的是内容,“==”比较的是地址

七、List集合(接口)

  • List集合是一个接口,继承自Collection,需要通过实现类来进行操作。

  • 特点:集合中的元素“有序可重复”(存进去的元素顺序与取出来的元素顺序一致,且元素可以重复)

 1、List接口特有方法

boolean add(E e,int index) 向列表中指定位置添加元素
Object get(int index)获取类表中指定位置的元素
int indexOf(Object o)获取列表中第一次出现元素的索引
int lastIndeOxf(Object o)获取列表中出现元素最后的位置
Object remove(int index)删除指定位置元素
Object set(int index,Object element)用指定元素替换列表中的指定位置的元素

2、List接口中实现类

2.1 、ArrayList集合

  • ArrayList集合底层为一个Object[ ]数组,非线性安全;(数组优点,查找(检索)元素效率较高;数组缺点:随机增删元素效率较低,末尾增删元素效率不受影响)
  • ArrayList集合在未添加元素之前,底层数组长度为0,添加第一个元素时,数组会进行扩容,默认初始化容量为10;
  • 扩容为原容量的1.5倍,建议给定一个初始化容量,减少数组的扩容次数(ArrayList集合优化策略)

2.2、LinkedList集合

  • LinkedList集合底层是双向链表形式,非线性安全;(链表优点:随机增删效率较高,因为实则不能增删元素需要位移大量元素;链表缺点:查找元素效率较低,因为每次查找都要从头结点开始)

2.3、Vector 集合

  • Vetor集合底层为一个数组,初始化容量为0,添加第一个元素时默认初始化容量为10,扩容之后是原容量的2倍;
  • Vector中所有的方法都是线程同步的,都带有synchronized关键字,是线程安全的,效率较低,使用较少;
  • 将一个非线程安全的集合转换成线程安全的集合:
  • 使用集合工具类:java.util.Collections;
    java.util.Collection; // 集合接口
    java.util.Collections; // 集合工具类
    Collections.synchronizedList(非线性安全集合); // 将集合转换为线程安全的集合

八、Set集合(接口)

  • Set集合也是一个接口,继承自Collection,与List类似,都需要通过实现类来进行操作;

  • 特点:“无序不可重复”(存进去的元素与取出来的元素顺序不一样),且元素没有下标;(不能使用for循环进行遍历)

1、HashSet集合

  • HashSet底层是:数组+链表+红黑树的结构
  • Hashset集合的无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的
  • 不可重复性:保证添加的元素按照equals()判断时,不能返回true.。即:相同的元素只能添加一个,是通过equlas和hashcode值共同来判断是否重复,如果都返回true则是重复元素;
  • HashSet扩容:底层也是数组,初始容量为16,当如果使用率超过0.75(16*0.75=12),就会扩大容量为原来的2倍。(16扩容为32,依次为64,128等)

2、TreeSet集合

  • TreeSet集合底层实际上是一个TreeMap集合,往TreeSet集合中添加元素时实际上将数据放入到TreeMap集合中的Key部分去了。TreeMap集合底层采用了二叉树结构;
  • 由于TreeSet集合继承于接口SoretSet,及继承与Set接口中元素存储的特点,无序不可重复,但是存放中的元素可以自动进行排序;
  • 对于自定义的类无法排序,因为类中对象之间没有比较规则,不知道谁大谁小。

(1)、对于自定义的类无法排序原因,举例说明:

/*
对于自定义的类型TreeSet可以自动排序吗?
      以下程序对于Person类型来说,无法排序。因为没有指定Person对象之间的比较规则
      谁打谁小并没有说明

      以下程序运行的时候出现了这个异常:类型转换异常
                java.lang.ClassCastException: com.javase.TreeSet.Person
                cannot be cast to java.lang.Comparable
      出现这个异常的原因是:
                Person类没有实现java.lang.Comparable接口
 */
public class TreeSetTest03 {
    public static void main(String[] args) {
        Person p1 = new Person(31);
        // System.out.println(p1);
        Person p2 = new Person(20);
        Person p3 = new Person(30);
        Person p4 = new Person(11);

        TreeSet<Person> persons = new TreeSet<>();
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p4);

        // 遍历
        for (Person s : persons){
            System.out.println(s);
        }
    }
}
class Person {
    int age;
    public Person(int age) {
        this.age = age;
    }
    // 重写toString
    public String toString(){
        return "Person[sge=" + age + "]";
    }
}

(2)、TreeSet集合元素可排序第一种方式:

  • 需要继承Comparator接口,举例:
public class TreeSetTest04 {
    public static void main(String[] args) {
        Customer c1 = new Customer(31);
        // System.out.println(p1);
        Customer c2 = new Customer(20);
        Customer c3 = new Customer(30);
        Customer c4 = new Customer(11);

        TreeSet<Customer> customers = new TreeSet<>();
        customers.add(c1);
        customers.add(c2);
        customers.add(c3);
        customers.add(c4);

        // 遍历
        for (Customer c : customers){
            System.out.println(c);
        }
    }
}
// 放在TreeeSet集合中的元素需要实现java.long.Comparable接口
// 并且实现compareTo方法,equals可以不写
class Customer implements Comparable<Customer>{
    int age;
    public Customer(int age) {
        this.age = age;
    }
    public String toString(){
        return "age=" + age  ;
    }
    /* 需要在这个方法中编写比较的逻辑,或者说比较的规则,按照什么进行比较
     k.compareT0(t.key)
     拿着参数k和集合中的每一个元k进行比较,返回值可能是>0 <0 =0;
     比较器最终由程序员自己指定:例如按照年龄升序,或者按照年龄降序*/
    @Override
    public int compareTo(Customer c) {// c1.compareTo(c2);
        // this 是c;
        // c是c2
        // c1和c2比较的时候,就是this和c比较
        int age1 = this.age;
        int age2 = c.age;
        /*if(age1 == age2){
            return 0;
        }else if(age1 >age2){
            return 1;
        }else{
            return -1;
        }*/
        return age1 - age2; // >0 <0 =0
    }
}
/*  结果:
age=11
age=20
age=30
age=31
*/

注意:

(1)、 放在TreeeSet集合中的元素需要实现java.long.Comparable接口
(2)、并且实现compareTo()方法,equals可以不写  

  • TreeSet集合中元素可排序的第二种方式:使用比较器的方式
public class TreeSetTest06 {
    public static void main(String[] args) {
        // 创建TreeSet集合的时候,需要使用这个比较器
        // TreeSet<WuGui> WUGUI = new TreeSet<>(); // 这样不行,没有通过构造方法传递一个比较器进去

        // 给构造方法传递一个比较器
        // TreeSet<WuGui> wuGuis = new TreeSet<>(new WuGuiComparator());

        // 可以使用匿名内部类的方式(这个类没有名字,直接new接口)
        TreeSet<WuGui> wuGuis = new TreeSet<>(new Comparator<WuGui>() {
            @Override
            public int compare(WuGui o1, WuGui o2) {
                return o1.age - o2.age;
            }
        });
        wuGuis.add(new WuGui(1000));
        wuGuis.add(new WuGui(234));
        wuGuis.add(new WuGui(245));
        wuGuis.add(new WuGui(645));
        wuGuis.add(new WuGui(4213));

        // 排序
        for(WuGui w : wuGuis){
            System.out.println(w);
        }
    }

}
class WuGui{
    int age;
    public WuGui(int age){
        this.age = age;
    }
    @Override
    public String toString() {
        return "小乌龟{" +
                "age=" + age +
                '}';
    }
}

(3)、最终结论:

  • 放到TreeSet或者集合TreeMap集合key部分的元素要想做到排序,包括两种方式:
  • 第一种:放在集合中的元素实现java.lang.Comparable接口
  • 第二种:在构造TreeSet或者TreeMap集合的时候给他传一个比较器对象(比较器实现java.util.Comparator接口)

(4)、Comparable和Comparator怎么选择呢?

  • 当比较规则不会发生改变的时候,或者说当比较器规则只有一个的时候,建议实现Comparable接口
  • 如果比较规则有多个的时候,并且需要多个比较规则之间频繁切换,建议使用comparator接口
  • Comparator接口的设计符合OCP原则

九、Map集合(接口)

  • Map集合为双列集合:以键值对方式存储数据
  • 双列集合:

(1)、interface Map<K,V> : K(key)键 ,V(value)值

(2)、将键映射到值的对象,不能出现重复的键,每个键最多可以映射到一个值

注:

  • Map和Collection没有继承关系;
  • Map集合以key和value的方式存储数据:键值对方式;
  • key和value都是引用数据类型;
  • key和value都是存储对象的内存地址;
  • key起到主导的地位,value是key的一个附属品;

例如:

学号(key)姓名(value)
Stu001张三
Stu002李四
Stu003王五

1、Map中常用方法

方法说明
V put(K key,V value) 向Map集合中添加键值对
V get(Object key)通过key获取value
void clear()清空Map集合
boolean containsKey(Object key)判断Map中是否包含某个key
boolean containsValue(Object value)判断Map中是否包含某个value
V remove(Object key)通过Key删除键值对
boolean isEmpty()判断集合是否为空
int size() 获取集合中键值对个数
Collection<V> value()获取集合中所有的value,返回一个Collection集合
Set<K> keySet()获取Map集合中所有的Key(所有的键是一个Set集合)

Set<Map.Entry<k,values>> entrySet()

将Map集合接转换为Set集合

 注:Map.Entry  ->  静态内部类:Map中的Entry方法

以上部分方法详解

(1)、Set<Map.Entry<k,values>> entrySet() 将Map集合接转换为Set集合

Map<Integer, String> map = new HashMap<>();
        map.put(01, "zhangsan");
        map.put(02, "lisi");
        map.put(03, "wangmazi");
        map.put(04, "zhaoliu");
        map.put(04, "king"); // key重复的时候value会自动覆盖
// 遍历map集合(无序不可重复)
// 方法一:        
Set<Map.Entry<Integer, String>> set = map.entrySet();  // 将Map集合转化为Set集合
        for (Map.Entry<Integer, String> entry : set) { // 进行遍历
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
/* 结果:
   1=zhangsan
   2=lisi
   3=wangmazi
   4=king
*/

// 方法二:
Iterator<Map.Entry<Integer, String>> node = set.iterator(); // 迭代器
        while (it.hasNext()) {
            Map.Entry<Integer, String> node = it.next();
            Integer key = node.getKey();
            String valus = node.getValue();
            System.out.println(key + "=" + valus);
        }
/* 结果:
   1=zhangsan
   2=lisi
   3=wangmazi
   4=king
*/

   2、HashMap集合

  • HashMao集合底层是哈希表/散列表的数据结构
  • 数组 + 链表 + 红黑树实现的一种数据结构(在JDK8之后,如果哈希表中元素超过8个牡丹香链表这种数据结构会变成红黑树数据结构,当红黑树上的节点数量小于6时没回重新把红黑树树变成单向链表数据结构)
  • 哈希表将以上两种数据结构融合在一起,充分发挥他们各自的优点
  • HashMap集合底层的源代码:

public class HashMap{
             Node<K,V>[] table; // HashMap底层实际上就是一个数组。(一维数组)
             static class Node<K,V>{// 静态的内部类HashMao.Node
                    final int hash; // 哈西值 (哈西值是Key的hashCode()方法的执行结果。hash值通过哈希函数/算法,可以转换成数组的下标)
                    final K key; // 存储在Map集合中的那个Key
                    V value; // 存储在Map集合中的那个value
                    Node<K,V> next; // 下一个节点的内存地址
             }
         }
// 哈希表/散列表:一维数组,这个数组中的第一个元素是一个单项列变(数组和列表的结合体)
  • HashMap集合Key部分特点:

无序不可重复复
无序: 因为不一定挂在哪个单项列表上
不可重复: equals方法来保证HashMap集合的key不可重复,如果key重复了,value会覆盖

  • HashMap集合的默认初始化容量是16,默认加载因子是0.75(当HashMap集合底层数组容量达到75%的时候,数组开始扩容)
  • 重点,HashMap集合的初始化容量必须是2的倍数,这也是官方推荐的。这是因为达到散列均匀,为了提高HashMap集合的存储效率,所必需的
  • 重点:放在HashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode() + equals()方法  (具体原因待究)
  • HashMap集合遍历(含两种方法):
    public class CollectionTest01 {
        public static void main(String[] args) {
            // 创建HashMap集合
            Map<Integer,String> map = new HashMap<>();
            // 添加元素
            map.put(1,"zhangsan");
            map.put(2,"lisi");
            map.put(3,"wangwu");
            map.put(4,"zhaoliu");
            map.put(4,"king");
            map.put(6,"main");
            // 获取元素个数
            System.out.println(map.size()); // 5
            // 取key是2的元素
            System.out.println(map.get(2)); // lisi
            // 遍历Map集合
            // 第一种方式,获取所有的key,通过key获取value
            Set<Integer> set = map.keySet();
            for (Integer key:set) {
                System.out.println(key + "=" + map.get(key));
            }
            /* 结果:
             1=zhangsan
             2=lisi
             3=wangwu
             4=king
             6=main
            */
            // 第二种方式:将Map集合转换为Set集合,Set集合中的每一个元素是node
            // 这个node节点中右key和value
            Set<Map.Entry<Integer,String>> nodes = map.entrySet();
            for (Map.Entry<Integer,String> node : nodes){
                System.out.println(node.getKey() + "=" + node.getValue());
            }
            /* 结果:
             1=zhangsan
             2=lisi
             3=wangwu
             4=king
             6=main
            */
        }
    }

3、Properties集合 

  • Properties是一个Map集合,继承Hashtable,Properties的key和value都是String类型。 Properties被称为属性类对象。 Properties是线程安全的。
  • 这里不做详解,简单了解即可。直接上代码:
public class PropertiesTest01 {
    public static void main(String[] args) {
        // 创建一个properties对象
        Properties pro = new Properties();
        // 需要掌握Properties中两个方法:存、取
        pro.setProperty("url", "jdbc:mysql//localhost:3350/bjpowernode");
        pro.setProperty("driver","co.mysql.jdbc.Driver");
        pro.setProperty("username", "root");
        pro.setProperty("psaaword", "123");

        // 通过key获取value
        String ur1 = pro.getProperty("url");
        String driver = pro.getProperty("driver");
        String username = pro.getProperty("username");
        String password = pro.getProperty("password");

        System.out.println(ur1);
        System.out.println(driver);
        System.out.println(username);
        System.out.println(password);
    }
}
/* 结果:
jdbc:mysql//localhost:3350/bjpowernode
co.mysql.jdbc.Driver
root
null
*/

4、TreeMap集合

  • TreeSet集合底层创建了一个TreeMap集合,底层是一个二叉树;
  • 放到TreeSet集合中的元素吗等同于放到TreeMap集合中的key部分;
  • 放到TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小顺序自动排序,称为:可排序集合;
  • 具体详解已在上述TreeSet集合中说明;

十、总结(可忽略)

  • 每个集合的创建(new)
  • 向集合中添加元素
  • 从集合中取出某个元素
  • 遍历集合
  • 主要的集合类

(1)、ArrayList

(2)、LinkedList

(3)、HashSet(HashSet的key,存储在HashMap集合key的元素需要同时重写hashCode + equals)

(4)、Properties

(5)、TreeMap

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值