Java集合架构

本文介绍了Java集合框架的概念,包括集合和数组的区别、使用集合的原因。详细讲解了List集合中的ArrayList和LinkedList,Set集合中的HashSet和TreeSet,以及Map接口中的HashMap。特别提到了JDK1.7和1.8中HashMap的实现区别,包括数据结构和冲突解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.集合框架

1.1 概念

        Java集合框架(Java Collections Framework简称JCF)是为表示和操作集合,而规定的一种统一的标准的体系结构。集合框架包含三大块内容:对外的接口、接口的实现和对集合运算的算法。

集合就是用于存储对象的容器。 只要是对象类型就可以存进集合框架中。集合的长度是可变的。 集合中不可以存储基本数据类型的值

1.2 集合和数组的区别

数组和集合相比,数组的缺点是它长度是固定的,没有办法动态扩展。而集合存储数据时是没有长度限制的,是可以动态扩展的。集合容器因为内部的数据结构不同,有多种不同的容器对象。这些容器对象不断的向上抽取,就形成了集合框架。

2.为什么使用集合?

1)我们原来讲过数组.思考: 数组有缺陷?--定容【一定数组定义好,他们得长度就无法改变.如果需要改变数组得长度,变得很复杂。

2)我们是否可以定义一个长度改变的容器。---当然可以。

3)手撕可变长度的容器

package com.java0415.test;

import java.util.Arrays;

/**
 * @author: jh
 * @create: 2022/4/15
 */
public class MyArray {
    private Object [] arr; //声明一个Object类型的数组
    private int size;//表示数组的下标

    public MyArray(){ //无参构造函数
        this(3);
    }

    public MyArray(int initSize){ //有参构造函数
        if(initSize<0){ //长度不合法
            throw new RuntimeException("sorry 数组的长度有误。");
        }
        arr=new Object[initSize];
    }

    //把元素o放入数组arr
    public void addData(Object o){
        //判断你的数组是否已满
        if(size>=arr.length){
            //扩容--(1)容器的长度变长 (2)把原来容器中的元素复制到新的容器中
            Object[] newArr = Arrays.copyOf(arr, size * 2);
            arr=newArr;
        }
        arr[size]=o;
        size++;
    }

    //根据下标获取数组中的元素。
    public Object getData(int index){
        if(index>=size){
            throw new ArrayIndexOutOfBoundsException("下标越界");
        }
        Object o = arr[index];
        return o;
    }
}

我们自己可以手写一个可变的容器,那么别人也可以手写可变的容器。

java官网 基于数组 根据不同的数据结构 创建了多个类 而这些类统称 为集合框架。

以后 我们在说集合框架时 就表示多个类。

3.集合的架构

4.List集合

4.1 ArrayList

package com.java0415.test;

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

/**
 * @author: jh
 * @create: 2022/4/15
 */
public class Demo1 {
    public static void main(String[] args) {
        //创建集合对象
        List list = new ArrayList();

        //添加操作
        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");
        System.out.println(list);
        List list2=new ArrayList();
        list2.add("a");
        list2.add("b");
        list.addAll(list2);
        System.out.println(list);

        //删除操作
        list.remove(2);
        System.out.println(list);
        //list.clear();
        System.out.println(list);

        //修改操作
        list.set(1,"张三");
        System.out.println(list);

        //查询操作
        Object o = list.get(3);
        System.out.println(o);
        int size = list.size();
        System.out.println(size);
        boolean f = list.contains("java03");
        System.out.println(f);
        int index = list.indexOf("张三");
        System.out.println(index);

        for(int i=0;i<list.size();i++){
            Object o1 = list.get(i);
            System.out.println(o1);
        }

    }
}

 4.2 LinkedList

        链表结构

package com.java0415.test.test1;

import java.util.LinkedList;

/**
 * @author: jh
 * @create: 2022/4/15 22:06
 */
public class DemoLinkedList {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        //添加操作
        linkedList.add("张三");
        linkedList.addFirst("李四");
        linkedList.addLast("王五");
        linkedList.addFirst("徐六");
        linkedList.addLast("郭七");
        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查询效率低,因为它要一个一个节点的往后找。

 5.set集合

 5.1 HashSet集合

package com.java0416.test;

import java.util.HashSet;
import java.util.Iterator;

/**
 * @author: jh
 * @create: 2022/4/18
 */
public class HashSetTest {
    public static void main(String[] args) {
        //创建HashSet对象
        HashSet hashSet = new HashSet();
        HashSet  hashSet1 = new HashSet(16);//初始容器的大小
        //loadFactor:--->0.7f 表示负载因子 当空间使用70%时 要求扩容
        HashSet hashSet2 = new HashSet(16,0.7f);

        //添加操作
        hashSet.add("张三");
        hashSet.add("李四");
        hashSet.add("王五");
        hashSet.add("徐七");
        hashSet.add("郭九");

        HashSet set2=new HashSet();
        set2.add("赵四");
        set2.add("曾三");
        set2.add("陈二");

        hashSet.addAll(set2);
        System.out.println(hashSet);

        //删除操作
        hashSet.remove("曾二");
        //hashSet.clear();//清空容器集合
        System.out.println(hashSet);

        //查询操作,HashSet无修改方法
        boolean e = hashSet.isEmpty(); //判断是否为空
        System.out.println(e);
        boolean b = hashSet.contains("赵四");//判断元素是否在容器中
        System.out.println(b);

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

 

 5.2 TreeSet集合

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

 存储一个对象类型时,运行会发生错误

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

解决办法:(两个)

1.让你的类实现Comparable接口

package com.java0416.test;

import java.util.TreeSet;

/**
 * @author: jh
 * @create: 2022/4/18
 */
public class TreeSetTest {
    public static void main(String[] args) {
        /*
        //存储String类型
        TreeSet treeSet=new TreeSet();
        treeSet.add("java1");
        treeSet.add("java3");
        treeSet.add("java5");
        treeSet.add("java7");
        treeSet.add("java9");
        treeSet.add("java4");
        System.out.println(treeSet);*/

        //存储一个对象类型
        TreeSet treeSet=new TreeSet();//TreeSet不允许重复元素
        treeSet.add(new Student("张三",20,"男"));
        treeSet.add(new Student("赵四",45,"男"));
        treeSet.add(new Student("王五",34,"女"));
        treeSet.add(new Student("李二",26,"男"));
        System.out.println(treeSet);
    }
}
class Student implements Comparable{
    private String name;
    private Integer age;
    private String sex;
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex+
                '}';
    }

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

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

    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    //排序:---返回如果大于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;
    }
}

 2.在创建TreeSet时指定排序的对象

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

 

//需要比对得两个对象
    @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);
    }
}  

6.Map  属于键值对模式

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

package com.java0418.test;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author: jh
 * @create: 2022/4/19
 */
public class MapTest {
    public static void main(String[] args) {
        //创建Map对象
        //默认初始化大小为16 负载因子为0.75
        Map map = new HashMap();
        //初始化大小
        Map map2 = new HashMap(16);
        //初始化大小  负载因子
        Map map3 = new HashMap(16, 0.78f);

        //添加操作
        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);
        map.putIfAbsent("age", 28);//如果指定得key存在,则不放入map中,如果不存在则放入map中
        System.out.println(map);

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

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

        //查询操作
        boolean f = m1.containsKey("k3");//判断map是否存在指定得key
        System.out.println(f);
        Object v = m1.get("k2"); //根据指定的key获取对应得value值
        System.out.println(v);

        Set keys = m1.keySet();//返回该map中所有得key
        System.out.println(keys);
        //遍历map.
        for (Object k : keys) {
            Object value = map.get(k);//
            System.out.println(k + "----->" + value);
        }
    }
}

6.1 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使用得数据结构: 数组+链表+红黑树 而且链表得插入模式为尾部插入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值