java的集合

为什么使用集合?

1. 我们原来讲过数组 .
思考 : 数组有缺陷 ?-- 定容【一定数组定义好,他们得长度就无法改
. 】如果需要改变数组得长度,变得很复杂。
2. 我们是否可以定义一个长度改变的容器。 --- 当然可以。
3. 手撕可变长度的容器。
我们自己可以手写一个可变的容器,那么别人也可以手写可变的容器。
java 官网 基于数组 根据不同的数据结构 创建了多个类 而这些类统称 为集
合框架。
以后 我们在说集合框架时 就表示多个类。
集合的架构

List集合

1. 集合: 理解为容器--它的长度可以变大的,而且它存储的都是对象类型。
2. List:----->它是一个接口,该集合中的元素可以重复,而且是有序的(有下标)。
     ArrayList--->它的底层是数组结构,它的查询效率高,但是它的添加和删除效率低--因为它要牵涉到数据的迁移。
     常见方法: add();size();indexOf(); contains(); get();remove();isEmpty();
    
     LinkedList--->底层双向链表结构,它增加和删除效率高,但是它的查询效率低。
      常见的方法: 它的方法和ArrayList中的方法比较相似,它也有自己特有的方法:
      addFirst() addLast() getFirst()  getLast()
     

创建集合对象(用ArrayList
List list = new ArrayList(); // 创建一个集合对象 如果没有指定集合容器的长度默认为 10
List list1 = new ArrayList(15);
添加的操作
// 添加 可以添加任意类型
list.add("java01");
list.add("java02");
list.add(15.5);
list.add(18);
list.add(true);
list.add(new Date());
System.out.println(list);
list.add(2,"hello"); // 下标为 2 的位置添加元素 并把后面的元素进行唯一
System.out.println(list); // 打印一个对象时默认调用的为 toString()
List list2=new ArrayList();
list2.add("a");
list2.add("b");
list.addAll(list2);// 添加多个元素 把 list2 中的每个元素一一添加到 list
System.out.println(list);
删除的操作
list.remove(2);// 移除下标为 2 的元素
System.out.println(list);
list.clear();// 清空集合中的元素 .
System.out.println(list);
修改的操作
list.set(1," 刘德华 ");
System.out.println(list);
查询操作
List list = new ArrayList();
list.add("java01");
list.add("java02");
list.add("java03");
list.add("java02");
// 查询的方法
Object o = list.get(1);// 根据下标获取元素
System.out.println(o);
int size = list.size();// 获取集合中元素的个数。
System.out.println(size);
boolean f = list.contains("java05");// 判断元素是否在集合中
System.out.println(f);
int index = list.indexOf("java05");// 查询元素在集合中第一次出现的位置
System.out.println(index);
// 遍历集合中的元素 for 循环
for(int i=0;i<list.size();i++){
   Object o1 = list.get(i);
   System.out.println(o1);
}

LInkedList:

public class TestLinkedList {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        //添加
        linkedList.add("java01"); //追加尾部
        linkedList.addFirst("java02"); //添加到头部
        linkedList.addLast("java03");//追加到尾部
        linkedList.addFirst("java04"); //追加到头部
        linkedList.addLast("java05");//追加到尾部
        System.out.println(linkedList);

        //删除操作
        linkedList.removeFirst();//移除头部元素
        System.out.println(linkedList);

        linkedList.remove(2);//移除指定位置的元素
        System.out.println(linkedList);

       linkedList.removeLast();//移除尾部的元素
        System.out.println(linkedList);

        //修改操作
        linkedList.set(1,"java11");
        System.out.println(linkedList);

        //查询操作
        int size = linkedList.size();//求长度
        boolean empty = linkedList.isEmpty();//是否为空

        boolean b = linkedList.contains("java01");//判断元素是否在集合中

        Object o = linkedList.get(1);//根据下标获取指定位置的元素

        Object first = linkedList.getFirst();//获取第一个元素
        System.out.println(first);

        Object last = linkedList.getLast();
        System.out.println(last);
    }

LinkedList的底层源码:

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;
        }
    }

Set集合

HashSet集合

(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);
    }
}

(2) 添加元素

//添加操作
        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); //元素不能重复 而且无序

(3) 删除

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

(4) 修改

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

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

(5) hashSet的遍历

①通过foreach遍历

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

②通过迭代器来遍历

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

(6) hashSet的源码

从构造函数说起:
    /**
     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
        map = new HashMap<>();
    }
 在创建一个HashSet的对象时,底层创建的是HashMap。我们说hashset的底层原理时,我们就在后HashMap的原理就行。 讲HashMap时给大家说原理。

 TreeSet集合。

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

例子: 存储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);

存储一个对象类型:

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;
​
/**
 * @program: day03
 * @description:
 * @author: 闫克起2
 * @create: 2022-04-16 15:59
 **/
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;
    }
}

第一个:在创建TreeSet时 为其指定排序的规则

我们之前 创建过TreeSet对象。
  TreeSet treeSet=new TreeSet(); 但是在创建对象时 并没有为其指定排序得规则,那么就要求该集合得元素有排序规则。 如果元素得类已经创建完成,不能修改该类得源码,这时我们又想把该类得对象放入得TreeSet容器中。 这时就需要你在创建TreeSet时指定排序得规则。
public class MyComparator implements Comparator {

   //需要比对得两个对象
    @Override
    public int compare(Object o1, Object o2) {
        Student s1= (Student) o1;
        Student s2= (Student) o2;
        if(s1.getAge()>s2.getAge()){
            return 1;
        }else if(s1.getAge()<s2.getAge()){
            return -1;
        }else {
            return 0;
        }
    }
}
   
public class Demo01 {
    public static void main(String[] args) {
        //Comparator<? super E> comparator
        //为TreeSet容器指定了排序规则
        TreeSet treeSet=new TreeSet(new MyComparator()); 
        treeSet.add(new Student(18,"王亚波"));
        treeSet.add(new Student(17,"潘世浩"));
        treeSet.add(new Student(19,"刘晓东"));
        treeSet.add(new Student(19,"娄明阳"));
        System.out.println(treeSet);
    }
}  

Map 属于键值对模式

map中得每个元素属于键值对模式。 如果往map中添加元素时 需要添加key 和 value. 它也属于一个接口,该接口常见得实现类有: HashMap.

(1) 如何创建Map对象

        //默认初始化大小为16 负载因子为0.75
         Map map=new HashMap();
         //初始化大小
         Map map2=new HashMap(16);
         //初始化大小  负载因子
         Map map3=new HashMap(16,0.78f);

(2) 添加操作

 //默认初始化大小为16 负载因子为0.75
         Map map=new HashMap();
         //添加操作 key: name     value: 高景霞
         map.put("name","高景霞"); //注意: 要求map得key必须唯一。
         map.put("age",18);
         map.put("name","李赛"); //因为key不能重复,所以后者会把前者覆盖
​
        Map m1=new HashMap();
        m1.put("k1","v1");
        m1.put("k2","v2");
        map.putAll(m1); //把m1中得每个元素 添加到map中
​
        map.putIfAbsent("age",28) ;//如果指定得key存在,则不放入map中,如果不存在则放入map中
​
        System.out.println(map);

(3) 删除操作

        //删除操作
        map.remove("age2");//根据指定得key移除元素
        System.out.println(map);
        map.clear(); //清空map容器
        System.out.println(map);

(4) 修改操作

     //修改操作
        map.replace("name","刘德华");//替换元素
        System.out.println(map);

(5) 查询

public static void main(String[] args) {
        Map map=new HashMap();
        map.put("k1","v1");
        map.put("k4","v4");
        map.put("k2","v2");
        map.put("k3","v3");
        //查询操作
        boolean f = map.containsKey("k5");//判断map是否存在指定得key
​
        Object v = map.get("k5"); //根据指定的key获取对应得value值
        System.out.println(v);
​
        Set keys = map.keySet();//返回该map中所有得key
        System.out.println(keys);
        //遍历map.
        for(Object k:keys){
            Object value= map.get(k);//
            System.out.println(k+"================>"+value);
        }
​
    }

(6) HashMap得底层原理

JDK1.7 和 JDK1.8他们是有区别得。
   JDK1.7使用得数据结构: 数组+链表  而且链表插入模式为头部插入(造成死循环)。
   jdk1.8使用得数据结构: 数组+链表+红黑树 而且链表得插入模式为尾部插入。
   
从构造函数入口:
  /**
     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
     * (16) and the default load factor (0.75).
     */
   public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

 总结:

JDK1.8 HashMap原理
Hashmap得原理,存储元素使用得put(key,value),根据key得hash计算出相应得哈希值,根据相应得算法求出该元素在数组中得位置, 如果求出得哈希值相同,则称为哈希冲突,会根据equals来判断元素是否一致,如果equals不同,则存入单向链表上, 如果哈希碰撞得个数超过8个,则把链表转换为红黑二叉树。


JDK1.7和JDK1.8 HashMap得区别。
   JDK1.7使用得数据结构: 数组+链表  而且链表插入模式为头部插入(造成死循环)。
   jdk1.8使用得数据结构: 数组+链表+红黑树 而且链表得插入模式为尾部插入。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值