容器框架(Collection、Map)

一、Collection(单列集合)

1.1 集合概述

  • 集合:是Java提供的一种容器,可以用来存储多个数据。

集合和数组都是容器,两者的区别?

  • 数组的长度是固定的,集合的长度是可变的。

  • 数组存储的是同一类型的元素,可以是基本类型,也可以是引用类型。

    集合存储的都是对象(引用类型),而且对象的类型可以不一致。在开发中,一般当对象多的时候可以用集合进行存储

1.2 集合框架

1.3 Collection集合共性的方法:

  • public boolean add(E e); 添加元素
  • public void clear(); 清空集合中所有的元素
  • public boolean remove(E e); 删除元素:集合中存在元素,删除,返回true;不存在,删除失败,返回false
  • public boolean contains(E e); 判断当前集合中是否包含给定的对象
  • public boolean isEmpty(); 判断当前集合是否为空
  • public int size(); 返回集合中元素的个数
  • public Object[] toArray(); 把集合中的元素,存储到数组中
//java.util.Collection接口:所有单列集合最顶层的接口,里面定义了所有单列集合共性的方法。
public class Demo1Collection {
    public static void main(String[] args) {
        //使用多态创建集合
        Collection<String> coll = new ArrayList<>();
        //添加元素:add
        boolean b = coll.add("KD");
        //System.out.println(b); //true 添加成功
        coll.add("PG");
        coll.add("James");
        coll.add("KT");
        System.out.println(coll); //[KD, PG, James, KT] 重写了toString()
        //当前集合所含元素个数:size
        System.out.println("当前集合中含有元素:" + coll.size() + "个"); //4
        //移除元素:remove
        coll.remove("PG");
        System.out.println(coll); //[KD, James, KT]
        System.out.println("移除一个元素后,元素个数:" + coll.size() + "个"); //3
        //判断当前集合中是否含有给定的对象:contains
        boolean b1 = coll.contains("PG");
        System.out.println("集合中是否含有元素'PG':" + b1); //false
        //判断当前集合是否为空:isEmpty
        System.out.println("当前集合是否为空:" + coll.isEmpty()); //false
        //把集合中元素存储到数组中
        Object[] obj = coll.toArray();
        System.out.println("数组长度:" + obj.length); //3
        //遍历数组obj
        System.out.print("数组元素:");
        for (int i = 0; i < obj.length; i++) {
            System.out.print(obj[i] + " ");
        }
        System.out.println();
        //清空集合:clear 并不删除集合,集合还存在。
        coll.clear();
        System.out.println(coll); //[]
    }
}

1.4 集合的遍历方式:

  • (带索引的集合可用)普通for循环
  • 迭代器
  • for-each循环

二、Iterator迭代器

2.1 Iterator接口

​ 在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口java.util.Iterator

Iterator接口也是java集合中的一员,但它与Collection、Map接口有所不同,Collection与Map接口主要用于存

储元素,而Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。

迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。一直把集合中的所有元素全部取出,这种取出方式专业术语称为迭代。

2.2 迭代器的使用

java.util.Iterator接口:迭代器(对集合进行遍历)

  1.有两个常用的方法:
      boolean hasNext();   如果仍有元素可以迭代,则返回true
          判断集合中还有没有下一个元素,有就返回true,没有就返回false
      E next();    返回迭代的下一个元素
          取出集合中的下一个元素

  2.Iterator迭代器,是一个接口,我们无法使用,需要使用Iterator接口的实现类对象,获取实现类的方式比较特殊:
    Collection接口中有一个方法,叫iterator(),这个方法返回的就是迭代器的实现类对象
      Collection.Iterator<E> iterator();  返回在此Collection的元素上进行迭代的迭代器。

  3.迭代器的使用步骤(重点):
      ① 使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
      ② 使用Iterator接口中的方法hasNext()判断还有没有下一个元素
      ③ 使用Iterator接口中的方法next()取出集合中的下一个元素

      NoSuchElementException 没有下一个元素异常!
public class Demo1Iterator {
    public static void main(String[] args) {
        //创建一个集合对象
        Collection<String> coll = new ArrayList<>();
        //添加元素
        coll.add("杜兰特");
        coll.add("詹姆斯");
        coll.add("库里");
        coll.add("韦德");
        coll.add("威斯布鲁克");
        coll.add("哈登");

        //获取迭代器对象
        //多态: 接口                     实现类对象
        Iterator<String> iterator = coll.iterator();

        //判断集合中还有没有下一个元素
        while(iterator.hasNext()){
            System.out.println(iterator.next()); //获取该元素
        }

2.3 迭代器实现原理

2.4 For-Each循环

增强for循环(也称for-each循环):JDK1.5之后新特性,专门用来遍历集合和数组。

它的内部原理其实是一个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。

格式:

​ for(数组/集合的数据类型 变量名 :数组/集合名){

​ //操作代码; }

三、泛型Generic

3.1 概述

​ 未知的数据类型。当不确定集合中存储元素的数据类型时,就可以使用泛型来表示。比如:

​ E e : Element

​ T t : Type

3.2 集合(不)使用泛型

  • 不使用泛型:

​ ①好处:默认Object类型,可以存储任意类型的数据

​ ②弊端:不安全,会引发异常。ClassCastException!

public class Demo1Generic {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("abc");
        list.add(1);
        //获取迭代器
        Iterator it = list.iterator();
        //判断还有没有下一个元素: hasNext()
        //有就获取该元素
        while(it.hasNext()){
            Object obj = it.next();
            System.out.println(obj);
        /*  想使用String特有的方法:
              length获取长度;父类不能使用子类特有的方法和属性,多态 Object obj = "abc"
              向下转型
              会抛出 ClassCastException!不能把Integer类型转换为String  */
            String s = (String)obj;
            System.out.println(s.length());
        }
    }
}
  • 使用泛型:

​ ①优点:避免类型转换的麻烦,存什么类型就取出什么类型。

​ ②缺点:泛型是什么类型,只能存储什么类型的数据。

public class Demo2Generic {
    public static void main(String[] args) {
        //使用泛型创建一个集合对象
        ArrayList<String> list =new ArrayList<>();
        //添加元素
        list.add("彭于晏");
        list.add("李一桐");
        list.add("128269");
        //使用迭代器遍历集合
        //获取迭代器对象
        Iterator<String> it = list.iterator();
        //hasNext(): 判断还有没有下一个元素
        while(it.hasNext()){
            //获取该元素
            String s = it.next();
            //存储的都是String类型,可以使用length(),避免了类型转换的麻烦!
            System.out.println(s + "-->" + s.length());
        }
    }
}

3.3 泛型的定义与使用

3.3.1 含有泛型的类

/*
    定义一个含有泛型的类,模拟ArrayList集合:
        泛型是一个未知的数据类型,当我们不确定什么数据类型的时候,可以使用泛型。
        泛型可以接受任意的数据类型,可以是Integer、String、Student... 但必须是同一数据类型!
        创建对象的时候确定泛型的数据!
 */
public class Test01GenericClass {
    public static void main(String[] args) {
        GenericClass gc = new GenericClass();
        gc.setName("只能是字符串");

        //创建对象的时候确定泛型的数据类型
        GenericClass<Integer> gc2 = new GenericClass<>();
        gc2.setName(206);
        System.out.println(gc2.getName());
    }
}

//定义和使用含有泛型的类:
class GenericClass <E> {
    private E name;

    public E getName(){
        return name;
    }
    public void setName(E name){
        this.name = name;
    }
}

3.3.2 含有泛型的方法

/*
    定义含有泛型的方法:泛型定义在方法的修饰符和返回值类型之间

    格式:
        修饰符 <E> 返回值类型 方法名(参数列表(使用泛型)){
            方法体;
        }

    含有泛型的方法,在调用方法时确定泛型的数据类型!
    传递什么类型的参数,泛型就是什么类型
 */
public class GenericMethod {
    public static void main(String[] args) {
       demo1("KD");
       demo1(12);
       demo1(true);
       demo1('X');
    }

    public static <E> void demo1(E e){
        System.out.println(e + "-Collection.Generic");
    }
}

3.3.3 含有泛型的接口

3.4 泛型通配符

  • 代表任意的数据类型
  • 基本使用

    ​ ①不能创建对象使用

    ​ ②只能作为方法的参数

    public class Demo3Generic {
        public static void main(String[] args) {
            ArrayList<String> list1 = new ArrayList<>();
            list1.add("KD");
            list1.add("PG");
    
            ArrayList<Integer> list2 = new ArrayList<>();
            list2.add(35);
            list2.add(13);
    
            printArray(list1);
            System.out.println("--------------");
            printArray(list2);
    
        }
        /*
            定义一个方法,能遍历所有数据类型的ArrayList集合
            这时候我们不知道ArrayList集合是什么数据类型,可以用泛型的通配符?来接收数据类型
            注意:
                泛型是没有继承概念的!
         */
        public static void printArray(ArrayList<?> list){
            //使用for-each循环遍历集合
            for(Object obj:list){
                System.out.println(obj);
            }
        }
    }
    
  • 高级使用<受限泛型>

    ​ ①泛型上限:? extends E 代表使用的泛型只能是E类型的子类/本身

    ​ ②泛型下限:? super E 代表使用的泛型只能是E类型的父类/本身

    public class Demo4Generic {
        public static void main(String[] args) {
            Collection<Integer> cl1 = new ArrayList<>();
            Collection<String> cl2 = new ArrayList<>();
            Collection<Number> cl3 = new ArrayList<>();
            Collection<Object> cl4 = new ArrayList<>();
    
            getElement1(cl1);
            //getElement1(cl2); //报错!
            getElement1(cl3);
            //getElement1(cl4); //报错!
    
            //getElement2(cl1); //报错!
            //getElement2(cl2); //报错!
            getElement2(cl3);
            getElement2(cl4);
        }
        //泛型的上限:此时的泛型?,必须是Number类型或Number类型的子类
        public static void getElement1(Collection<? extends Number> coll) {}
        //范兴德下限:此时的泛型?,必须是Number类型或Number类型的父类
        public static void getElement2(Collection<? super Number> coll) {}
    }
    

四、数据结构

4.1 栈和队列:

4.2 数组:

4.3 链表:

4.4树:

五、List集合

5.1 List接口的特点:

  • 有序的集合,存储元素和取出元素的顺序是一致的(存储123 取出123)

  • 允许存储重复的元素

  • 有索引,包含了一些带索引的方法

  • 带索引的方法(特有):

    ​ public void add(int index, E e); 将指定的元素,添加到该集合中指定的位置上。

    ​ public E get(int index); 返回集合中指定位置的元素

    ​ public E remove(int index); 移除列表中指定位置的元素,返回的是被移出的元素

    ​ public E set(int index, E e); 用指定元素替换集合中指定位置的元素,返回值为更新前的元素

    注意:操作索引的时候,一定要防止索引越界异常!IndexOutOfBoundsException!

5.2 List接口的实现类

5.2.1 ArrayList

  • 底层是一个数组,查询快,增删慢;不同步,多线程

5.2.2 LinkedList

  • 底层是一个链表,查询慢,增删快;不同步,多线程

  • 特有方法:

    ​ public void addFirst(E e); 将指定元素插入到此列表的开头

    ​ public void addLast(E e); 将指定元素添加到此列表的结尾

    ​ public void push(E e); 将元素推入此列表所表示的堆栈(相当于addFirst( ))

    ​ public E getFirst(); 返回此列表的第一个元素

    ​ public E getLast(); 返回此列表的最后一个元素

    ​ public boolean isEmpty(); 判断列表是否为空,如果集合不包含元素,返回true

    ​ public E removeFirst(); 移除并返回此列表的第一个元素

    ​ public E removeLast(); 移除并返回此列表的最后一个元素

    ​ public E pop(); 从此列表所处的堆栈中弹出一个元素(相当于removeFirst( ))

5.2.3 Vector

  • 所有单列集合的祖先,底层是一个数组,单线程,同步。(了解就行)

六、Set集合

6.1 Set接口的特点:

  • 不允许存储重复的元素
  • 没有索引,也没有带索引的方法,也不能用普通的for循环遍历

6.2 HashSet类

6.2.1 特点:

  • 不允许存储重复的元素
  • 没有索引,也没有带索引的方法,也不能用普通的for循环遍历
  • 是一个无序的集合,存储元素和取出元素的顺序可能不一样
  • 底层是一个哈希表(HashMap),查询速度非常快

6.2.2 哈希值、哈希冲突

  • 哈希值:是一个十进制整数,由系统随机给出(就是对象的地址值,是计算机底层模拟出来的一个逻辑地址,并不是数据实际存储的物理地址。)

  • 在Object方法中,可以获取对象的哈希值
        int hashCode(); 返回该对象的哈希码值
        hasCode方法的源码:
            public native int hashCode();
            native: 代表该方法调用的是本地操作系统的方法
    
  • 哈希冲突:两个元素不同,但哈希值相同。

6.2.3 哈希表(HashMap)

6.2.4 Set集合存储元素不重复的原理

前提:Set集合中的元素必须重写hashCode()和equals()

6.3 LinkedHashSet类

  • 有序,不重复,无索引。
  • 底层是一个哈希表 + 链表;多了一层链表(记录元素的存储顺序),保证元素有序。

七、Collections集合工具类

java.util.Collections 是集合工具类,用来对集合进行操作。
常用方法:
  public static <T> boolean addAll(Collection<T> c, T... elements); 往集合中添加一些元素
  public static void shuffle(List<?> list); 打乱集合顺序
  public static <T> void sort(List<T> list); 将集合中元素按照默认规则排序(默认是升序)
  public static <T> void sort(List<?> list,Comparator<? super T>); 将集合中元素按照指定规则排序
/*
    public static <T> void sort(List<T> list); 将集合中元素按照默认规则排序(默认是升序)
    注意:
        sort(List<T> list)使用前提:
        被排序的集合里边存储的元素,必须实现Comparable,重写接口中的compareTo()定义排序的规则
        Comparable接口的排序规则:自己(this) - 参数:升序
 */
public class Demo2Sort {

    public static void main(String[] args) {
        /*
            注意:
                Integer、String类均实现了Comparable接口,且重写了其中的compareTo()
                因此,能够调用Collections.sort()并按照它们的规则进行排序
         */
        ArrayList<Integer> list01 = new ArrayList<>();
        //往集合中添加元素
        Collections.addAll(list01,2,8,6);
        System.out.println(list01);
        //打乱集合
        Collections.shuffle(list01);
        System.out.println(list01);
        //排序(默认是升序)
        Collections.sort(list01);
        System.out.println(list01);

        ArrayList<String> list02 = new ArrayList<>();
        Collections.addAll(list02,"a","c","b");
        System.out.println(list02); //[a, c, b]
        Collections.sort(list02);
        System.out.println(list02);  //[a, b, c]

        ArrayList<Players> list03 = new ArrayList<>();
        Players p1 = new Players("杜兰特",35);
        Players p2 = new Players("詹姆斯",23);
        Players p3 = new Players("保罗·乔治",13);
        Collections.addAll(list03,p1,p2,p3);
        System.out.println(list03); //[Players{name= 杜兰特,numbers= 35}, Players{name= 詹姆斯,numbers= 23}, Players{name= 保罗·乔治,numbers= 13}]
        //Collections.sort(list03); //没有实现Comparable接口时会报错! Players类必须实现Comparable接口,重写其中的compareTo()
        Collections.sort(list03);
        System.out.println(list03); //[Players{name= 保罗·乔治,numbers= 13}, Players{name= 詹姆斯,numbers= 23}, Players{name= 杜兰特,numbers= 35}]
    }
}

class Players implements Comparable<Players>{
    private String name;
    private int numbers;

    public Players(){

    }
    public Players(String name,int numbers){
        this.name = name;
        this.numbers = numbers;
    }

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

    public int getNumbers(){
        return numbers;
    }
    public void setNumbers(int numbers){
        this.numbers = numbers;
    }

    public String toString(){
        return "Players{name= " + name + ",numbers= " + numbers + "}";
    }

    //重写compareTo()
    public int compareTo(Players p){
        //自定义比较的规则:比较两个人的球衣号
        return this.numbers - p.numbers;    //球衣号码升序
    }
}
/*
  public static <T> void sort(List<?> list,Comparator<? super T>); 将集合中元素按照指定规则排序
 */
public class Demo3Sort {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,1,3,2);
        System.out.println(list); //[1, 3, 2]
        
                                //匿名内部类
        Collections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //重写比较的规则:
                return o1-o2; //升序
             //   return o2-o1; //降序
            }
        });
        System.out.println(list); //[1, 2, 3]

        ArrayList<Stars> list1 = new ArrayList<>();
        Stars s1 = new Stars("陈乔恩",28);
        Stars s2 = new Stars("刘诗诗",26);
        Stars s3 = new Stars("z汤唯",22);
        Stars s4 = new Stars("q汤唯",22);
        Collections.addAll(list1,s1,s2,s3,s4);
        System.out.println(list1);
        Collections.sort(list1, new Comparator<Stars>() {
            @Override
            public int compare(Stars o1, Stars o2) {
                //按照年龄升序排序:
                return o1.getAge()-o2.getAge();
            }
        });
        /* 扩展了解:
        Collections.sort(list1, new Comparator<Stars>() {
            @Override
            public int compare(Stars o1, Stars o2) {
                int result = o1.getAge() - o2.getAge();
                if(result == 0){
                    //如果年龄相同,按姓名第一个字母排序
                    return o1.getName().charAt(0) - o2.getName().charAt(0); //升序
                }
                return result;
            }
        });
         */
        System.out.println(list1);
    }
}

class Stars {
    private String name;
    private int age;

    public Stars() {
    }
    public Stars(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 "Stars{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

八、Map(双列集合)

8.1 Map集合的特点

java.util.Map<K,V>接口:

  • 是一个双列集合,一个元素包含两个值(K:键,V:值)
  • Map集合中的元素,key和value的数据结构可以相同,也可以不同。
  • Map集合中的元素,key是唯一的,不允许重复,value可以重复。
  • Map集合中的元素,键和值是一一对应的,一个键对应一个值。

8.2 Map接口常用子类

8.2.1 HashMap<K,V>类

  • 无序:存储元素和取出元素的顺序可能不一样

  • 底层是一个哈希表:查询速度特别快

    ​ JDK1.8之前:数组 + 单向链表

    ​ JDK1.8之后:数组 + 单向链表/红黑树(链表长度超过8时):提高查询速度

  • 不同步,多线程,不安全。

8.2.2 LinkedHashMap<K,V>类

java.util.LinkedHashMap extends HashMap<K,V>

  • 有序:存储元素和取出元素的顺序是一样的
  • 底层是一个哈希表 + 链表(保证迭代的顺序)
  • 不同步,多线程,不安全。

8.3 Map接口常用方法

  • public V put(K key,V value); 把指定的键和指定的值添加到Map集合当中去

    ​ 返回值:V

    ​ 存储键值对的时候,key不重复,返回值V是null

    ​ 存储键值对的时候,key重复,会用新的value替换Map中重复的value,返回被替换掉的value值

  • public V remove(Object key); 把指定的键 所对应的键值对元素 从Map集合中删除,返回被删除元素的值

    ​ 返回值:V

    ​ key不存在,返回值V为null

    ​ key存在,V返回被删除元素的值

  • public boolean containsKey(Object key); 判断集合中是否包含指定的key

    ​ 包含返回true

    ​ 不包含返回false

  • public V get(Object key); 根据指定的键,在Map中获取对应的值

    ​ 返回值:V

    ​ key不存在,V返回null

    ​ key存在,V返回对应的value值

8.4 遍历Map集合

8.4.1 ①:通过键找值的方式

Map集合中的方法:
    public Set<k> keySet(); 返回此映射中包含的Set视图。
实现步骤:
    a. 使用Map集合中的keySet()方法,把Map集合中所有的键取出来,存到Set集合中
    b. 遍历Set集合,获取Map集合中的每一个key
    c. 调用Map集合中的public V get(Object key),通过key找到value
public class Demo2KeySet {
    public static void main(String[] args) {
        //创建一个Map集合,多态:
        Map<String,Integer> map = new HashMap<>();
        //往map集合中添加元素: put
        map.put("布鲁克林篮网",71113);
        map.put("洛杉矶湖人",323);
        map.put("洛杉矶快船",213);

        //keySet(): 把map集合中速所有的键取出来,存到Set集合中
        Set<String> set = map.keySet();
        //遍历Set集合方式:①迭代器
        //获取迭代器
        Iterator<String> it = set.iterator();
        //hasNext(): 判断还有没有下一个元素
        while(it.hasNext()){
            //获取该元素: key
            String key = it.next();
            //调用Map集合get(Object key)方法,通过键找到值
            Integer v = map.get(key);
            System.out.println(key + "=" + v);
        }
        System.out.println("---------------------------");
        //for-each循环:遍历Set集合
        for(String sKey:map.keySet()){
            //调用Map集合get(Object key)方法,通过键找到值
            System.out.println(sKey + "=" + map.get(sKey));
        }
    }
}

8.4.2 ②:通过内部接口Map.Entry<K,V>的Entry对象的方式

Map集合中有一个内部接口:Map.Entry<K,V>;
作用:在创建Map集合的时候,会自动生成一个Entry对象,用来记录键与值(键值对对象,键与值的映射关系)。

实现步骤:
    a. 使用Map集合中的entrySet(),把生成的Entry对象存放在Set集合中;
    b. 遍历Set集合,获取每一个Entry对象;
    c. 通过Entry对象来调用Map.Entry<K,V>接口中的两个方法:
        getKey( ),getValue( ), 获取键和值。
public class Demo3EntrySet {
    public static void main(String[] args) {
        //创建一个Map集合,多态:
        Map<String,String> map = new HashMap<>();
        //添加元素:键值对。put();
        map.put("吴奇隆","刘诗诗");
        map.put("陈晓","陈妍希");
        map.put("尔康","紫薇");

        //entrySet(); 把Entry对象(键值对对象)存放在Set集合中
        Set<Map.Entry<String, String>> entries = map.entrySet();

        //遍历Set集合:for-each循环
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey(); //获取键
            String value = entry.getValue();  //获取值
            System.out.println(key + "=" + value);
        }
        System.out.println("----------------");

        //遍历Set集合:迭代器Iterator
        Iterator<Map.Entry<String, String>> it = entries.iterator();
        while(it.hasNext()){
            Map.Entry<String, String> entry = it.next();
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
        }
    }
}

8.5 HashMap存储自定义类型键值

Map集合保证键是唯一的,不能重复:
    作为key的元素,必须重写Object类中的hashCode()和equals()!

8.6 Hashtable<K,V>类

java.util.Hashtable<K,V>集合 implements Map<K,V>接口

Hashtable底层是一个哈希表,是一个安全的单线程集合,速度慢。
HashMap:底层是一个哈希表,是一个不安全的多线程集合,速度快。

Hashtable集合,不能存储null值,null键
HashMap(之前学的所有集合):可以存储null值,null键

Hashtable和Vector集合一样,在JDK1.2版本之后被更先进的集合(HashMap,ArrayList)取代了
Hashtable的子类Properties集合依然活跃在历史的舞台,并且是唯一一个和IO流相关的集合!
Vector:最早期的单列集合;Hashtable:最早期的双列集合

8.7 JDK9新特性

JDK9新特性:
    List接口,Set接口,Map接口:里面增加了一个静态的方法of();可以给集合一次性添加多个元素
    static <E> List<E> of(E...elements);
    使用前提:
        当集合中存储的元素个数已经确定了,不再改变时使用。
    注意:
        1.of方法只适用于List、Set、Map接口,不适用于接口的实现类
        2.of方法的返回值是一个不能改变的集合,集合不能再使用add、put方法添加元素,会抛出异常
        3.Set、Map接口在调用of方法时,不能有重复的元素,否则会抛出异常。

        UnsupportedOperationException! 不支持操作异常!
posted @ 2021-06-14 23:23  Sleepinglion  阅读(306)  评论(0)    收藏  举报