14 Java集合(集合框架+泛型+ArrayList类+LinkedList类+Vector类+HashSet类等)

简介: 14 Java集合(集合框架+泛型+ArrayList类+LinkedList类+Vector类+HashSet类等)

14.1 集合框架

什么是集合框架?

Java中的集合框架其实就是对**【数据结构】**的封装,这个封装中提供了一些常用方法,可方便操作数据,无需程序猿自定定义操作,只需要调用封装方法就可以完成对存在集合中数据【增删改查】

集合其实就是对数据结构一种封装,所以之前sun公司就把集合放置到一个统一包中进行管理【java.util】包


什么是数据结构?

数据结构其实就是计算机,组织和存储数据形式

数据结构是指相互之间存在一种或多种特定关系的数据集合

通常情况下,精心选择数据结构可以带来更加高效运行和存储效率, 数据结构往往高效的原因在于**【检索算法】和【索引计数】**

常见数据结构:【数组、栈、链表(单向和双向)、哈希表、队列(单向和双向)、堆、树、图】

Java的集合框架其实就是对【数据结构实现】,我们需要掌握就是如何操作这个数据结构(即操作集合中方法),高效存储与处理数据

PS:根据不同数据结构,操作数据性能是不同(有地查询块、有的插入快、有地允许重复、有的不允许重复等等),在开发中只要选择合理数据结构即集合对数据存储与操作即可


Java中常见的集合框架


习惯性说Java中集合有三大框架【List、Set和Map】


如果详细说明的话应该2个框架3个实现


2个框架: Collection 和 Map

3个实现 :Collection这个集合下两个主要实现 List 和 set 所以称为三大集合List、set 和Map

集合和数组最大区别在于:


集合中只能储存引用类型即对象

集合是一个变长容量,根据集合储存元素个数动态进行删减【扩容和减容】

数组是一个定长容器,创建大小数固定,无论存储多少数据长度都是唯一

常见三大集合框架:


List【列表】:集合中存储对象是按照索引位置进行存储,允许存储重复数据

Set【集】: 集合中存储对象不是按照特定方式进行存储,不允许出现重复数据

Map【映射】:集合中每一个存储元素都是以一种【键值对key- value】方式进行存储的,以一种key和value的形式存储的,key 这个对象是不允许重复【唯一性】,value是允许重复

14.1.1 概念
  • 集合是一种对象容器,用于存放对象
  • 数组的缺点:
  • 1、数组定长,一旦定义不能改变
  • 2、数组中没有方法
  • 3、数组中只能存放相同的数据类型的数据
  • 集合特点:
  • 1、长度可以改变
  • 2、集合中丰富的操作元素的方法
  • 3、集合中只能存储引用数据类型的数据
  • 集合的分类
  • 1、单列集合 (集合中一个元素保存一个数据) Collection
  • 2、双列集合 (集合中一个元素保存两个数据) Map
14.1.2 集合架构
集合架构

image.png

14.2 Collection接口

单列集合的顶层接口

14.2.1 常用方法
  • add方法向集合集合中添加元素
  • clear方法,清空集合中所有元素
  • contains方法 判断集合是否包含某个元素
  • isEmpty判断集合是否为空
  • remove方法 移除集合中元素,返回boolean类型。如果集合中不包含次元素,则删除失败
  • size()返回集合中元素的个数
  • toArray将集合转换成数组。
  • addAll 向一个集合中添加另一个集合
  • containsAll 判断一个集合中是否包含另一个集合
  • removeAll 从一个集合中移除另一个集合
public class CollectionDemo {
  public static void main(String[] args) {
    //创建Collection对象
    Collection coll = new ArrayList();
    
    //Collection接口下常用的方法
    
    //add   向集合中添加元素
    coll.add("jack");
    coll.add(10);
    coll.add("rose");
    
    System.out.println(coll);
    
    //contains 判断集合中是否包含指定元素
    System.out.println(coll.contains("赵四"));
    
    //isEmpty  判断集合的元素个数是否为0     
    System.out.println(coll.isEmpty());
    
    //remove   移除集合中指定的元素,如果存在返回true、否则返回false
    coll.remove("jack1");
    System.out.println(coll);
    
    //size    获取集合中元素个数
    System.out.println(coll.size());
    
    //toArray 将集合变成数组 
    Object[] arr = coll.toArray();
    
    //Arrays.toString  将数组变成字符串形式
    System.out.println(Arrays.toString(arr));
    
    int[] nums = {1,2,3,4};
    //将数组转成集合
    List asList = Arrays.asList(nums);
    System.out.println(asList);
    
    
    Collection coll1 = new ArrayList();
    coll1.add("lilei");
    coll1.add("hanmeimei");
    //addAll   将另一个集合中元素添加到当前集合中
    coll1.addAll(coll);
    System.out.println(coll1);
    //containsAll  判断集合中是否包含另一个集合
    System.out.println(coll1.containsAll(coll));
//    coll1.removeAll(coll);
//    System.out.println(coll1);
    
    //retainAll  保留coll中包含的元素
    coll1.retainAll(coll);
    System.out.println(coll1);
  }
}

14.3 迭代器

14.3.1 迭代器原理

迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。

迭代器原理

image.png

//迭代器的作用:获取集合中的所有的元素    
Collection coll = new ArrayList();
coll.add("jack");
coll.add("rose");
coll.add(10);
coll.add(20.2);
//1、获取迭代器对象
Iterator it = coll.iterator();
while(it.hasNext()) {
    System.out.println(it.next());
}
System.out.println(coll);
14.3.2 迭代器使用常见问题
  • 1、迭代器迭代完成之后,迭代器的位置在最后一位。 所以迭代器只能迭代一次
  • 2、迭代器在迭代的时候,不要调用多次next方法,可能会出错 NoSuchElementException
  • 3、在迭代器迭代的时候,不能向集合中添加或者删除元素 ConcurrentModificationException
public class IteratorDemo {
  public static void main(String[] args) {
    //使用迭代器需要注意的问题
    
    //1、迭代器只能使用一次
//    Collection coll = new ArrayList();
//    coll.add("jack");
//    coll.add("rose");
//    coll.add(10);
//    coll.add(20.2);
//    Iterator it = coll.iterator();
//    while(it.hasNext()){
//      System.out.println(it.next());
//    }
//    while(it.hasNext()){
//      System.out.println(it.next());
//    }
    
    //2、迭代器使用的时候不能多次使用next方法
//    Collection coll = new ArrayList();
//    coll.add("jack");
//    coll.add("rose");
//    coll.add(10);
//    coll.add(20.2);
//    coll.add(100);
//    Iterator it = coll.iterator();
//    while(it.hasNext()) {
//      Object obj = it.next();
//      System.out.println(it.next());
//    }
    //3、迭代器在迭代的时候不要添加或者删除元素
    Collection coll = new ArrayList();
    coll.add("jack");
    coll.add("rose");
    coll.add(10);
    coll.add(20.2);
    coll.add(100);
    Iterator it = coll.iterator();
    while(it.hasNext()) {
      coll.remove(10);
      //coll.add("zhaosi");
      System.out.println(it.next());
    }
  }
}

14.4 泛型基本使用

泛型:参数化类型 JDK1.5之后

  • 用途:
  • 因为如果不使用泛型,那么向集合中添加元素,实际当做Object对象传递进去的,此时发生向上转型了当从集合中获取数据,得到的是Object类型,那么在使用的需要向下转型,,才能正常使用。因此频繁向上向下转型。可能会出现类转换异常。 这个时候就需要使用泛型。
  • 泛型的作用实际上就是讲类型转换的检查提前到了编译期
  • 泛型擦除: JDK1.7之后
  • 集合类型<泛型> 变量名 = new 集合类型<>();
  • 泛型需要注意的问题:
  • 1、泛型上不存在多态
  • Collection coll = new ArrayList();//错误
  • 2、泛型只能是引用数据类型
  • 如果是基本数据类型,则使用它的包装类
public class GenericDemo {
  public static void main(String[] args) {
//    Collection coll = new ArrayList();
//    coll.add(new Student("我要去输液了",38));
//    coll.add(new Student("要输什么液",20));
//    coll.add(new Teacher("想你的夜",30));
//    coll.add("哈哈哈~~平衡了");
//    //获取迭代器对象
//    Iterator it = coll.iterator();
//    while(it.hasNext()) {
//      Student stu = (Student) it.next();
//      stu.play();
//    }
    
//    Collection<Student> coll = new ArrayList<>();
//    coll.add(new Student("我要去输液了",38));
//    //coll.add("");   不能添加其他类型的元素
//    coll.add(new Student("我要去输液了",38));
//    //获取迭代器对象
//    Iterator<Student> it = coll.iterator();
//    while(it.hasNext()) {
//      Student stu = it.next();
//      stu.play();
//    }
    
//    Collection<Person> coll = new ArrayList<Person>();
//    coll.add(new Student("我要去输液了",38));
    
//    Collection<Integer> coll = new ArrayList<Integer>();
  }
}
class Person{
}
class Teacher extends Person{
  String name;
  int age;
  public Teacher() {
  } 
  public Teacher(String name, int age) {
    super();
    this.name = name;
    this.age = age;
  } 
}
class Student extends Person{
  String name;
  int age;
  public Student() {
  } 
  public Student(String name, int age) {
    super();
    this.name = name;
    this.age = age;
  } 
  public void play() {
    System.out.println("就是玩儿");
  }
}

14.5 ArrayList类

14.5.1 常用方法
  • add(innt index, E element)
  • remove(int index)
  • set(int index, E element)
  • get(int index)
  • subList(int beginIndex,int endIndex)
  • list.listIterator();
package com.qf.demo02;

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

public class ArrayListDemo {
  public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    //List集合相对于Collection集合多了一些关于下标操作的方法
    
    //List集合的常用方法
    list.add("jack");
    list.add("rose");
    list.add("cxk");
    list.add("尼古拉斯");
    System.out.println(list);
    System.out.println("======================================");
    //在集合指定下标位置上添加元素      add(index, element)
    list.add(0, "李雷");
    list.add(3, "韩梅梅");
    list.add(6, "亚洲舞王");
    //list.add(10, "赵四");  下标范围:0~size
    System.out.println(list);
    System.out.println("======================================");
    //清空集合中所有的元素  clear()
    //list.clear();
    //System.out.println(list);
    System.out.println("======================================");
    
    //返回元素在集合中的下标,如果不存在返回-1
    System.out.println(list.indexOf("cxk"));
    //返回元素在集合中的下标(找到集合中最后一个相同元素),如果不存在返回-1
    System.out.println(list.lastIndexOf("cxk"));
    
    System.out.println("======================================");
    //移除集合中指定下标位置上的元素    下标范围:0 ~ size-1
    list.remove(0);
    System.out.println(list);
    
    System.out.println("======================================");
    //修改集合中指定下标位置上的元素     下标范围:0 ~ size-1
    list.set(1, "李雷");
    System.out.println(list);
    
    System.out.println("======================================");
    //截取集合中指定下标开始到结束位置上的元素
    List<String> list1 = list.subList(2, 5);
    System.out.println("list1----》"+list1);
    
    System.out.println("======================================");
    //获取指定下标位置上的元素
    System.out.println(list.get(0));
    
    /**
     * List集合遍历的三种方式:
     *   1、迭代器
     *   2、for循环
     *   3、foreach循环(增强for循环)  可以遍历数组和集合
     *   
     *   语法:
     *    for(元素的类型    变量  : 数组|集合){ //变量就表示遍历出来的元素
     *   
     *      }
     */
    System.out.println("===================迭代器遍历===================");
    Iterator<String> it = list.iterator();
    while(it.hasNext()) {
      System.out.println(it.next());
    }
    System.out.println("===================for循环遍历===================");
    for (int i = 0; i < list.size() ; i++) {
      System.out.println(list.get(i));
    }
    System.out.println("===================foreach循环遍历===================");
    for(String s : list) {
      System.out.println(s);
    }
    
    System.out.println("=================list集合的迭代器=====================");
    ListIterator<String> li = list.listIterator();
//    while(li.hasNext()) {
//      System.out.println(li.next());
//    }
//    
//    while(li.hasPrevious()) {
//      System.out.println(li.previous());
//    }
        
    while(li.hasNext()) {
      li.add("hehe");
      System.out.println(li.next());
    }
    System.out.println("--------------");
    while(li.hasPrevious()) {
      System.out.println(li.previous());
    }
  }
}
14.5.2 实现原理

ArrayList其底层实现使用数组

实现原理

image.png

14.6 LinkedList类

14.6.1 常用方法

常用的方法与ArrayList一致。自己独有一些向首尾添加移除等方法(可以模拟对列、堆栈等数据结构)

package com.qf.demo02;

import java.util.LinkedList;

public class LinkedListDemo {
  public static void main(String[] args) {
    //创建LinkedList对象
    LinkedList<String> list = new LinkedList<String>();
    list.add("jack");
    list.add("rose");
    list.add("cxk");
    list.add("李雷");
    list.add("韩梅梅");
    list.add(1, "马冬梅");
    System.out.println(list);
    
    list.addFirst("尼古拉斯");
    list.addLast("亚洲舞王");
    System.out.println(list);
    
    System.out.println("================================================");
    System.out.println(list.getFirst());
    System.out.println(list.getLast());
    System.out.println(list.get(3));
    
    
    System.out.println("================模拟栈结构==================");
    LinkedList<String> list1 = new LinkedList<String>();
    list1.push("aa");
    list1.push("bb");
    System.out.println(list1.pop());
    System.out.println(list1.pop());
    
    System.out.println("================模拟对列结构==================");
    LinkedList<String> list2 = new LinkedList<String>();
    //向对列的尾部添加元素
    list2.offer("哈哈");
    list2.offer("呵呵");
    list2.offer("嘻嘻");
    list2.offer("hiahia");
    //获取并移除对列的头部的元素
    System.out.println(list2.poll());
    System.out.println(list2.poll());
    System.out.println(list2.poll());
    System.out.println(list2.poll());
    //获取但不移除对列的头部的元素
    //System.out.println(list2.element());
    //获取但不移除对列的头部的元素
    //System.out.println(list2.peek());
    System.out.println(list2);
    
    //LinkedList集合三种遍历方式
  }
}


14.6.2 LinkedList实现原理
实现原理

image.png

14.6.3 堆栈和队列结构
堆栈和队列结构

image.png

14.7 Vector类

14.7.1 常用方法

ArrayList的方法基本一致

public class VectorDemo {
  public static void main(String[] args) {
    Vector<String> vector = new Vector<String>();
    vector.add("aa");
    System.out.println(vector);
    /**
     * ArrayList、LinkedList、Vector的区别
     * 
     * ArrayList和Vector底层使用数组实现(增删慢、查询快)
     *   ArrayList是当添加元素的时候,才会扩容数组,默认长度为10
     *   Vector是当创建对象的是,就创建长度为10的数组
     *   ArrayList线程不安全,效率高
     *   Vector是线程安全的,效率低
     *   
     * LinkedList底层使用双向链表实现(增删快、查询慢)
     */
  } 
}
14.7.2 实现原理

ArrayList的底层一致,使用数组实现

14.7.3 常见面试问题

ArrayListLinkedListVector的区别:

ArrayList和Vector底层使用数组实现(增删慢、查询快)

  • ArrayList是当添加元素的时候,才会扩容数组,默认长度为10, Vector是当创建对象的是,就创建长度为10的数组
  • ArrayList线程不安全,效率高 Vector是线程安全的,效率低
  • LinkedList底层使用双向链表实现(增删快、查询慢)

14.8 HashSet类

14.8.1 HashSet基本使用

常用方法与Collection接口中定义的方法一致

特点:

  • 无序 (插入顺序)
  • 无下标
  • 不可重复
HashSet<String> set = new HashSet<String>();
set.add("jack");
set.add("rose");
set.add("cxk");
set.add("jack");
System.out.println(set);
14.8.2 HashSet 去重原理

HashSet底层去重:

首先会比较两个对象的hashCode的值,如果hashCode值不一样,则直接认为两个对象是不同的对象,如果HashCode值一样,那么就会比较两个方法的equals方法, 如果equals方法返回false,则表示两个对象是不同的对象,如果equals方法返回true,则表示两个对象是相同的对象,则不会向HashSet中添加

总之:HashSet确定对象是否重复,是先判断hashcode再判断equals,两者都相等则认为是相同对象

HashSet<User> userSet = new HashSet<User>();
User cxk = new User("cxk", "123");
userSet.add(cxk);
userSet.add(new User("jack", "456"));
userSet.add(new User("王校长", "输液..."));
userSet.add(new User("jack", "456")); // 相同对象无法插入
userSet.add(cxk);// 相同对象无法插入

重写hashCodeequals方法

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((password == null) ? 0 : password.hashCode());
    result = prime * result + ((username == null) ? 0 : username.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    //判断两个对象是否是同一个对象
    if (this == obj)
        return true;
    //判断比较的对象是否为null
    if (obj == null)
        return false;
    //getClass() 返回对象的真实(运行)类型
    if (getClass() != obj.getClass())
        return false;
    User other = (User) obj;
    if (password == null) {
        if (other.password != null)
            return false;
    } else if (!password.equals(other.password))
        return false;
    if (username == null) {
        if (other.username != null)
            return false;
    } else if (!username.equals(other.username))
        return false;
    return true;
}

14.9 LinkedHashSet类

LinkedHashSet

特点::

  • 1、有序
  • 2、无下标
  • 3、不可重复

与父类的方法一致,去重的原理,也与父类一致

public class LinkedHashSetDemo {
  public static void main(String[] args) {
    //LinkedHashSet  有序(链表维护顺序)  不能重复
    LinkedHashSet<String> set = new LinkedHashSet<>();
    set.add("jack");
    set.add("大娃");
    set.add("二娃");
    set.add("rose");
    set.add("爷爷");
    set.add("爷爷");
    for (String s : set) {
      System.out.println(s);
    }
        //1、底层实现 (LinkedHashMap)
        //2、去重原理 (与hashSet一致)
  }
}

14.10 Collections工具类

集合: 工具类(Collections)


Collections.reverse(List list)

将集合中的元素反转

Collections.shuffle(List list)

将集合中的元素随机打乱

  • Collections.sort(List list)
  • 将集合中的元素排序 (必须要实现Comparable接口)
 public class CollectionsDemo {
  public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("jack");
    list.add("大娃");
    list.add("二娃");
    list.add("rose");
    list.add("妖怪");
    list.add("蛇妖");
    list.add("蛇妖");
    System.out.println(list);
    //按照字典顺序
    Collections.sort(list);
    System.out.println(list);
    
    //将集合元素进行翻转
    Collections.reverse(list);
    System.out.println(list);
    
    //将集合中的元素进行随机打乱
    Collections.shuffle(list);
    System.out.println(list);
    
    //Arrays数组工具类      Collections集合工具类
  }
}



目录
相关文章
|
14天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
37 17
|
6天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
10天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
49 4
|
14天前
|
存储 Java 索引
Java中的数据结构:ArrayList和LinkedList的比较
【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。
|
11天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
26 2
|
3月前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
58 7
|
22天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
16 3
|
22天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
28 2
|
22天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
28 1
|
3月前
|
Oracle 安全 Java
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的
JDK8到JDK28版本升级的新特性问题之在Java 15及以后的版本中,密封类和密封接口是怎么工作的