java集合详解

 

简介

集合又称容器。是Java中对数据结构(数据存储方式)的具体实现。

我们可以利用集合存放数据,也可以对集合进行新增、删除、修改、查看等操作。

集合中数据都是在内存中,当程序关闭或重启后集合中数据会丢失。所以集合是一种临时存储数据的容器。

JDK中集合结构图

集合作为一个容器,可以存储多个元素,但是由于数据结构的不同,java提供了多种集合类。将集合类中共性的功能,不断向上抽取,最终形成了集合体系结构。

 

List接口和Set接口

List和Set的父接口

1. List接口:存储有序, 可重复数据。

1. Vector:List的实现类,底层为可变长度数组实现。所有方法都是同步操作(线程安全),每次扩容成本增长。新数组长度为原数组长度的2倍

2. ArrayList:List的实现类,底层为可变长度数组实现。所有方法都是非同步操作(非线程安全的),以1.5倍的方式在扩容。常用于: 查询较多的情况

3. LinkedList:List的实现类,双向非循环链表的实现。常用于: 删 增 较多的情况

Set接口:存储无序,不可重复数据。

1. HashSet:Set实现类,底层是HashMap 散列表(数组+链表+(红黑树 jdk1.8及之后))。所有添加到 HashSet 中的元素实际存储到了HashMap的key中

2. LinkedHashSet:HashSet子类. 使用LinkedHashMap来存储它的元素,存储的值插入到LinkedHashMap的可以key中, 底层实现(数组+链表+(红黑树 jdk1.8及之后) + 链表), 可以记录插入的顺序

3. TreeSet:Set实现类,底层是TreeMap(红黑树实现), 存入到TreeSet中的元素, 实际存储到了TreeMap中, 根据存储元素的大小可以进行排序

2.2 Map接口

Map:独立的接口。每个元素都包含Key(名称)和Value(要存储的值)两个值。

1. HashMap:Map实现类, 对散列表 (数组+链表+(红黑树Java8及之后))的具体实现,非同步操作(非线程安全的)。存储时以Entry类型存储(key, value)

2. LinkedHashMap: HashMap的子类,是基于HashMap和链表来实现的。在hashMap存储结构之上再添加链表, 链表只是为了保证顺序

3. TreeMap:Map实现类, 使用的不是散列表, 而是对红黑树的具体实现。根据key值的大小, 放入红黑树中, 可实现排序的功能(key值大小的排序)

4. HashTable:Map实现类, 和HashMap数据结构一样,采用散列表(数组+链表+(红黑树 jdk1.8及之后))的方法实现, 对外提供的public函数几乎都是同步的(线程安全)。

常用的集合: ArrayList, HashMap, HashSet

ArrayList

ArrayList 实现了List接口, 底层实现可变长度数组。存储有序、可重复数据, 有下标

实例化

常用向上转型进行实例化。绝大多数集合都支持泛型,如果不写泛型认为泛型是<Object>,使用集合时建议一定要指定泛型。

List<泛型类型> 对象 = new ArrayList<>();

内存结构图

常用API

 

public class TestArrayList {
  public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    //按照下标添加
    list.add("aa");
    //添加到指定的位置
    list.add(1, "bb");
    //查看元素个数
    int size = list.size();
    //根据指定的下标修改
    list.set(0, "aaa");
    //判断
    int bb = list.indexOf("bb"); //元素存在, 返回元素的下标. 不存在, 返回-1
    boolean b = list.contains("bb"); //元素存在, 返回true. 不存在, 返回false
    //删除
    list.remove(0); //根据下标删除
    list.remove("bb"); //根据指定元素删除
    //更新
    list.set(1, 65); 
      
    //查询
    for (String s : list) {
      System.out.println(s);
    }
    for (int i = 0; i < size; i++) {
      System.out.println(list.get(i));
    }
  }
}

LinkedList

介绍

LinkedList是Java中对双向非循环链表的实现。实现了List接口。

具有ArrayList所有常用方法,额外还添加了头尾操作方法(实现了Deque接口),这些方法在List接口中是不存在的,所以如果希望使用这些头尾操作方法,实例化时不用向上转型。

实例化语法

LinkedList<泛型>  对象= new LinkedList<>();

常用API

ArrayList里面常用API在LinkedList中都可以使用。

下面的演示为LinkedList比ArrayList多的常用方法。

public class TestLinkedList {
  public static void main(String[] args) {
    LinkedList<String> linkedList = new LinkedList<>();
    linkedList.addFirst("aa");
    linkedList.addLast("bb");
​
    //获取头结点 没有头结点 java.util.NoSuchElementException
    String first = linkedList.getFirst();
    System.out.println(first);
    //获取尾结点 没有尾结点 java.util.NoSuchElementException
    String last = linkedList.getLast();
    System.out.println(last);
​
    //获取头结点 没有头结点 返回 null
    String s = linkedList.peekFirst();
    System.out.println(s);
    //获取尾结点 没有尾结点 放回 null
    String s1 = linkedList.peekLast();
    System.out.println(s1);
​
    //删除头结点 没有头结点 java.util.NoSuchElementException
    String s2 = linkedList.removeFirst();
    System.out.println(s2); //被删除结点中的值
    //删除尾结点 没有尾结点 java.util.NoSuchElementException
    String s3 = linkedList.removeLast();
    System.out.println(s3);//被删除结点中的值
    
    //删除头结点 没有头结点 返回 null
    String s4 = linkedList.pollFirst();
    System.out.println(s4);
    //删除尾结点 没有尾结点 放回 null
    String s5 = linkedList.pollLast();
    System.out.println(s5);
​
  }
}

问题1:将ArrayList替换成LinkedList之后,变化的是什么?

底层的结构变了

ArrayList:数组 LinkedList:双向非循环链表

问题2:到底是使用ArrayList还是LinkedList

根据使用场合而定

大量的根据索引查询的操作,大量的遍历操作(按照索引0--n-1逐个查询一般),建议使用ArrayList

如果存在较多的添加、删除操作,建议使用LinkedList

问题3:LinkedList增加了哪些方法

增加了对添加、删除、获取首尾元素的方法

addFirst()、addLast()、removeFirst()、removeLast()、getFirst()、getLast()

Java中栈和队列的实现类

Vector过时了,被ArrayList替代了,Stack也就过时了

public  class Stack<E> extends Vector<E>  

Deque和Queue的实现类,用的非常少了解即可 1.ArrayDeque 顺序栈 数组 2.LinkedList 链栈 链表

 public interface Queue<E> extends Collection<E>
 public interface Deque<E> extends Queue<E>

早期的栈结构实现类 Stack

public class Test1 {
    public static void main(String[] args) {
        Stack<String> stack =new Stack<String>();
        // 入栈方法
        stack.push("马云");
        stack.push("马化腾");
        stack.push("马明哲");
        stack.push("马老师");
        // 跳栈 弹栈 取出栈顶元素
        String pop = stack.pop();
        System.out.println(pop);
        System.out.println(stack);
    }
}

Queue单端队列

public class Test2 {
    public static void main(String[] args) {
        Queue<String> q=new LinkedList<String>();
        // 入队方法
        q.offer("张三丰");
        q.offer("张翠山");
        q.offer("张无忌");
​
        System.out.println(q);
​
        // 出队方法 取出队首
        String poll = q.poll();
        System.out.println(poll);
        System.out.println(q);
​
    }
}

Deque双端队列

public class TestLinkedList2 {
    public static void main(String[] args) { 
        //摞盘子
        Deque<String> deque1 = new LinkedList<String>();
        deque1.offerFirst("盘子1");//队首存值
        deque1.offerLast("盘子2");//队尾存值
        deque1.pollFirst();//队首取值
        deque1.pollLast();//队尾取值
        
        System.out.println(deque1.size());
  
    }
}

HashSet

介绍

完全基于HashMap(数组+链表+(红黑树))实现的。

存储无序, 无下标, 元素不重复数据。

代码示例

public class HashSetTest {
    public static void main(String[] args) {
        Set<Student> set = new HashSet<>();
        set.add(new Student("张三", 12,1));
        set.add(new Student("李四", 12,2));
        set.add(new Student("王五", 12,3));
        set.add(new Student("张三", 12,4));
        System.out.println(set);
    }
}
//[Student{name='王五', age=12, id=3}, Student{name='张三', age=12, id=1}, Student{name='李四', age=12, id=2}]

注意

HashSet 保证唯一方式 必须重写hashcode和equals

TreeSet

介绍

底层是基于TreeMap红黑树。红黑树底层进行会进行值比较 使用 Comparable中CompareTo进行 所以存储泛型类必须实现 Comparable接口或外部定义类实现Comparator接口

代码示例

//实现Comparable接口并 重写compareTo方法 否则报Student cannot be cast to java.lang.Comparable错误
public class Student implements Comparable<Student> { 
    private String name;
    private int age;
    private int id;

    public Student(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                id == student.id &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, id);
    }
    //自定义比较内容
    @Override
    public int compareTo(Student o) {
        return this.id - o.id;
    }
}
//或自定义类实现Comparator接口
public class Compares implements Comparator<Teacher> {


    @Override
    public int compare(Teacher o1, Teacher o2) {
        return o1.getAge() - o2.getAge();

    }
}
public class TreeSetTest {

    public static void main(String[] args) {
        Set<Student> set = new TreeSet<>();
        set.add(new Student("张三", 12,1));
        set.add(new Student("李四", 12,2));
        set.add(new Student("王五", 12,3));
        set.add(new Student("张三", 12,1));
        System.out.println(set);

        //也可 通过外部类实现Comparator TreeSet构造设置
//        Set<Teacher> set = new TreeSet<>(new Compares());
//        set.add(new Teacher( 12,1));
//        set.add(new Teacher( 13,1));
//        set.add(new Teacher( 12,1));

//        System.out.println(set);
    }

}

HashMap与TreeMap

介绍

HashMap与HashTree实现 Map接口与Collection没有关系 Map中每个元素都是Entry类型,每个元素都包含Key(键)和Value(值)二者十分类似

HashMap是对散列表的具体实现。

TreeMap是红黑树的具体实现。

里面都包含Key-Value值。

代码示例

public class HashMapTest {
    public static void main(String[] args) {
        Map<Integer,String> map  = new HashMap<>();
        Map<Integer,String> map2  = new TreeMap<>();
        map.put(1, "bj");
        map.put(2, "bj2");
        map.put(3, "bj3");
        map.put(1, "bj4");
        map.put(null, "bj5");
        map.put(null, "bj6"); //hashmap允许null
        System.out.println(map);

//        map2.put(1, "bj");
//        map2.put(2, "bj2");
//        map2.put(3, "bj2");
//        map2.put(1, "bj4");
        map2.put(null, "bj5"); //treemap 不允许null
//        System.out.println(map2);
        System.out.println("===========map遍历1============");
        map.forEach((k,v)->{
            System.out.println(k+"---"+v);
        });

        System.out.println("===========map遍历2============");

        Set<Integer> integers = map.keySet();
        for (Integer key : integers) {
            System.out.println(key+"---"+map.get(key));
        }
        System.out.println("===========map遍历3============");

        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);

        }
        System.out.println("===========map遍历4============");

        Set<Map.Entry<Integer, String>> entries = map.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
            System.out.println(entry.getKey()+"---"+entry.getValue());
        }



    }
}

Iterator

简介

中文名称:迭代器。是一个接口,每个集合中实现类都对Iterator提供了内部类的实现。

通过Iterator可以实现遍历集合的效果。

仅collection实现类可用 map不可用 增强for循环底层为迭代器

存在意义:

隐藏集合实现细节,无论是哪种集合都是通过Iterator进行操作,而不是直接操作集合。通过一套API实现所有集合的遍历。

可以在遍历时删除集合中的值。

代码示例

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

        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
//            list.remove(1);  //ConcurrentModificationException 删除或插入报错
            iterator.remove();  //删除当前内容
        }
       for (Integer integer : list) {
 //           list.remove(0); //ConcurrentModificationException 不可用
        }
        for (int i = 0; i < list.size(); i++) {
            list.remove(0); //无影响
        }
    }
}

Collections

介绍

Collections是一个工具类型,一个专门操作集合的工具类。

代码示例

public class TestCollections {
    public static void main(String[] args) {
        //添加元素
        List<Integer> list = new ArrayList();
        Collections.addAll(list, 10, 50, 30, 90, 85, 100);//6
        System.out.println(list);
        //排序
        Collections.sort(list);//默认按照内部比较器
        System.out.println(list);
        //查找元素(元素必须有序)
        int index = Collections.binarySearch(list, 500);//不存在返回负数
        System.out.println(index);
        //获取最大值和最小值
        int max = Collections.max(list);
        int min = Collections.min(list);
        System.out.println(max + "   " + min);
        //填充集合
        Collections.fill(list, null);
        System.out.println(list);
        //复制集合
        List list2 = new ArrayList();
        Collections.addAll(list2, 10, 20, 30, 50);
        System.out.println(list2);
        Collections.copy(list, list2);//dest.size >= src.size  目标列表的长度至少必须等于源列表。
        System.out.println(list);
        //同步集合
        //StringBuffer 线程安全效率低 StringBuilder 线程不安全,效率高
        //Vector 线程安全  效率低  ArrayList 线程不安全,效率高
        //难道是要性能不要安全吗,肯定不是。
        //在没有线程安全要求的情况下可以使用ArrayList
        //如果遇到了线程安全的情况怎么办
        //方法1:程序员手动的将不安全的变成安全的   
        //方法2:提供最新的线程安全并且性能高的集合类
        List list3 = new ArrayList();
        Collections.addAll(list3, 10, 90, 30, 40, 50, 23);
        System.out.println(list3);
        //将list3转换成线程安全的集合类
        list3 = Collections.synchronizedList(list3);
        //下面再操作,就线程安全了
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值