集合框架-

集合框架

为什么使用集合框架?
1、数组长度是固定的
2、数组无法同时存储多个不同的数据类型
集合就是一个长度可变,可以保存任意数据类型的动态数组。
Java种的集合不是由一个类来完成的,而是由一组接口和类构成了一个框架体系,大致可分为3层,最上层是一组接口,再而是接口的实现类。

接口

Collection: 集合框架最基础的接口,
List:Collection的子接口,有序不唯一,最常用的接口
Set: Collection的子接口,存储无序、唯一的对象
Map:独立于Collection的另外一个接口,最顶层的接口, 存储一组简直对象,提供键到值的映射
Iterator:输出集合元素的接口,一般适用于无序集合,从前往后输出
ListLterator:lterator子接口,可以双向输出集合种的元素。
SortedMap:Map的子接口,可以对集合种的元素进行排序。
SortedSet:Set的子接口,可以对集合种的元素进行排序。
Queue:队列接口
Map.Entry:Map内部接口,描述Map种存储的一组键值对元素。
Enumeration:传统的输出接口,已经被lterator取代

Collection 接口

Collection 是集合框架种最基础的父接口,可以存储一组无序,不唯一的对象。

 * @since 1.2
 */

public interface Collection<E> extends Iterable<E> {
    // Query Operations

可以存储一组无序,不唯一的对象,一般不直接使用该接口,也不能被实例化,只是用来提供规范。
Collection是lterable接口。

int size()获取集合长度
boolean isEmpty()判断集合是否为空
boolean contains(Object o)判断集合种是否存在某个对象
lteratorlterator()实例化lterator接口,遍历集合
Object[] toArray将集合转换为一个Object数组
T[] toArray(T[ ] a)将集合转换为一个指定数据类型的数组
boolean add(E e)向集合添加元素
boolean remove(Object o)从集合中删除某元素
boolean containsAll判断集合种是否存在另一个集合的所有元素
boolean addAll(Collection c)向集合种添加某个集合的所有元素
boolean removeAll(Colletion c)从集合种删除某个集合的所有元素
void clea()清除集合中的所有元素
boolean equals(Collection c)判断两个集合是否相等
int hashCode()返回集合的哈希值

Collection子接口

  • List: 存放有序,不唯一的元素
  • Set: 存放无序,唯一的元素
  • Queue: 队列接口

List接口

 * @since 1.2
 */

public interface List<E> extends Collection<E> {
    // Query Operations

List 常用方法

T get(int index)通过下标返回集合种对应位置的元素
T set(int index,T element)在集合中的指定位置存入对象
int indexOf(Object o)从前向后查找某个对象在集合中的位置
int lastIndexOf(Object o)从后向前查找某个对象在集合中的位置
Listlteratorlistlterator()实例化Listlterator接口,用来遍历List集合
ListsubList(int fromIndex,int toIndex)通过下标截取List集合

List接口的实现类

ArrayList 是开发中使用频率最高的List实现类,实现长度可变的数组,在内存中分配连续空间,所有读取快,增删慢

import java.util.ArrayList;
import java.util.Iterator;
public class Test {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("hello");
        arrayList.add("world");
        arrayList.add("JavaSE");
        arrayList.add("JavaME");
        arrayList.add("JavaEE");
        System.out.println("ArrayList: "+arrayList);
        System.out.println("ArrayList长度: "+arrayList.size());
        System.out.println("ArrayList是否包含Java: "+arrayList.contains("Java"));
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println(arrayList.get(i));
        }
        Iterator iterator = arrayList.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        arrayList.remove("hello");
        arrayList.remove(0);
        System.out.println("***********");
        System.out.println(arrayList);
       arrayList.add(1,"Spring");
        System.out.println(arrayList);
        arrayList.add(1,"SpringBoot");
        System.out.println(arrayList);
        //改  set
        arrayList.set(1,"Spring Could");
        System.out.println(arrayList);
        System.out.println("*********************************");
        //根据元素返回下标
        System.out.println(arrayList.indexOf("Spring"));
        //根据区间值截取元素
        System.out.println(arrayList.subList(1,3));
    }
}

ArrayList: 基于数组的实现,非线程安全,效率高,所有方法都没有synchronized修饰
Vector:线程安全,效率低,实现线程安全直接通过synchronized修饰方法来完成。

import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
public class Test3 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            new Thread(() -> {
                try {
                    TimeUnit.MICROSECONDS.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                arrayList.add(String.valueOf(temp));
                System.out.println(arrayList);
            }).start();
        }

    }
}

java.util.ConcurrentModificationException
并发修改异常
在这里插入图片描述
解决异常

public class Test3 {
    public static void main(String[] args) {
       Vector arrayList = new Vector();
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            new Thread(() -> {
                try {
                    TimeUnit.MICROSECONDS.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                arrayList.add(String.valueOf(temp));
                System.out.println(arrayList);
            }).start();
        }

    }
}

Stack: Vector的子类,实现了栈的数据结构 先进后出
  • push: 入栈
  • peek: 输出栈顶元素,但不删除元素,取完后栈内数据不变
  • pop: 输出栈顶元素,并删除,取完之后栈内的数据减一
LikedList: 实现了先进先出的队列,采用链表的形式来存储。

ArrayList和LikedList区别: 都是线程不安全
在内存中存储形式不同,ArrayList采用的数组方式,LinkedLiss采用的是链表的形式。

数组在内存中存储空间是连续的,读取快,增删慢
因为数组在内存中是连续的,所以取数据可以通过寻址公式很快求出目标元素的内存地址,因为内存是连续的,所以新增或者删除元素,必须需要移动数据,而且数组长度越长,需要移动的元素越多,操作就越慢。
链表在内存中存储空间是不连续的,读取慢,增删快。链表在内存中是不连续的,没有固定的公式可以使用,要读取只能从第一位开始一直遍历到目标元素,数据规模越大,操作越慢。

增删快,因为只需要重新设置目标元素前后两个节点的后置指针即可,与数据规模无关。

import java.util.LinkedList;
public class Test5 {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add("Hello");
        linkedList.add("world");
        linkedList.add("JavaEE");
        System.out.println(linkedList);
        linkedList.offer("JavaSE");
        System.out.println(linkedList);

        linkedList.push("Spring");
        System.out.println(linkedList);
        linkedList.addFirst("First");
        System.out.println(linkedList);
        linkedList.addLast("last");
        System.out.println(linkedList);
        System.out.println(linkedList.peek());
        System.out.println(linkedList.peekFirst());
        System.out.println(linkedList.peekLast());
        System.out.println(linkedList.pop());
        System.out.println(linkedList);

    }
}

LinkedList和Stack都有pop方法,有什么区别和相同点

pop方法都是取出集合中第一个元素,但两者顺序是相反的,Stack是”先进后出“,所以pop取出的是最后一个元素,LikedList是”先进先出“,所以pop取出的第一个元素。
LikedList实现了Deque接口,而Deque接口是Queue的子接口,Queue就是队列,底层实现了队列的数据结构。
实际开发中,不能直接实例化Queue对象。
Queue的实现类是AbstractQueue,它是一个抽象类,不能直接实例化,开发中需要实现它的子类PriorityQueue.
Queue中添加的数据必须是有顺序的。

public class Test6 {
    public static void main(String[] args) {
        PriorityQueue priorityQueue = new PriorityQueue();
        priorityQueue.add(new A(1));
        priorityQueue.add(new A(2));
        System.out.println(priorityQueue);

    }
}

class A {
    private int num;

    public A(int num) {
        this.num = num;
    }
}

Exception in thread “main” java.lang.ClassCastException:
类型转换异常
在这里插入图片描述
解决



import java.util.PriorityQueue;
public class Test6 {
    public static void main(String[] args) {
        PriorityQueue priorityQueue = new PriorityQueue();
        priorityQueue.add(new A(1));
        priorityQueue.add(new A(2));
        System.out.println(priorityQueue);

    }
}

class A implements Comparable {
    private int num;

    public A(int num) {
        this.num = num;
    }

    @Override
    public int compareTo(Object o) {
        A a =(A)o;
        if(this.num > a.num){
            return 1;
        }else if(this.num == a.num) {
            return 0;
        }else {
            return -1;
        }

    }

    @Override
    public String toString() {
        return "A{" +
                "num=" + num +
                '}';
    }
}

Queue默认给元素进行升序排序,既自然排序。

List Set Map 的 区 别

  • List:
  • Set:
  • Map:
    List Set: 存储的是单个数据,List可以存储重复的数据,Set数据不能重复
    Map: 存储的是一组数据 是键值对的形式存在

Set

跟List一样,Set是Collection的子接口,Set集合是以散列的形式存储数据,元素是没有顺序的,可以存储一组无序且唯一的数据

public interface Set<E> extends Collection<E> {
    // Query Operations

常用实现类:

  • HashSet
  • LinkedHashSet
  • TreeSet
    HashSet是开发中经常使用的一个实现类,存储一组无序且唯一的对象。
    无序:元素的存储顺序和遍历顺序不一致。
import java.util.HashSet;
import java.util.Iterator;
public class Test2 {
    public static void main(String[] args) {
        HashSet set = new HashSet();
        set.add("Hello");
        set.add("Java");
        set.add("world");
        set.add("Hello");
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("------------------------------");
        set.remove("world");
        iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }
}

LikedHashSet是Set的另外一个实现类,可以存储一组有序且唯一的元素。
有序:元素的存储顺序和遍历顺序一致。

equals 和 == 区别

所有类中的equals都是继承Object,Object类中原生的equals方法就是在通过 == 进行判断

   public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

但是每个类都可以对equals方法进行重写,覆盖掉之前使用 == 进行判断的逻辑,改用新的逻辑进行判断是否相等。
LinkedhashSet如何判断两个对象是否相等?
首先会判断两个对象的hashCode是否相等

什么是hashCode?
将对象的内部信息(内存地址、属性值等),通过某种特定规则转成一个散列值,就是该对象的hashCode.

  • 两个不同对象的HashCode值可能相等。
  • hashCode不相等的两个对象一定不是同一个对象。
    集合在判断两个对象是否相等的时候,会先比较他们的HashCode,如果HashCode不相等,则认为不是同一个对象,可以添加。
    如果HashCode值相等,还不能认为两个对象是相等,需要通过equals进行进一步的判断,equlas相等,则两个对象相等,否则两个对象不相等。
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashSet;
public class Test3 {
    public static void main(String[] args) {
        LinkedHashSet set = new LinkedHashSet();
        Data data1 = new Data(1);
        set.add(data1);
        Data data2 = new Data(1);
        set.add(data2);
        System.out.println(data1.equals(data2));
        System.out.println(set);
    }
}
class Data{
    private int num;

    public Data(int num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "Data{" +
                "num=" + num +
                '}';
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        //instanceof 判断对象是否属于某个类
        if( obj instanceof Data){
            Data data = (Data) obj;
            if(this.num == data.num);
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return 1;
    }
}

== 判断的是栈内存中的值

引用类型的数据,栈内存中存储的是地址,所以此时 == 判断的是引用地址 。

基本数据类型,栈内存中存储的是具体的数值。
在这里插入图片描述

栈中存储的是变量
Data data;
引用类型具体的对象(属性)存储在堆中,再将堆中对象的内存地址赋值给栈中的变量data,data中存储的就是地址。

基本数据类型不需要用到堆内存,变量在栈中,变量的值直接存储在变量中。

TreeSet

LinkedHashSet和TreeSet都是存储一组有序且唯一的数据,但是这里的两个有序是有区别的。
LinkedHashSet的有序是指元素的存储顺序和遍历顺序一致的。
TreeSet的有序是指集合内部会自动对所有元素按照升序进行排列,无论存入的顺序是什么,遍历的时候一定按照升序输出。


import java.util.Iterator;
import java.util.TreeSet;
public class Test5 {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add(1);
        treeSet.add(5);
        treeSet.add(7);
        treeSet.add(3);
        treeSet.add(4);
        treeSet.add(1);
        treeSet.add(2);
        System.out.println("treeSet长度: "+treeSet.size());
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }
}

Exception in thread “main” java.lang.ClassCastException:
类型不匹配异常

import java.util.TreeSet;

public class Test6 {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Data0(1));
        treeSet.add(new Data0(3));
        treeSet.add(new Data0(4));
        treeSet.add(new Data0(5));
        System.out.println("treeset长度 "+ treeSet.size() );

    }
}
class Data0{
    private int num;

    public Data0(int num) {
        this.num = num;
    }
}

解决



import java.util.Iterator;
import java.util.TreeSet;
public class Test6 {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Data0(1));
        treeSet.add(new Data0(3));
        treeSet.add(new Data0(4));
        treeSet.add(new Data0(5));
        treeSet.add(new Data0(2));
        System.out.println("treeSet长度 "+ treeSet.size() );
        System.out.println("treeSet遍历 ");
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }
}
class Data0 implements Comparable{
    private int num;

    public Data0(int num) {
        this.num = num;
    }

    /**
     * A.comparable
     * 返回值
     * 1 表示A 大于 B
     * 0 表示A 等于 B
     * -1 表示A 小于 B
     * @param o
     * @return
     */
    @Override
    public int compareTo(Object o) {
        if ( o instanceof Data0){
            Data0 data0 = (Data0) o;
            if(this.num > data0.num){
                return -1;
            }else if(this.num == data0.num){

                return 0;
            }else {
                return 1;
            }

        }
        return 0;
    }

    @Override
    public String toString() {
        return "Data0{" +
                "num=" + num +
                '}';
    }
}

Map

List、Set接口都是Collection的子接口,Map接口是与Collection完全独立的另外一个体系。
List & Set Vs Map
List & Set & Collection只能操作单个元素,Map可以操作一对元素,因为Map存储结构是Key- Value映射。
Map接口定义时使用泛型,并且定义两个泛型K和V,K表示key,规定键元素的类型,V表示value,规定值元素的类型。

方法描述
int size()获取集合长度
boolean isEmpty()集合是否为空
boolean containsKey(Object key)判断集合中是否存在某个key
boolean containsValue(Object value)判断集合中是否存在某个Value
V get(Object key)取出集合中key对应的value
V put(Object key)向集合中存入一组key-value的元素
V remove(Object)删除集合中key对应的value
void purAll(Map map)向集合中添加另外一个Map
void clear()清除集合中所有的元素
Set keySet()取出集合中所有的key,返回一个Set
Collectionvalues()取出集合中所有的Value,返回一个Collection
Set<Map.Entry<K,V>entrySet()将Map以Set的形式输出
int hashCode()获取集合的散列值
boolean equals(Object o)比较两个集合是否相等

Map接口的实现类

  • HashMap: 存储一组无序,key不能重复,value可以重复的元素。
  • Hashtable: 存储一组无序的,key不可以重复,value可以重复的元素。
  • TreeMap: 存储一组有序,key不可以重复,value可以重复的元素,可以按照key进行排序。
    HashMap常规操作
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.locks.Condition;

public class Test7 {
    public static void main(String[] args) {
       HashMap hashMap = new HashMap();
       hashMap.put("h","hello");
       hashMap.put("j","java");
       hashMap.put("a","apple");
       hashMap.put("c","cat");
       hashMap.put("e","javaee");
        System.out.println(hashMap);
        hashMap.remove("h");
        System.out.println("删除之后"+hashMap);
        hashMap.put("j","hhhhhhhhhhhh");
        System.out.println("添加之后"+hashMap);
        if(hashMap.containsKey("a")){
            System.out.println("集合中存在key = a");
        }else {
            System.out.println("集合中不存在key = a");
        }


        if(hashMap.containsValue("cat")){
            System.out.println("集合中存在value=cat");
        }else {
            System.out.println("集合中不存在value=cat");
        }

        Set keys = hashMap.keySet();
        System.out.println("集合中的key");
        Iterator iterator = keys.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("集合中的Value");
        Collection values = hashMap.values();
        for (Object value : values) {
            System.out.println(value);

        }

        System.out.println("****************************");
        iterator = keys.iterator();
        while (iterator.hasNext()){
            String key = (String) iterator.next();
            String value = (String) hashMap.get(key);
            System.out.println(key +" - "+value);
        }
    }
}

*iterator 只取不收回 ,所有后面 在使用需重写赋值
Hashtable用法与HashMap基本一样,区别是Hashtable是线程安全的性能较低,HashMap是非线程安全的,但性能较高。
HashMap,方法没有用synchronized修饰,所有非线程安全

    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

Hashtable,方法被synchronized修饰,所以是线程安全的

   public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }

        addEntry(hash, key, value, index);
        return null;
    }

Hashtable的使用

package com.xmm.maptest;

import java.util.Collection;
import java.util.Hashtable;
import java.util.Set;

/**
 * @Description TODO
 * @Author Xm
 * @Date 2022/8/3 22:15
 */

public class Test {
    public static void main(String[] args) {
        Hashtable hashtable = new Hashtable();
        hashtable.put("h","hello");
        hashtable.put("j","java");
        hashtable.put("p","put");
        hashtable.put("c","cat");
        hashtable.put("m","move");
        hashtable.put("f","fun");

        System.out.println(hashtable);
        hashtable.remove("f");
        System.out.println(hashtable);
        System.out.println(hashtable.containsKey("f"));
        System.out.println(hashtable.containsValue("cat"));
        Set keys = hashtable.keySet();
        System.out.println(keys);
        Collection values = hashtable.values();
        System.out.println(values);
    }
}

HashMap和HashTable,保存的数据都是无序的,Map 的另一个实现类TreeMap主要功能是按照key对集合中的元素进行排序。

TreeMap使用

import javax.jws.soap.SOAPBinding;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
public class Test4 {
    public static void main(String[] args) {
        TreeMap treeMap = new TreeMap();
        treeMap.put(new User(3, "java"), "java");
        treeMap.put(new User(5, "javaME"), "javaME");
        treeMap.put(new User(2, "javaEE"), "javaEE");
        treeMap.put(new User(1, "javaCC"), "javaCC");
        treeMap.put(new User(4, "javaBB"), "javaBB");
        treeMap.put(new User(6, "javaSE"), "javaSE");
        System.out.println(treeMap);
        Set keys = treeMap.keySet();
        Iterator iterator = keys.iterator();
        while (iterator.hasNext()) {
            Object key = iterator.next();
            System.out.println(key + "-" + treeMap.get(key));
        }
    }
}

class User implements Comparable {
    private int id;
    private String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

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


    @Override
    public int compareTo(Object o) {
        if (o instanceof User) {
            User user = (User) o;

            if (this.id > user.id) {
                return 1;
            } else if (this.id == user.id) {

            } else {
                return -1;
            }
        }
        return 0;
    }
}

Collections 工具类

Collection 接口,List和Set的父接口。
Collection不是接口,他是一个工具类,专门提供了一些对集合的操作,方便开发者去使用,完成相应的业务功能。
Collections针对于集合的工具类, Collection
Arrays针对数组的工具类,Array

方法描述
public static sort()对集合进行排序
public static int binarySearch(List list,Objetc v)查找v在list的位置,集合必须是升序排列
public static get(List list,int index)返回list中index位置的值
public static void reverse(List list)对list进行反序输出
public static void swap(List list,int i, int j)交换集合中指定位置的两个元素
public static void fill(List list,Object obj)将集合中所有元素替换成 obj
public static Object min(List list)返回集合中最小值
public static Object max(List list)返回集合中最大值
public static boolean replaceAll(List list,Object old,Object new)在list集合中用new替换old
public static boolean addAll(List list,Object…obj)向集合中添加元素
可变参数
public static void test(int ... arg){
    
}

可以传任意类型,任意数量的参数,多态的一种体现

public static void test(Object ... arg){
    
}

Java中默认输出对象的格式:对象所属的全类名(全限定类名)带着包名的类名+@+对象的哈希值

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值