【JavaSE 集合框架的继承体系】

【JavaSE 集合框架的继承体系】

一、集合框架

1.集合框架由来

JDK 1.2 版本后,出现集合框架,到 JDK1.5 后,大幅度优化。

①集合本质上是存储对象的容器
②数组也能存储对象,数组的弊端就是定长(限制长度)
③为了解决数组的问题,开发出来集合框架,集合框架无需考虑长度

  • 集合和数组的区别与共同点:
    • 集合,数组都是容器,都可以存储数据
    • 集合只存储引用数据类型不存储基本数据类型
    • 数组可以存储基本类型,也可以存储引用类型
    • 数组定长,集合容器可以变长

牢记:数据多了存数组,对象多了存集合

  • 集合学习的关键点:
    • 怎么存储数据
    • 怎么取出数据
    • 选择哪种容器

2.集合框架的继承体系

(1)第一个派系:
  • Collection (集合) 顶级接口 单列集合(一次只能存一个对象)
    • List (列表) 接口
      • ArrayList (数组列表) 实现类
      • LinkedList (链表) 实现类
      • Vector (数组列表) 实现类,已过时
    • Set (集合) 接口
      • HashSet (哈希表) 实现类
        • LinkedHashSet (链表哈希表) 实现类,继承自 HashSet
      • TreeSet (红黑树) 实现类
(2)第二个派系:
  • Map (映射键值对) 顶级接口 双列集合(一次可以存两个对象)
    • HashMap (哈希表) 实现类
      • LinkedHashMap (链表哈希表) 实现类,继承自 HashMap
    • TreeMap (红黑树) 实现类
    • Hashtable (哈希表) 实现类,已过时
      • Properties (哈希表) 实现类,继承自 Hashtable
    • ConCurrentHashMap (哈希表) 线程相关
(3)存在一个独立的接口
  • Iterator 迭代器接口(用来做遍历)
(4)泛型
  • 泛型 Generic
    • 写法
    • 泛型类 ,泛型方法,泛型接口,泛型限定,泛型通配符
(5)增强型循环
  • for(:) 循环

二、 第一个派系:Collection 接口(单列集合)

是所有单列集合的顶级接口,任何单列集合都是他的子接口或者是实现类,该接口中定义的方法,是所有单列集合的共性方法。

使用接口 Collection 的实现类 ArrayList,创建对象。
Collection<E> 尖括号就是泛型,(这是 API 文档中的写法)自己编程时 E 处要写,集合存储的数据类型

(二.1)Collection 接口的常用方法:

方法的定义 方法作用
boolean add(E) 元素添加到集合
void clear() 清空集合容器中的元素
boolean contains(E) 判断元素是否在集合中
boolean isEmpty() 判断集合的长度是不是0,如果是0返回 true
int size() 返回集合的长度,集合中元素的个数
boolean remove(E) 移除集合中指定的元素,移除成功返回 true
T[ ] toArray(T[ ] a) 集合转成数组

Collection 接口的常用方法,使用ArrayList实现类创建对象

(1)boolean add(E)
/**
 *  boolean add(E) 元素添加到集合中
 *  返回值,目前都是true
 */
public static void collectionAdd(){
   
    // 建议使用接口多态创建集合容器对象,存储的数据类型是字符串
    Collection<String> coll = new ArrayList<>(); // 后面尖括号中的数据类型可以不写,但是如果要写前后的数据类型必须一致
    // 注意:集合不能存储基本数据类型
    // 集合对象的方法 add 添加元素
    coll.add("hello");
    coll.add("world");
    coll.add("java");
    coll.add("apple");
    coll.add("banana");
    /**
     *  输出语句中,输出集合对象,调用的是方法 toString()
     *  看到的内容是一个完整的字符串,这种操作不叫遍历
     */
    System.out.println(coll);
}
(2)void clear(), int size(), boolean isEmpty()
    /**
     *  void clear() 清空集合中的所有元素
     *  int size() 集合的长度
     */
    public static void collectionClear(){
   
        Collection<Integer> coll = new ArrayList<>(); // 可以写包装类,但是不能写 int
        coll.add(1);
        coll.add(2);
        coll.add(3); // 具备自动装箱的操作
        System.out.println(coll);
        System.out.println("集合的长度::"+ coll.size()); //长度
        coll.clear();
        System.out.println(coll); // 里面的元素被清空了,但是集合本身仍然存在
        System.out.println("集合的长度::"+ coll.size());
        System.out.println("集合是空吗?" + coll.isEmpty()); //长度=0,isEmpty() 返回 true
    }
(3)boolean contains(), boolean remove()
    /**
     *  boolean contains(E)  判断是否包含
     *  boolean remove(E)  移除元素
     */
public static void collectionContains(){
   
    // 接口多态创建集合容器对象,存储的数据类型是字符串
    Collection<String> coll = new ArrayList<>();
    // 集合对象的方法 add 添加元素
    coll.add("hello");
    coll.add("wife");
    coll.add("world");
    coll.add("java");
    coll.add("apple");
    coll.add("banana"); 
    // 判断集合中是否包含某个元素
    boolean b = coll.contains("world");
    System.out.println("b = " + b);

    // 移除集合中的元素
    // 删除成功返回 true,如果有多个相同的对象,删除最先遇到的那个
    boolean b1 = coll.remove("banana"); // 写一个本来就没有的元素,删不掉就是 false
    System.out.println("b1 = " + b1);
    System.out.println(coll);
}

(二.2)Collections 工具类:

  • java.util.Collection 集合的顶级接口
  • java.util.Collections 操作集合的工具类
    • 工具类的方法全部静态方法,类名直接调用
    • 主要是操作 Collection 系列的单列集合,少部分功能可以操作 Map 集合(双列集合)
/**
 *  集合操作的工具类:Collections
 *  工具类有组方法:synchronized 开头
 *  	操作过程:类名调用传递集合,返回集合
 *  	功能作用:传递的集合,返回后,变成了线程安全的集合
 */
public class CollectionsTest {
   
    public static void main(String[] args) {
   
    	binarySearch();
    	shuffle();
    	sort01();
        sort02();
    }
    
    // 1.集合的二分查找
    public static void binarySearch(){
   
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(5);
        list.add(9);
        list.add(15);
        list.add(20);
        list.add(25);
        int index = Collections.binarySearch(list, 15);
        System.out.println(index);
    }
    
    // 2.集合元素的随机交换位置
    public static void shuffle(){
   
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(15);
        list.add(5);
        list.add(20);
        list.add(9);
        list.add(25);
        System.out.println("list = " + list);
        Collections.shuffle(list);
        System.out.println("list = " + list);
    }
    
    // 3.集合元素的排序
    public static void sort01(){
   
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(15);
        list.add(5);
        list.add(20);
        list.add(9);
        list.add(25);
        System.out.println("list = " + list);
        Collections.sort(list);
        System.out.println("list = " + list);
    }
    
    // 4.集合元素的排序,逆序
    public static void sort02(){
   
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(15);
        list.add(5);
        list.add(20);
        list.add(9);
        list.add(25);
        System.out.println("list = " + list);
        // Collections.reverseOrder() 用来逆转自然顺序
        Collections.sort(list,Collections.reverseOrder());
        System.out.println("list = " + list);
    }
}

1. Collection 下的 List 接口(列表)

List 接口,继承 Collection 接口,是单列集合

(1)List 接口的特点
  • 这个接口的集合都具有索引
  • 这个接口中的元素允许重复
  • 这个接口中的元素是有序
    • 元素不会排序,有序指的是:元素存储和取出的顺序是一致的

List 接口的所有实现类,都具有以上三个特征
(与 List 接口并列存在的 Set 接口,基本上特点是相反的,Set 接口的集合没有索引,元素不允许重复,接口中的元素根据实际有些有序有些无序。)

(2)List 接口自己(独有)的方法 (带有索引)
add(int index ,E e)
/**
* List接口的方法 add(int index, E e)
* 指定的索引位置,添加元素
*
*   IndexOutOfBoundsException (继承自RuntimeException 异常) 集合越界异常  集合的长度是size()
*     子类:①StringIndexOutOfBoundsException 字符串越界异常  字符串的长度是 length()
*     		②ArrayIndexOutOfBoundsException 数组越界异常  数组的长度是 length
*/
public static void listAdd(){
   
    List<String> list = new ArrayList<>();
    list.add("a") ; // 这样是在集合的尾部添加
    list.add("b");
    list.add("c");
    list.add("d");
    list.add("e");
    System.out.println(list); // 按照输入的顺序输出
    // 指定的索引上,添加元素,3 索引上添加元素
    list.add(3,"QQ"); // 如果超出本来的索引数就会出现异常
    System.out.println(list); // 添加后按照索引,依次输出
}
get(int index)
    /**
     *  List 接口的方法 E get(int index)
     *  返回指定索引上的元素
     *  List 集合可以使用 for 循环像数组一样的方式遍历
     */
    public static void listGet(){
   
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        // List 接口方法 get 取出元素
        // String s = list.get(3);
        // System.out.println(s);
        for(int i = 0 ; i < list.size() ; i++){
   
            System.out.println(list.get(i));
            // 已经有了索引后,就和数组的遍历一样
        }
    }
set(int index,E e),remove(int index)
	/**
     *  List接口方法
     *  E set (int index , E e) 修改指定索引上的元素,返回被修改之前的元素
     *  E remove(int index) 移除指定索引上的元素,返回被移除之前的元素
     */
    public static void listSetRemove(){
   
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        System.out.println(list);
        // 修改指定索引上的元素,修改 3 索引
        String str = list.set(3,"https://www.baidu.com");
        System.out.println(list);
        System.out.println(str);
        // 删除指定索引上的元素,删除 3 索引
        str = list.remove(3);
        System.out.println(list);
        System.out.println(str);
    }
(3)List 集合的特有迭代器

List 接口中的方法 listIterator() 返回迭代器,迭代器的接口是 ListIterator ,集合的专用迭代器

  • ListIterator 迭代器接口的方法:
  • boolean hasNext()
  • E next()
  • boolean hasPrevious() 判断集合中是否有上一个元素,反向遍历
  • E previous() 取出集合的上一个元素
    /**
     *   List 接口的方法:
     *   listIterator() List 集合的特有迭代器
     *   反向遍历
     */
    public static void iterator(){
   
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        // 获取特有迭代器接口实现类对象
        ListIterator<String> lit = list.listIterator();
        // 由于集合遍历中的指针只有一个,需要让指针到最后位置,所以先要正向遍历
        while (lit.hasNext()){
   
            String s = lit.next();
            System.out.println(s);
        }
        // 反向遍历
        // 判断上一个元素
        while (lit.hasPrevious()){
   
            //取出元素
            String s = lit.previous();
            System.out.println(s);
        }
        // 反向遍历并不实用 
    }
(4) List 接口的实现类的数据结构

链表结构

链表
(存储数据时,都会放入三个节点中间的地方,起初的节点数据为 null ,要在之后再次输入数据就会在后一个节点中输入下一个元素的地址,再次在新地址中重复操作,存储到最后的节点数据也为 null,删除其中的一个数据,大体结构不会变化,就让要删除元素的上一个节点存储要删除元素的下一个的对象地址。)
数组与链表的对比:

  • 数组:
    • 有索引,数组中元素的地址是连续,查询速度快
    • 数组的长度为固定的,实现扩容需要新创建数组,要通过数组元素的复制,增加或者删除堆内存中的数据导致效率慢
  • 链表:
    • 链表没有索引,采用对象之间内存地址记录的方式存储
    • 查询元素,必须通过第一个节点依次查询,查询性能慢
    • 增删元素,不会改变原有链表的结构,速度比较快
1.1 List 接口的实现类 ArrayList(数组列表)

ArrayList 集合,其内部定义了一个数组,数组的名字叫做: elementDate ,默认初始化长度为 10,一旦超过长度 10,长度就会翻1.5倍,拷贝原数组中的值进入新数组,从而扔掉原数组,但是不能减容量,如果要删除中间的某个元素,就会把之后的元素复制粘贴前进到新的位置,但是它的数组长度不是元素存储的长度(10),而是其中所包含的的元素个数 ArrayList() 一旦被创建(new),就会构造一个初始容量为十的空列表,其中有一个计数器,一旦通过该类调用 size 计数器方法就会返回输入元素的个数

(1) ArrayList 集合的特点

ArrayList 类实现接口 List,ArrayList 具备了 List 接口的特性: (有序、重复、索引)

  • ArrayList 集合底层的实现原理是数组,大小可变(存储对象的时候长度无需考虑)。
  • 数组的特点:查询速度快,增删慢。
  • 数组的默认长度是10个,每次的扩容是原来长度的1.5倍。
  • ArrayList 是线程不安全的集合,但是运行速度快。(API 文档中显示是:不同步)
(2) ArrayList 源码解析
① ArrayList 类的成员变量
 private static final int DEFAULT_CAPACITY = 10; // 默认容量
 private static final Object[] EMPTY_ELEMENTDATA = {
   }; // 空数组(被 final 修饰不可改变)
transient Object[] elementData; // ArrayList 集合中的核心数组(实际在这里面存数据,可以改变长度)
private int size; // 记录数组中存储个数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 数组扩容的最大值
② ArrayList 集合类的构造方法
// 无参数构造方法
public ArrayList() {
   
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
   }; // 数组没有长度
// 有参数的构造方法
public ArrayList(int 10) {
   
    if (initialCapacity > 0) {
   
        // 创建了一个长度为10的数组
    	this.elementData = new Object[10];
    } else if (initialCapacity == 0) {
   
    	this.elementData = EMPTY_ELEMENTDATA;
    } else {
   
    	throw new IllegalArgumentException("Illegal Capacity: "+
    initialCapacity);
    }
}
③ ArrayList 集合类的方法 add()
// main 方法中使用
public static void main(String[] args) {
   
	new ArrayList<>().add("abc"); // 集合中添加元素
}
// 方法 add()
public boolean add("abc") {
   
    // 只要向数组中存数据,检就要检查容量:(1),安全保障
    ensureCapacityInternal(size + 1);  // 总保障容量加一,保障安全
    // abc 存储到数组中,存储数组0索引,size 计数器++
    elementData[size++] = "abc"; // 数组扩容为10
    return true;
}

Ⅰ、add() 中用到的: ensureCapacityInternal() 方法的源码:(嵌套着calculateCapacity()方法)

// 检查集合中数组的容量,参数是1(方便理解),源码是(int minCapacicy)最小容量
private void ensureCapacityInternal(int minCapacity = 1) {
    // 传入 1
    // calculateCapacity 计算容量,方法的参是数组, 1
    // ensureExplicitCapacity (10) 用来扩容
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

calculateCapacity() 方法的源码:

// 计算容量的方法,返回10
private static int calculateCapacity(Object[] elementData, int minCapacity = 1) {
   
    // 存储元素的数组 == 默认的空的数组  构造方法中有赋值
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
   
        // 两个值中返回最大值   max(10,1)
    	return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

Ⅱ、add() 中用到的:ensureExplicitCapacity() 方法的源码:(嵌套着 grow() 方法)

//扩容 
private void ensureExplicitCapacity(int minCapacity = 10) {
    // 传入 10
	 // 私有的方法
    modCount++; // 记录集合被操作了多少次
   // 10 - 数组的长度(就是0) > 0
    if (minCapacity - elementData.length > 0)
        // grow方法(10) 用来数组增长
    	grow(minCapacity);
}

grow() 方法的源码:

 // 增长的方法,参数是(10)
 private void grow(int minCapacity = 10) {
    // 传入 10
     // 变量 oldCapacity 保存原有数组的长度(为零)
     int oldCapacity = elementData.length; // 原有的数组容量为 0
     // 新的数组容量 = 原有数组的容量 + (原有数组的容量 / 2)
     int newCapacity = oldCapacity + (oldCapacity >> 1); // 新的数组容量为0  位移
     // 0 - 10 < 0 新容量-计算出的容量
     if (newCapacity - minCapacity < 0)
     	newCapacity = minCapacity; // 新的数组容量变为10
     // 判断是否超过最大容量
     if (newCapacity - MAX_ARRAY_SIZE > 0) // 判断是否超过最大容量,如果超过最大容量,就直接赋值为最大容量
     newCapacity = hugeCapacity(minCapacity);
	 // 数组的复制,原始数组和新的容量
     elementData = Arrays.copyOf(elementData, newCapacity);
 }
1.2 List 接口的实现类 LinkedList(链表)
(1) LinkedList 集合的特点

LinkedList 类实现接口 List,LinkedList 具备了 List 接口的特性 (有序,重复,索引)

  • LinkedList 底层实现原理是链表,双向链表
  • LinkedList 增删速度快
  • LinkedList 查询速度慢
  • LinkedList 是线程不安全的集合,但是运行速度快
(2) LinkedList 集合的特有方法

集合是链表的实现,可以单独操作链表的开头元素和结尾元素

  • void addFirst(E e) 元素插入到链表开头
  • void addLast(E e) 元素插入到链表结尾
  • E getFirst() 获取链表开头的元素
  • E getLast() 获取链表结尾的元素
  • E removeFirst() 移除链表开头的元素
  • E removeLast() 移除链表结尾的元素
  • void push(E e) 把元素推入堆栈中
  • E pop() 把元素从堆栈中弹出

LinkedList 不能使用多态性(会出现一些问题),要使用纯子类。

public static void main(String[] args) {
   
	linkedAdd();
	linkedGet();
	linkedRemove();
	linkedPushPop();
}

// 1.void addFirst(E e) 元素插入到链表开头
// 2.void addLast(E e) 元素插入到链表结尾
public static void linkedAdd(){
   
    LinkedList<String> linkedList = new LinkedList<String>();
    linkedList.add("a"); // 结尾添加
    linkedList.add("b"); // 结尾添加
    linkedList.add("c"); // 结尾添加
    linkedList.add("d"); // 结尾添加
    System.out.println("linkedList = " + linkedList);
    // 结尾添加
    linkedList.addLast("f");
    linkedList.add("g"); // 再次添加 "g" 在 "f" 之后
    // 开头添加
    linkedList.addFirst("e");
    System.out.println("linkedList = " + linkedList);
}

// 3.E getFirst() 获取链表开头的元素
// 4.E getLast() 获取链表结尾的元素
public static void linkedGet(){
   
    LinkedList<String> linkedList = new LinkedList<String>();
    linkedList.add("a"); // 结尾添加
    linkedList.add("b"); // 结尾添加
    linkedList.add("c"); // 结尾添加
    linkedList.add("d"); // 结尾添加
    System.out.println("linkedList = " + linkedList);
    // 获取开头元素
    String first = linkedList.getFirst();
    // 获取结尾元素
    String last = linkedList.getLast();
    System.out.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值