【集合框架】

目录

1.1为什么要用集合框架

1.2 集合框架的概念

2.List集合特点

2.1ArrayList

2.1.1ArrayList添加数据

2.1.2ArrayList删除数据      

2.1.3ArrayList修改数据

2.1.4ArrayList查询数据

2.1.5ArrayList底层原理

2.1.6ArrayList的特点

2.2LinkedList

2.2.1LinkedList添加数据

2.2.2LinkedList删除数据

2.2.3LinkedList修改数据

2.2.4LinkedList查询数据

2.2.5 LinkedList底层原理

2.2.6LinkedList特点

3.set集合

3.1.1HashSet添加元素

3.1.2HashSet删除

 3.1.3HashSet查询

3.1.4HashSet底层原理

 3.2TreeSet集合

4.Map

4.1创建Map对象

4.2添加

4.3删除

4.4修改

 4.5查询

4.6HashMap底层原理

4.7总结

 5.泛型

5.1什么是泛型

5.2如何使用泛型

5.3自己定义泛型


1.1为什么要用集合框架

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

java官方  就 基于数组 根据不同的数据结构 封装出来了很多的 类  这些类统称为 集合框架

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

1.2 集合框架的概念

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

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

2.List集合特点

  • List集合是有序集合: 数据的添加和存储次序一致
  • List集合可以存储重复的数据
  • List集合中的数据可以通过下标访问

 

2.1ArrayList

2.1.1ArrayList添加数据

public class MyArrayList {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        //添加元素
        arrayList.add("java");
        arrayList.add(2);
        arrayList.add(2.2);
        arrayList.add(true);
        arrayList.add(new Date());
        //指定位置添加
        arrayList.add(2,3);
        //添加多个元素
        ArrayList arrayList1 = new ArrayList();
        arrayList1.add("java01");
        arrayList1.add("java02");
        arrayList.addAll(arrayList1);
        System.out.println(arrayList);

2.1.2ArrayList删除数据
      

 //删除指定位置
        arrayList.remove(2);
        System.out.println(arrayList);
        //清除全部
        //arrayList.clear();
        //system.out.println(arrayList);


        2.1.3ArrayList修改数据

 //修改指定元素
        arrayList.set(0,1);
        System.out.println(arrayList);

2.1.4ArrayList查询数据

 List list = new ArrayList();
        list.add("java1");
        list.add("java2");
        list.add("java3");
        list.add("java4");
        //for each遍历
        for(Object o : list){
            System.out.println(o);
        }
        //获取指定下标元素
        Object o2 = list.get(1);
        System.out.println(o2);
        //查询数组长度
        Object o3 = list.size();
        System.out.println(o3);
        //获取第一次出现的位置
        int indexOf = list.indexOf("java1");
        System.out.println(indexOf);
        //判断是否有这个元素
        boolean o4= list.contains("java5");
        System.out.println(o4);
        //for循环遍历
        for(int i=0;i< list.size();i++){
            Object o5 = list.get(i);
            System.out.println(o5);
        }

2.1.5ArrayList底层原理

从构造方法来入手。new ArrayList(22) 底层声明了一个Object类型的数组 名字elementData
  Object[] elementData

  public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) { //大于0
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) { //等于初始化为一个空数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else { //抛出一个异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

==========add("java01")======E理解为Object类型================  
   public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 扩容 
        elementData[size++] = e;  //把元素赋值给数组的相应位置
        return true;
    }
==========indexOf("java02") 判断元素在集合中第一次的位置=============
     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;
    }   

===========size() 请求数组的长度======================
 public int size() {
        return size;
    }   

============contain("java05")判断元素是否在集合中==============
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
===============get(1) 获取指定位置的元素========
   public E get(int index) {
        rangeCheck(index); //判断指定的位置是否合法 

        return elementData(index);
    }  

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

============toString() 为什么不打印对象的引用地址 
    [java01, java02, java03, java02]因为重写了Object里面的toString方法。
    
 public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }   
    
    
通过对ArrayList方法的底层代码分析:底层就是对数组的操作。
    ArrayList的底层就是基于数组实现的。

2.1.6ArrayList的特点

ArrayList的底层原理是数组结构,查询效率高,但是数据的添加、删除效率年低。因为它牵涉到数据的迁移。

2.2LinkedList

2.2.1LinkedList添加数据

public static void main(String[] args) {
    LinkedList linkedList = new LinkedList();
    //添加元素
    linkedList.add("java01");
    linkedList.add('a');
    linkedList.add(2);
    linkedList.add(2.23);
    linkedList.add(false);
    linkedList.add(new Date());
    //指定位置添加元素
    linkedList.add(2,"java02");
    System.out.println(linkedList);
    //添加到头部
    linkedList.addFirst("javaFirst");
    //添加到尾部
    linkedList.addLast("javaLast");
    System.out.println(linkedList);
    //添加多个元素
    LinkedList linkedList1=new LinkedList();
    linkedList1.addLast(1);
    linkedList1.addLast(2);
    linkedList.addAll(linkedList1);
    System.out.println(linkedList);

2.2.2LinkedList删除数据

//删除头部
linkedList.removeFirst();
System.out.println(linkedList);
//删除尾部
linkedList.removeLast();
System.out.println(linkedList);
//删除指定位置元素
linkedList.remove(1);
System.out.println(linkedList);

2.2.3LinkedList修改数据

 //修改指定位置的元素
        linkedList.set(0,1);
        System.out.println(linkedList);

2.2.4LinkedList查询数据

public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add("java01");
        linkedList.add("java02");
        linkedList.add("java03");
        //查询数组长度
        int i = linkedList.size();
        System.out.println(i);
        //根据下标获取指定元素
        Object o =linkedList.get(1);
        System.out.println(o);
        //获取第一个元素
        Object o1 = linkedList.getFirst();
        System.out.println(o1);
        //获取最后一个元素
        Object o2 = linkedList.getLast();
        System.out.println(o2);
        //判断是否有这个元素
        boolean b = linkedList.contains("java01");
        System.out.println(b);
        //判断是否为空
        boolean b1 = linkedList.isEmpty();
        System.out.println(b1);
    }

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

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

2.2.6LinkedList特点

LinkedList底层原理是双向链表结构,添加和删除效率高

,但是他的查询效率低,因为它要一个节点一个节点的往后找。

3.set集合

3.1.1HashSet添加元素

 // HashSet hashSet = new HashSet(16);默认长度
        HashSet hashSet = new HashSet();
        //添加元素
        hashSet.add("java01");
        hashSet.add("java02");
        hashSet.add("java03");
        hashSet.add("java04");
        //添加多个元素
        HashSet hashSet1 = new HashSet();
        hashSet1.add("java05");
        hashSet1.add("java06");
        hashSet.addAll(hashSet1);
        System.out.println(hashSet);

3.1.2HashSet删除

//删除元素
        hashSet.remove("java02");
        System.out.println(hashSet);
        //清空元素
        //hashSet.clear();

 3.1.3HashSet查询

 //查询: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);
        }

3.1.4HashSet底层原理

  public HashSet() {

        map = new HashMap<>();
    }
 在创建一个HashSet的对象时,底层创建的是HashMap, 讲HashMap时给大家再说。

 3.2TreeSet集合

TreeSet 基于TreeMap 实现。TreeSet可以实现有序集合,但是有序性需要通过比较器实现。

储存String类型

 TreeSet treeSet = new TreeSet();
        //储存String类型
        treeSet.add("java01");
        treeSet.add("java02");
        System.out.println(treeSet);

储存对象类型(会报错)

public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        //储存对象类型
        treeSet.add(new Student("张三",18));
        treeSet.add(new Student("李四",14));
        treeSet.add(new Student("王五",18));
        treeSet.add(new Student("赵六",20));
        System.out.println(treeSet);

解决方案:

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

public class Student implements Comparable{
    private String  name;
    private int age;
    public Student(){};

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //排序规则:return 大于0表示当前元素比o大 return -1表示当前元素比o小
    // return 0 相同元素
    @Override
    public int compareTo(Object o) {
        Student student=(Student) o;
        if (this.age>student.age){
            return 1;
        }else if (this.age<student.age){
            return -1;
        }
        return 0;
    }
}

 第二种解决方案:在创建TreeSet时设置排序规则

1.自己创建一个类,设置排序规则


import java.util.Comparator;

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

====================================================
public class Student {
    private String name;
    private  int age;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

public class Test {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet(new MyComparator());
        treeSet.add(new Student("张三",18));
        treeSet.add(new Student("李四",16));
        treeSet.add(new Student("王五",16));
        treeSet.add(new Student("赵六",20));
        System.out.println(treeSet);
    }
}

4.Map

 map中的每一个值属于键值对模式,如果往map中添加元素需要添加key和value,key是唯一的。

它也是一个接口,该接口的实现类有:HashMap

4.1创建Map对象

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

4.2添加

//添加
        map.put("k1", "v1");
        map.put("k2", "v2");
        map.put("k3", "v3");
        //添加多个元素
        Map map2 = new HashMap();
        map2.put("k4","v5");
        map2.put("k5","v5");
        map.putAll(map2);
        System.out.println(map);
        //在map中有这个key则不添加,没有就添加进去
        map.putIfAbsent("k1","v1");
        System.out.println(map);

4.3删除

 //删除
        map.remove("k4");
        System.out.println(map);

4.4修改

//修改
        map.replace("k5","v1");//替换元素
        System.out.println(map);

 4.5查询

//查询
       Object o = map.containsKey("k2");//判断map中是否存在指定key
        System.out.println(o);
        Object o2 = map.get("k3");//根据指定key获取value值
        System.out.println(o2);
        Set set = map.keySet();//返回map中所有key
        System.out.println(set);
        //遍历
        for (Object k:set){
            Object value = map.get(k);
            System.out.println(k +""+value);
        }

4.6HashMap底层原理

 Jdk1.7和jdk1.8的区别:

 jdk1.7使用的数据结构:数组+链表 链表的插入模式为头部模式(会造成死循环)

 jdk1.8使用的数据结构:数组+链表+红黑二叉树 链表的插入模式为尾部插入

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                 //如果key得hash值相同,判断key得equals是否相同,替换原来得元素
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        // 判断链表得长度是否超过8个
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            // 把链表转换为红黑树结构
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

4.7总结

jdk1.8HashMap原理:

储存元素使用put(key,value),根据key的hash计算出hash值,并根据相应的算法计算出在数组中的位置,如果hash值相同则称为哈希冲突,会用equals来判断元素是否一致,不一致则存入单项链表上,如果哈希冲突>=8,则把链表转为红黑二叉树。

 Jdk1.7和jdk1.8的区别:

 jdk1.7使用的数据结构:数组+链表 链表的插入模式为头部模式(会造成死循环)

 jdk1.8使用的数据结构:数组+链表+红黑二叉树 链表的插入模式为尾部插入

 5.泛型

5.1什么是泛型

  泛型就是限制我们得数据类型

5.2如何使用泛型

 public static void main(String[] args) {
        //限制了集合中每个元素得类型,只能添加String类型
        List<String> list = new ArrayList<>();
        list.add("java01");
        list.add("java02");
       // K:表示键得泛型为String  V:表示值得泛型为Integer
        HashMap<String,Integer> hashMap = new HashMap<>();
        hashMap.put("张三",18);
    }

5.3自己定义泛型

public  class 类名<标识,标识....> {
     标识  变量名;
     
     public 标识 方法名(){
        
     }
     
     public void 方法名(标识 参数名){
     
     
     }
     .........

}

 

  public static void main(String[] args) {
        Point<Integer> p = new Point<>();
        p.setX(28);
        p.setY(10);
        p.show();
    }
}
    class Point<T>{
        private T x;
        private T y;
        public void show(){
            System.out.println(x+""+y);
        }

        public T getX() {
            return x;
        }

        public void setX(T x) {
            this.x = x;
        }

        public T getY() {
            return y;
        }

        public void setY(T y) {
            this.y = y;
        }
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值