L'analyse du code source sous-jacent des méthodes de la collection Java Collection et de la classe d'implémentation Collection

Un: Présentation de Java Collection Framework

集合和数组都是对多个数据进行存储操作的容器,简称 Java 容器(此时的存储主要指的是内存层面的存储,不涉及到持久化存储(持久化存储:硬盘,服务器))

2: Comparaison des collections et des tableaux

1.1数组在存储多个数据方面的特点

> 一旦初始化以后长度就确定了,不可以对长度进行修改

> 定义数组的时候需要指定数组的元素类型,数组定义好以后,数组元素的类型也就确定了

> 也会表现出多态性

1.2 数组的缺点

> 一旦初始化后长度不可修改

> 数组中提供的方法非常有限,对于添加,删除,插入数据等操作 非常不方便,同时效率也不高

> 获取数组中实际元素的个数,数组没有现成的属性和方法可以和使用

< 数组存储数据的特点是有序的,可重复的 对于无序的,不可重复的数据 数组则比较弊端

Trois: la collection Java peut être divisée en collection et système de carte

Collection 体系:单例集合,用来存储一个一个的对象

List接口:存储有序的,可重复的 “动态数组,相较于数组本身静态”
	<List接口下包含 ArrayList,LinkedList,Vector 三个接口实现类
	
Set接口: 存储无序的,不可重复的  “类似于高中讲的集合 ” 无序,确定,互异
  	<Set接口下包含 HashSet,LinkedHashSet,TreeSet 三个实现类

4: Analyse des trois classes d'implémentation sous l'interface List

package CollectionListUse;

import org.junit.Test;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @Author:CT
 * @Date:2021/2/5
 * @Description:CollectionListUse
 * @Version 1.0
 */
/*
 一:list接口:存储有序的,可重复的   “动态数组,相较于数组本身静态”
        <  arraylist “作为list接口的主要实现类,线程不安全,执行效率高 底层使用object[] element”
        <  LinkedList “底层使用双向链表进行存储”
        <  vector  “作为list接口的古老实现类,效率低,线程安全”
二:面试题: 三种实现类的异同
同: 三个类都实现了list接口,都是有序的,可重复的

不同:见上

三:arraylist jdk7 当中的源码分析  类似于stringBuilder,stringBuffer

  arraylist list=new arraylist();// 在底层创建一个类型为object 类型的数组 长度为10
  list.add(123);// elementData[0]=new integer(123) 相当于elementData 中添加数据
  .....
  ....
  list.add(111)// 如果此次添加导致elementData的数组的最大长度不够,则会进行扩容。
  默认情况下扩容为原来的1.5倍,再把原来的数据 调用copy() 方法复制到新的数组当中

  结论: 在开发中我们建议使用带参的构造器 去初始化底层创建数组的长度,会避免在中间环节扩容 提高开发效率

  四:arraylist jdk8 中源码变化

    arraylist list=new arraylist();// 在底层创建一个类型为object 类型的数组,并没有初始化数组的长度,节省了内存空间
    后续的add() 操作于JDk7 一致

    小结:JDK7 和JDK8 的两者种初始化ArrayList 类似于单例模式中的 饿汉式和懒汉式两种设计模式


  五:LinkedList源码分析 JDK8的源码分析

    Linked list=new LinkedList(); 内部声明为Node类型的 first 和 Last 属性,默认值为null
    List.add(123); 将123封装到Node中,创建了Node对象

    其中Node 定义为:体现了Linked List 双向链表

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

    6.Vector 的源码分析:JDK7 和 JDK8 当中通过Vector() 构造器创建对象时,底层都要创建了长度为10的数组
    ,在扩容方面,默认扩容为原来是数组的两倍。。



 */

    /*
    List 接口中的抽象方法
   总结; 常用方法
   增: add(Object obj)

   删: remove(int index)

   改: set(int index,Object)

   查: get(int index)

   插入: add(int index, object ele)

   长度: size()

   遍历: ① Iterator 迭代器
         ② 增强for循环
         ③ 普通的循环
     */
public class CollectionList {
    
    

@Test
    public void test(){
    
    
    ArrayList list=new ArrayList();
    list.add(123);
    list.add(456);
    list.add("AA");

    // 1.void add(int index, Object ele): 在Index 指定位置插入ele 元素
    list.add(2,3);
    System.out.println(list);//[123, 456, 3, AA]

    //2. boolean addAll(int index,Collection ele): 从指定Index位置开始插入ele 集合当中所有的元素

    List<Integer> integers = Arrays.asList(1, 2, 3);//可以初始化多个集合中的对象
    list.addAll(2,integers);
    System.out.println(list);//[123, 456, 1, 2, 3, 3, AA]

    //3. Object get(int index): 获取指定index位置上的值
    Object o = list.get(2);
    System.out.println(o);//1

    //4.int IndexOf(Object obj): 返回obj 在集合当中首次出现的问题 注意是首次出现的位置
    int i = list.indexOf(2);
    System.out.println(i);//3

    //5. int Last IndexOf(object obj): 返回Obj当前集合中末次出现的位置

    int i1 = list.lastIndexOf(3);
    System.out.println(i1);//[123, 456, 1, 2, 3, 3, AA]  值为5

    //6. 移除指定index位置的元素,并返回此元素
    Object remove = list.remove(0);
    System.out.println(remove);//123

    //7. Object set(int index,Object ele): 设置指定index位置的元素为ele
    Object set = list.set(2, 23);

    System.out.println(list);//[456, 1, 23, 3, 3, AA]

    //8. list sublist(int fromIndex, int toIndex): 返回从fromIndex到toIndex位置的子集合 左闭右开

    List list1 = list.subList(2, 4);
    System.out.println(list1);//[23, 3]

}

}

Cinq: Analyse du code source et de la méthode des trois classes d'implémentation sous l'interface Set

package ColeectionSetUse;

import org.junit.Test;

import java.util.*;

/**
 * @Author:CT
 * @Date:2021/2/6
 * @Description:ColeectionSetUse
 * @Version 1.0
 */
/*
 Set接口:是Collection的子接口

 一:set接口的特点
  < Set接口: 存储无序的,不可重复的  “类似于高中讲的集合 ” 无序,确定,互异
         三个实现类
         HashSet(set接口的主要实现类 线程不安全 可以存储 null值 )

         LinkedHashset(作为HashSet的子类): 使得遍历其内部的数据时,可以按照添加的顺序去遍历

         TreeSet: 可以按照添加对象的指定属性,进行排序

 ① set 接口的没有提供额外的方法
 ② set集合不允许包含相同的元素,如果试着把两个相同的元素加入同一个Set集合当中,则添加失败
 ③ set集合 判断两个对象是否相同不是使用 ==运算符,而是根据equals() 方法

二:向set类中添加元素,其所在类必须要重写两个方法 hashCode() 和equals() 方法
    重写的两个方法尽可能保持一致性(相对的对象必须具有相对的散列码”散列码==哈希值“)
    重写两个方法的小技巧(直接调方法,避免手动重写)

 */
public class CollectionSetuse {
    
    
    @Test
    /*
    一:如何理解:

    无序性:不等于随机性。 存储的数据在底层数组中,并非按照数组的索引顺序去做的添加,而是根据数据的哈希值决定的


    不可重复性:往Set 集合当中添加到数据时不可重复的

    二:添加元素的过程:以HashSet为例
    我们向HashSet中添加元素a,首先计算出元素a所在类的hashCode(),计算元素a的哈希值,
    此哈希值接着通过某种算法,算出元素a在底层HashSet当中存放的位置(位置:即为索引位置),判断
    数组在此位置上是否已经存在元素
        如果此位置上没有元素为Null 则直接添加成功 ----> 添加成功情况一
        如果此位置上已经存放了元素b或其他元素
            判断元素a与其他元素的哈希值是否相同
                如果哈希值不同  则添加成功------> 添加成功情况二
                如果哈希值相同
                    则比较元素a调用的equals() 方法比较两个元素的实体内容是否相同
                        如果不同则添加成功 equals() 方法返回值为false------> 添加成功情况三
                        如果相同则添加失败 equals()方法返回值为true

       对于添加成功的两种情况二和三: 元素a与已经在指定位置上的数据以链表的方式存储
       JDK 7:元素a放到数组中指向,指向原来的元素
       Jdk 8:原来的元素在数组中,指向新的元素
       (7上8下)

     */
    public void test(){
    
    
        Set set=new HashSet();
        set.add(456);
        set.add(1230);
        set.add("AAA");
        set.add("CC");
        set.add(new Person("Jerry",12));// 此处为什么要重写equals()方法里面的 hasCode()
        set.add(new Person("Jerry",12));
        Iterator iterator = set.iterator();
       while (iterator.hasNext()){
    
    
            System.out.println(iterator.next());//CC AAA 456 1230

        }


    }
    /*
    关于LinkedHashSet的使用
    ① LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,用于指向前一个数据和数
    ② 优点:对于频繁的遍历数组操作,LinkedHashSet效率高于HashSet
     */
    @Test
    public void test2(){
    
    
        Set set=new LinkedHashSet();
        set.add(456);
        set.add(1230);
        set.add("AAA");
        set.add("CC");
        set.add(new Person("Jerry",12));// 此处为什么要重写equals()方法里面的 hasCode()
        set.add(new Person("Jerry",12));
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
    
    
            System.out.println(iterator.next());//456 1230 AAA person[name="Jerry",age=12]

        }

    }
    /*
    一:TreeSet 类的使用
    ① 向TreeSet当中添加数据时,我们必须确定是同一个类提供的,否则会添加失败
    ② 可以按照对象的添加顺序进行输出
    ③ TreeSet添加数据是按照compareTo 去比较添加数据 他判断数据相同与否是按照return 0 如果返回的是0 则相同
    ④ 所以我们在定制排序的时候可以指定哪些数据能进来
     */
    @Test
    public void test3(){
    
    
    Set set=new TreeSet();
    set.add(123);
    set.add(456);
    set.add(456);//此时会有一个数据添加不成功
        System.out.println(set);

        Set set1=new TreeSet();

        /*
        两种排序方式: 自然排序 定制排序

        自然排序(Comparable)中比较两个对象是否相同的标准:CompareTo()方法
        定制排序(Comparator)
         */

    set1.add(new Person("Jerry",18));//此处会添加失败 原因是添加的对象不统一  java.lang.ClassCastException(报这个错误)
    set1.add(new Person("Jrry",134));
    set1.add(new Person("Jrry",54));

        System.out.println(set1);


    }
    @Test
    /*
    定制排序的使用
     */
    public void test5(){
    
    
        Comparator objectComparator = new Comparator(){
    
    

            @Override
            public int compare(Object o1, Object o2) {
    
    
              if(o1 instanceof Person&& o2 instanceof Person){
    
    
                  Person person=(Person)o1;
                  Person person1=(Person)o2;
                  int i = person.getName().compareTo(person1.getName());
                  if (i!=0){
    
    
                      return i;
                  }else{
    
    
                      return Integer.compare(person.getAge(),person1.getAge());
                  }
              }else{
    
    
                  throw new RuntimeException("输入的数据有误");
              }
            }
        };
        Set set1=new TreeSet(objectComparator);
        set1.add(new Person("Jerry",18));//此处会添加失败 原因是添加的对象不统一  java.lang.ClassCastException(报这个错误)
        set1.add(new Person("Jrry",134));
        set1.add(new Person("Jrry",54));
        System.out.println(set1);

    }
}

Pour résumer:

  1. Lorsque nous utilisons les méthodes sous l'interface List dans la collection, la classe créée par nous-mêmes doit remplacer la méthode equals (), car lors de l'ajout d'éléments à la collection, la méthode equals () dans la classe sera appelée à des fins de comparaison pour voir si il peut être ajouté avec succès.

  2. Lorsque nous utilisons HashSet () et LinkedHashSet () sous l'interface Set 'dans la collection, nous devons réécrire la méthode equals () et Hashcode () dans la classe. La raison en est que lorsque nous ajoutons des éléments à la collection, il sera d'abord return selon la méthode HashCode Pour trouver la position où cet élément est ajouté au tableau sous-jacent, puis appelez la méthode equals () pour comparer s'il est identique. S'il est différent, vous pouvez

  3. Désordre dans la collection: cela signifie que les éléments de la collection ne sont pas stockés dans l'ordre de l'index du tableau, mais sont stockés conformément à la valeur de hachage des éléments

  4. Les éléments stockés dans l'interface Liste sont ordonnés et reproductibles. Les éléments stockés dans l'interface Set sont désordonnés et ne peuvent pas être répétés.

Je suppose que tu aimes

Origine blog.csdn.net/weixin_46351306/article/details/113747032
conseillé
Classement