JAVA基础--集合框架

目录

1、集合框架的概述

1.1 为什么需要集合框架

1.2、集合框架体系

1.2.1单列集合

1.2.2 双列集合

2、List列表

2.1、List特点

2.2、ArrayList 快速数组 创建

2.3、ArrayList添加数据

2.4、ArrayList删除数据

2.5、ArrayLiay修改数据

2.6、ArrayList查询数据

2.7、ArrayList底层原理

3、LinkedList

3.1LinkedList创建

3.2LinkedList添加数据

3.3LinkedList删除数据

3.3LinkedList数据修改

3.4LinkedList数据查看

3.5、LinkedList的底层源码分析

3.5.1add函数的内部原理

 3.5.2get函数内部原理

4、Set集合

4.1HashSet集合

4.1.1创建HashSet对象

 4.1.2HashSet的添加、删除、修改和遍历

4.2、TreeSet集合

4.2.1   TreeSet集合概念


1、集合框架的概述

1.1 为什么需要集合框架

我们在java中学习过一个数据类型   ---  数组


数组有问题:  定容 (数组初始化的时候 一旦固定容量  从此就只能存储该容量的数据)
如果我们一旦创建数组  发现数组的容量不够用了    此时就需要扩容 就非常麻烦了。
    
所以我们自己写了一个类  MyArray     getData   addData

大家试想一下  你能写?别人也可以写  所以
   
 java官方  就 基于数组 根据不同的数据结构 封装出来了很多的 类  这些类统称为 集合框架

所以说 以后再说到 集合框架 就要想到 里面有很多的类

1.2、集合框架体系

基于数组(底层就是对数组的封装),根据不同的数据结构(列表、集合、数列、映射)产生了很多类

 

1.2.1单列集合

1.2.2 双列集合

 

 

 

public class MyArray6 {
    private Object[] arr; //声明一个Object类型的数组
    private int size;//表示数组的下标 行为他们是类成员变量在创建
                    //时都有默认值


    public MyArray6() {//无参构造函数
        this(3);//本类中其他的构造函数 this本类的对象。 
        // 如果在构造方法中this()表示调用本类的其他构造函数
    }
    
    public MyArray6(int size) {//有参构造函数---表示数组的长度
        if (size < 0) {
            throw new RuntimeException("数组长度不合法");//长度不合法抛出异常
        }else {
            arr = new Object[size];
        }
    }
    //把元素o放入数组arr
    public void addDate(Object o) {
        //判断你的数组是否已满
        if (size >= arr.length) {
            //扩容--(1)容器的长度变长 (2)把原来容器中的元素复制到新的容器中
            Object[] newArr = Arrays.copyOf(arr, size * 2);
            arr = newArr;
        }
        arr[size] = 0;
        size++;
    }
    //根据下标获取数组中的元素
    public Object getDate(int index) {
        if (index >= size) {
            throw new ArrayIndexOutOfBoundsException("下标越界");
        }
        Object o = arr[index];
        return 0;
    }
}

2、List列表

2.1、List特点

有序集合(也称为序列 )。 该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。

可以简单的理解成和数组的使用方式差不多 ,  存储到List中的数据有顺序的 并且可以通过索引编号对其进行操作

public interface List<E> extends Collection<E> 
public interface Collection<E> extends Iterable<E>
    
List接口中声明了一些 常用的增删改查的方法      

2.2、ArrayList 快速数组 创建

import java.util.ArrayList;
import java.util.List;

public class JavaTest {


    /**
     * ArrayList 的创建
     */
    @Test
    public void test() {

        /*创建一个默认容量的 ArrayList */
        List   haha1 =  new ArrayList();

        /*自定义初始容量的List创建 */
        List   haha2 = new ArrayList(666);

    }

}

2.3、ArrayList添加数据

public void test1(){
        // 有顺序 可以存储null 
        List haha = new ArrayList<>();

        /*追加    */
        haha.add("张三");
        haha.add("李四");
        // add(Object)   666是int类型  为什么能赋值?  自动装箱
        haha.add(666);
        haha.add(null);

        /*插入*/
        haha.add(1,"王五");


        List  hehe = new ArrayList();

        hehe.add("java");
        hehe.add("html");
        hehe.add( haha );
        hehe.addAll( haha );
        hehe.addAll(0,haha);


        //[张三, 王五, 李四, 666, null, java, html, [张三, 王五, 李四, 666, null], 张三, 王五, 李四, 666, null]
        System.out.println(hehe);


    }

2.4、ArrayList删除数据

public void test2(){

        List haha = new ArrayList();


        haha.add("张三");
        haha.add("lisi");
        haha.add("王五");
        haha.add("张三");

        System.out.println(haha);

        /*删除list中某个数据 返回值为 删除的结果 */
        boolean remove = haha.remove("张三");
        /*根据索引值进行删除 返回值为  被删除的数据 */
        Object remove1 = haha.remove(2);

        /*清空list中的内容*/
        haha.clear();


        System.out.println(haha);
    }

2.5、ArrayLiay修改数据

    public void test3(){

        List haha = new ArrayList();

        haha.add("张三");
        haha.add("lisi");

        // 1 先删再加
        haha.set(1,"李四");
        System.out.println(haha);

    }

2.6、ArrayList查询数据

    public void test4(){

        List  haha = new ArrayList(22);

        haha.add("张三");
        haha.add("李四");
        haha.add("李四");
        haha.add("李四");
        haha.add("王五");

        // Returns the number of elements in this list.
        //获取长度
        int size = haha.size();
        System.out.println(size);

        // Returns the element at the specified position in this list.
        //获取下标为1的元素
        Object o = haha.get(1);
        System.out.println(o);

        // Returns <tt>true</tt> if this list contains no elements.
        //判断是否为空
        boolean empty = haha.isEmpty();
        System.out.println(empty);

        // Returns <tt>true</tt> if this list contains the specified element.
        //判断是否存在元素lisi
        boolean contains = haha.contains("lisi");
        System.out.println(contains);

        // 将list转换成java数组 Returns an array containing all of the elements in this list in proper
        //     * sequence (from first to last element).
        Object[] objects = haha.toArray();
        System.out.println(Arrays.toString(objects));

        // Returns the index of the first occurrence(出现) of the specified element in this list, or -1 if this list does not contain the element.
        //得到李四的下标
        int i1 = haha.indexOf("李四");
        int i2 = haha.lastIndexOf("李四");
    
        
        //遍历得到每个元素 两种方法 for循环 和 for each
        for (int i = 0; i < haha.size(); i++) {
            Object o1 = haha.get(i);
            System.out.println(o1);
        }

        /* js 中的 for-in  */
        for (Object o1 : haha) {
            System.out.println(o1);
        }
    }

2.7、ArrayList底层原理

我们要查看底层原理 一般都是从 构造函数开始

在我们调用的时候 new ArrayList<>(66); 在底层其实干了这样的事情
也就是说 ArrayList的底层就是一个 Object 类型的数组 用变量 elementData

  /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            // 此时创建了一个 Object类型数组 赋值给了当前的成员变量  elementData
            this.elementData = new Object[initialCapacity];          
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            // 如果初始化容量小于零  此时抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

/**
     * Shared empty array instance used for empty instances.
     */
private static final Object[] EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access


函数 haha.add("asdasd"); 是往list中添加数据 底层就是将数组添加到 elementData这个数组中 
    
 /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!   扩容
        elementData[size++] = e;
        return true;
    }    
ensureCapacityInternal 扩容的函数
    
   private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    } 

函数 haha.size() 获取list中有多少个元素  底层就是 返回数组中元素的个数 size是单独定义的变量 每次add的时候都会累加
public int size() {
        return size;
    }

函数 haha.isEmpty() 获取list中是否有数据 底层就是 判断size变量的值是否为 0
public boolean isEmpty() {
        return size == 0;
}

函数 haha.get(1); 获取list中的指定索引位置的数据  底层就是从 elementData中根据索引获取具体的数据
public E get(int index) {
        rangeCheck(index);
        return elementData(index);
} 

E elementData(int index) {
        return (E) elementData[index];
}

函数 haha.indexOf("李四"); 获取在list中首次出现的索引  底层就是 遍历数组 依次查找 返回索引
    
public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        
        return -1;
 } 
    
函数 haha.contains("lisi"); 获取某个元素是否在list中   底层就是 
public boolean contains(Object o) {
        return indexOf(o) >= 0;
}
    
函数  haha.set(1,"李四"); 修改指定索引位置的数据  底层就是 修饰数组中某个索引位置的数据
    
 public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
 }
  

3、LinkedList

3.1LinkedList创建

ArrayList  底层体现出来的数据结构是 数组
Linkedlist 底层体现出来的数据结构是 链表


    public void test1(){

        List  haha =  new LinkedList();

    }

创建了一个 LinkedList 对象 底层构造函数 就是默认的构造函数

3.2LinkedList添加数据

 有序  可重复   可为null

public class TestLinkedList {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add("张三");
        linkedList.add("张三");
        linkedList.add("李四");
        linkedList.add(null);
        
        //元素的批量添加
        LinkedList l2 = new LinkedList();
        l2.addAll(linkedList);
        l2.add("嘿嘿");
        l2.add("王五");
        l2.add("赵六");
        System.out.println(l2);
        
        //在数组的第一个位置 和 最后一个位置添加元素
        l2.addFirst("第一个人");
        l2.addLast("最后一个人");
        l2.push("push");
        System.out.println(l2);
    }
}

3.3LinkedList删除数据

public class TestLinkedList {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        linkedList.add(4);
        linkedList.add(5);

        //默认删除第一个元素
        Object remove = linkedList.remove();
        //根据元素名称进行删除
        Object remove1 = linkedList.remove("李四");
        //删除第一个元素
        Object remove2 = linkedList.remove();
        //删除最后一个元素
        Object remove3 = linkedList.remove();
        //指定元素下标进行删除
        Object remove4 = linkedList.remove(0);
        System.out.println(linkedList);
    }
}

3.3LinkedList数据修改

     //根据下标进行修改
     Object o = linkedList.set(0, "张三三");//将下标为0的元素修改成“张三三”
     Object o1 = linkedList.set(0, "444");//将下标为0的元素修改为“444”

3.4LinkedList数据查看

//查看长度                
int size = hehe.size();
//判断是否为空
boolean empty = hehe.isEmpty();
//查看张三的小标
int i = hehe.indexOf("张三");
//判断是否含有李四元素
boolean contains = hehe.contains("李四");
//将hehe转换为数组
Object[] objects = hehe.toArray();
//得到下标为3的元素
Object o = hehe.get(3);
//得到第一个 和 最后一个元素
Object first = hehe.getFirst();
Object last = hehe.getLast();

Object peek = hehe.peek();
Object o1 = hehe.peekFirst();
Object o2 = hehe.peekLast();

3.5、LinkedList的底层源码分析

3.5.1add函数的内部原理

1.凡是查询源码 ,我们都是从类的构造方法入手:
     /**
     * Constructs an empty list.
     */
    public LinkedList() {
    }
 该类的构造方法内是空的,没有任何的代码。 但是该类中有三个属性。   
    transient int size = 0; //索引
   
    transient Node<E> first; //第一个元素对象 
   
    transient Node<E> last; //表示最后一个元素对象。
 
================ add的源码=====E:理解为Object类型==========================。
   public boolean add(E e) {
        linkLast(e);
        return true;
    }


   void linkLast(E e) {
        final Node<E> l = last;
        //上一个节点   数据  下一个节点
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
    
==================Node的源码 内部类=======================================   
   private static class Node<E> { //<E>泛型--object
        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;
        }
    }

 

 

 3.5.2get函数内部原理

1、==================== get(1)-----获取元素========================
   public E get(int index) {
        checkElementIndex(index); //检查index下标是否正确。
        return node(index).item;  //李四Node对象
    }
 ========================node(index)=============================
 Node<E> node(int index) {
        //>> 位运算二进制运算 ----- size >> 1 一半的意思size/2
        if (index < (size >> 1)) { //前半部分
            Node<E> x = first; 
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {  //后半部分
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
    

4、Set集合

4.1HashSet集合

4.1.1创建HashSet对象

public class Test02 {
    public static void main(String[] args) {
        HashSet  hashSet= new HashSet();

        HashSet  hashSet1 = new HashSet(16);//初始容器的大小

        //loadFactor:--->0.7f 表示负载因子 当空间使用70%时 要求扩容
        HashSet hashSet2 = new HashSet(16,0.7f);
    }
}

 4.1.2HashSet的添加、删除、修改和遍历

public class Test02 {
    public static void main(String[] args) {
        //如果没有指定容器的大小 默认为16  负载因子为0.75
        HashSet  hashSet= new HashSet();

        //添加操作
        hashSet.add("java01");
        hashSet.add("java02");
        hashSet.add("java04");
        hashSet.add("java03");
        hashSet.add("java02");

        HashSet set2=new HashSet();
        set2.add("刘德华");
        set2.add("张学友");
        set2.add("黎明");

        hashSet.addAll(set2); //把set2中的每个元素添加到hashset中
        System.out.println(hashSet); //元素不能重复 而且无序

        //删除
        hashSet.remove("黎明");
//        hashSet.clear();//清空容器集合
        System.out.println(hashSet);

        //查询操作
        boolean empty = hashSet.isEmpty(); //判断是否为空
        System.out.println(empty);

        boolean b = hashSet.contains("刘德华");//判断元素是否在容器中
        System.out.println(b);

        //迭代器遍历
        Iterator iterator = hashSet.iterator();//获取迭代器对象 有序:有下标
        while (iterator.hasNext()){//判断是否指定能够移动
            Object next = iterator.next();//指定移动并获取当前的元素
            System.out.println(next);
        }



        //遍历--- foreach
        for(Object o: hashSet){
            System.out.println(o);
        }


    }
}

4.2、TreeSet集合

4.2.1   TreeSet集合概念

TreeSet中的方法和HashSet中的方法一模一样 只是他们的实现不一样。
TreeSet 基于TreeMap 实现。TreeSet可以实现有序集合,但是有序性需要通过比较器实现。

 4.2.2   存储String类型

TreeSet treeSet=new TreeSet();
        treeSet.add("java05");
        treeSet.add("java03");
        treeSet.add("java04");
        treeSet.add("java01");
        treeSet.add("java02");
        treeSet.add("java04");

        System.out.println(treeSet);

4.2.3   存储一个对象类型

public class Test04 {
    public static void main(String[] args) {
        TreeSet treeSet=new TreeSet();
        treeSet.add(new Student("张三",17));
        treeSet.add(new Student("李四",16));
        treeSet.add(new Student("王五",16));
        treeSet.add(new Student("赵六",15));

        System.out.println(treeSet);
    }
}

通过运行我们发现出现如下的错误:

 发现: TreeSet中的元素必须实现Comparable接口 方可放入TreeSet

 

解决办法有两个:

第一个: 让你的类实现Comparable接口

package com.ykq;

import java.util.TreeSet;

public class Test04 {
    public static void main(String[] args) {
        TreeSet treeSet=new TreeSet(); //TreeSet不允许重复元素
        treeSet.add(new Student("张三",17));
        treeSet.add(new Student("李四",16));
        treeSet.add(new Student("王五",16));
        treeSet.add(new Student("赵六",15));

        System.out.println(treeSet);
    }
}
class Student implements Comparable{
     private String name;
     private Integer age;

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

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

    public Student() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
   //排序:---返回如果大于0 表示当前元素比o大  如果返回-1 当前添加的元素比o小  返回0表示相同元素。
    @Override
    public int compareTo(Object o) {
        Student student= (Student) o;
        System.out.println(this+"===================>"+o);

        if(this.age>student.age){
            return 1;
        }
        if(this.age<student.age){
            return -1;
        }

        return 0;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值