8.集合框架

集合

一、概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现类似数组的功能

二、集合和数组的区别:

​ (1)数组长度固定,集合长度不固定

​ (2)数组可以存储基本类型和引用类型,集合只能存储引用类型

三、位置:java.util.*

Collection体系

img

Collection父接口

  • 特点:代表一组任意类型的对象,无序、无下标、不能重复。

  • 创建集合

Collection collection = new ArrayList()

常用方法

  • 添加元素
collection.add();
  • 删除元素
collection.remove;
collection.clear;
  • 遍历元素【重点】

    • 使用增强for
    for(Object object : collection){}
    
    • 使用迭代器
    //haNext(); 有没有下一个元素
    //next(); 获取下一个元素
    //remove(); 删除当前元素
    Iterator it = collection.iterator();
    while(it.hasNext()){
      String object = (String)it.next(); //强转
      // 可以使用it.remove(); 进行移除元素
      // collection.remove(); 不能用collection其他方法 会报并发修改异常
    }
    
  • 判断

collection.contains();
collection.isEmpty();

List子接口

特点:有序、有下标、元素可以重复

方法:

​ 1.void add(int index, Object o) //在index位置插入对象o

​ 2.boolean addAll(int index, Collection c) //将一个集合中的元素添加到此集合的index位置

​ 3.Object get(int index) //返回集合中指定位置的元素

​ 4.List subList(int fromIndex, int toIndex) //返回fromIndex和toIndex之间的集合元素

public class Demo1 {
    public static void main(String[] args) {
        //创建集合对象
        List list = new ArrayList<>();
        //1.添加元素
        list.add("苹果");
        list.add("小米");
        list.add(0,"华为");
        System.out.println("元素个数"+list.toString());
        //2.删除元素
        //list.remove("苹果");//按元素删除
        //list.remove(0);//按脚标删除
        //System.out.println("删除之后"+list.toString());
        //3.遍历
        //3.1使用for
        System.out.println("-------------------");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        //3.2使用增强for
        System.out.println("-------------------");
        for (Object object: list) {
            System.out.println(object);
        }
        //3.3使用迭代器
        System.out.println("-------------------");
        Iterator it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //3.4使用列表迭代器ListIterator(),和Iterator()的区别:ListIterator()可以向前或向后遍历,添加、删除、修改元素
        System.out.println("----------从前往后---------");
        ListIterator lit = list.listIterator();
        while (lit.hasNext()){
            System.out.println(lit.nextIndex()+":"+lit.next());
        }
        System.out.println("----------从后往前---------");
        while (lit.hasPrevious()){
            System.out.println(lit.previousIndex()+":"+lit.previous());
        }
        //4.判断
        System.out.println(list.contains("苹果"));
        System.out.println(list.isEmpty());
        //5.获取位置
        System.out.println(list.indexOf("华为"));
    }
}
public class Demo2 {
    public static void main(String[] args) {
        //创建集合
        List list = new ArrayList();
        //1.添加数字数据(自动装箱)
        list.add(20);
        list.add(30);
        list.add(40);
        list.add(50);
        list.add(60);
        System.out.println("元素个数"+list.size());
        System.out.println(list.toString());
        //2.删除操作
        //list.remove(20);//调用remove调用的是使用脚标删除
        list.remove((Object) 20);
        list.remove(new Integer(30));
        System.out.println("删除元素"+list.size());
        System.out.println(list.toString());
        //3.subList:返回子集合,含头不含尾
        List sublist = list.subList(0,2);
        System.out.println(sublist.toString());
    }
}

List实现类

1.ArrayList【重点】
数组结构实现,查询块、增删慢
JDK1.2版本,运行效率块、线程不安全

源码分析:

​ (1)DEFAULT_CAPACITY = 10; 默认容量
​ 没向集合中添加元素时,容量为0

​ (2)elementData 存放元素的数组
​ (3)size 实际的元素个数
​ (4)add() 添加元素

public class Demo1 {
    public static void main(String[] args) {
        //创建集合
        ArrayList arrayList = new ArrayList<>();
        //1.添加元素
        Student s1 = new Student("刘德华",20);
        Student s2 = new Student("郭富城",22);
        Student s3 = new Student("梁朝伟",18);
        arrayList.add(s1);
        arrayList.add(s2);
        arrayList.add(s3);
        System.out.println("元素个数"+arrayList.size());
        System.out.println(arrayList.toString());
        //2.删除元素
//        arrayList.remove(s1);//可直接使用
//        arrayList.remove(new Student("郭富城",22));//重写equals后才能使用
//        System.out.println("删除之后"+arrayList.size());
//        System.out.println(arrayList.toString());
        //3.遍历【重点】
        //3.1使用迭代器
        System.out.println("===================");
        Iterator it = arrayList.iterator();
        while (it.hasNext()){
            Student s = (Student) it.next();
            System.out.println(s.toString());
        }
        //3.2使用列表迭代器
        ListIterator lit = arrayList.listIterator();
        System.out.println("======从前往后=======");
        while (lit.hasNext()){
            Student s = (Student) lit.next();
            System.out.println(s.toString());
        }
        System.out.println("======从后往前=======");
        while (lit.hasPrevious()){
            Student s = (Student) lit.previous();
            System.out.println(s.toString());
        }
        //4.判断
        System.out.println("===================");
        System.out.println(arrayList.contains(s1));
        System.out.println(arrayList.contains(new Student("郭富城",22)));//因为重写了equals,所以这种方式也可以
        System.out.println(arrayList.isEmpty());
        //5.查找
        System.out.println("===================");
        System.out.println(arrayList.indexOf(s1));
        System.out.println(arrayList.indexOf(new Student("郭富城",22)));//因为重写了equals,所以这种方式也可以
    }
}

2.Vector
数组结构实现,查询快、增删慢
JDK1.0版本,运行效率慢,线程安全

3.LinkedList【重点】
双向链表结构实现,增删快、查询慢

public class Demo1 {
    public static void main(String[] args) {
        //创建集合
        LinkedList linkedList = new LinkedList<>();
        //1.添加元素
        Student s1 = new Student("刘德华",20);
        Student s2 = new Student("郭富城",22);
        Student s3 = new Student("梁朝伟",18);
        linkedList.add(s1);
        linkedList.add(s2);
        linkedList.add(s3);
        linkedList.add(s1);
        System.out.println("元素个数:"+linkedList.size());
        System.out.println(linkedList.toString());
        //2.删除
        //linkedList.remove(s1);
        //System.out.println("删除之后:"+linkedList.size());
        //linkedList.clear();
        
        //3.遍历
        //3.1for遍历
        System.out.println("==========for============");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }
        //3.2增强for遍历
        System.out.println("==========增强for=========");
        for (Object object:linkedList) {
            Student s = (Student) object;
            System.out.println(s.toString());
        }
        //3.3使用迭代器
        System.out.println("============迭代器=========");
        Iterator it = linkedList.iterator();
        while (it.hasNext()){
            Student s = (Student) it.next();
            System.out.println(s.toString());
        }
        //3.4使用列表迭代器
        System.out.println("========列表迭代器=========");
        ListIterator lit = linkedList.listIterator();
        while (lit.hasNext()){
            Student s = (Student) lit.next();
            System.out.println(s.toString());
        }
        //4.判断
        System.out.println(linkedList.contains(s1));
        System.out.println(linkedList.isEmpty());
        //5.获取
        System.out.println(linkedList.indexOf(s1));
    }
}

泛型

  • 本质:参数化类型,把类型作为参数传递

  • 常见的形式:泛型类、泛型接口、泛型方法

  • 语法:<T,...> T称为类型占位符,表示一种引用类型

  • 好处:(1)提高代码的重用性

​ (2)防止类型转换异常,提高代码的安全性


泛型类

  • 语法:类名<>
// 写一个泛型类
public class MyGeneric<T>{
  //使用泛型T
  //1 创建变量
  T t;
  //2 泛型作为方法的参数
  public void show(T t){
    sout(t);
  }
  //3 泛型作为方法的返回值
  public T getT(){
    return t;
  }
}
// 使用泛型类
public class TestGeneric{
  public static void main(String[] args){
    //使用泛型类创建对象
    // 注意: 1. 泛型只能使用引用类型
    //			 2. 不用泛型类型对象之间不能相互赋值
    MyGeneric<String> myGeneric = new MyGeneric<String>();
    myGeneric.t = "hello";
    myGeneric.show("hello world!");
    String string = myGeneric.getT();
    
    MyGeneric<Integer> myGeneric2 = new MyGeneric<Integer>();
    myGeneric2.t = 100;
    myGeneric2.show(200);
    Integer integer = myGeneric2.getT();
    
  }
}

注:(1)泛型只能是引用类型

​ (2)不同泛型对象不能相互赋值

​ (2)错误的使用方法:不能实例化,因为不知道具体是什么类型,也就不知道这个构造方法可不可以使用

T t1 = new T();//错误使用

泛型接口

  • 语法:接口名
  • 注意:不能泛型静态常量
  • 两种使用方式:

    (1)写实现类的时候直接确定好类型

public class MyInterfaceImpl implements MyInterface<String>{
    public String server(String t) {
        System.out.println(t);
        return t;
    }
}
MyInterfaceImpl impl = new MyInterfaceImpl();
impl.server("xx");

​ (2)实现类也变成泛型类,使用的时候再去定义

public class MyInterfaceImpl2<T> implements MyInterface<T>{
    public T server(T t) {
        System.out.println(t);
        return null;
    }
}
MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImpl2<>();
impl2.server(1000);

泛型方法

  • 语法 返回值类型
public class MyGenericMethod {
    public <T> void show(T t){
        System.out.println("泛型方法:"+t);
    }
}
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("中国加油");
myGenericMethod.show(2022);
myGenericMethod.show(3.14);

泛型集合

  • 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致

  • 特点:

    • 编译时即可检查,而非运行时抛出异常
    • 访问时,不必类型转换(拆箱)
    • 不同泛型之间引用不能互相赋值,泛型不存在多态

错误示范:

public class Demo3 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList<>();
        arrayList.add("xxx");
        arrayList.add("yyy");
        arrayList.add(10);
        arrayList.add(20);

        for (Object object: arrayList) {
            String str = (String) object;  //类型转换异常
            System.out.println(str);
        }
    }
}

正确使用:

public class Demo3 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("xxx");
        arrayList.add("yyy");

        for (String string:arrayList) {
            System.out.println(string);
        }
//------------------------------------------------------------------------------
        ArrayList<Student> arrayList1 = new ArrayList<Student>();
        Student s1 = new Student("刘德华",20);
        Student s2 = new Student("郭富城",22);
        Student s3 = new Student("梁朝伟",18);
        arrayList1.add(s1);
        arrayList1.add(s2);
        arrayList1.add(s3);

        Iterator<Student> it = arrayList1.iterator();
        while (it.hasNext()){
            Student s = it.next();
            System.out.println(s.toString());
        }
    }
}

Set子接口

  • 特点:无序、无下标、元素不可重复

  • 方法:全部继承自Collection中的方法

  • 增、删、遍历、判断与Collection一致

    • 注意:由于Set是无序的,没有角标,所以删除元素时不能使用角标删除,遍历时也不能使用for

Set实现类

  • HashSet【重点】

    • 基于HashCode计算元素存放位置
    • 基于HashCode实现元素不重复
    • 当存入元素的哈希码相同时,会调用equals进行确认,如果为true,则拒绝后者存入
  • TreeSet

    • 基于排列顺序实现元素不重复

HashSet

  • 存储结构:哈希表(数组+链表+红黑树)

  • 存储过程(重复依据)

    1. 根据hashCode计算保存的位置,如果位置为空,直接保存,若不为空,进行第二步
    2. 再执行equals方法,如果equals为true,则认为是重复,否则形成链表
  • 特点:基于HashCode计算元素存放位置

    • 利用31这个质数,减少散列冲突
      • 31提高执行效率 31 * i = (i << 5) - i 转为移位操作
    • 当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入
  • 新建集合

HashSet<String> hashSet = new HashSet<String>();
  • 添加元素
hashSet.add( );
  • 删除元素
hashSet.remove( );
  • 遍历操作

    • 增强for

      for( type type : hashSet)
      
    • 迭代器

      Iterator<String> it = hashSet.iterator( );
      
  • 判断

    hashSet.contains( );
    hashSet.isEmpty();
    

TreeSet

  • 基于排列顺序实现元素不重复

  • 实现了SortedSet接口,对集合元素自动排序

  • 元素对象的类型必须实现Comparable接口,指定排序规则

  • 通过CompareTo方法确定是否为重复元素

补充:Comparator

  • Comparator:实现定制比较(比较器)
public class Demo6_TreeSet_Comparator {
    public static void main(String[] args) {
        //创建集合,并指定比较规则
        TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                int n1 = o1.getAge()- o2.getAge();
                int n2 = o1.getName().compareTo(o2.getName());
                return 0;
            }
        });
    }
}

案例

  • 要求:使用TreeSet集合实现字符串按照长度进行排序
public class Demo7_TreeSet_Test {
    public static void main(String[] args) {
        //创建集合,并指定比较规则
        TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int n1 = o1.length() - o2.length();
                int n2 = o1.compareTo(o2);
                return n1==0?n2:n1;
            }
        });
        //添加数据
        treeSet.add("apple");
        treeSet.add("lisi");
        treeSet.add("beijing");
        treeSet.add("cat");
        treeSet.add("xian");
        System.out.println(treeSet.toString());
    }
}

Map集合

  • Map接口的特点:

    • 用于存储任意键值对(key - value)
    • 键:无序、无下标、不允许重复(唯一)
    • 值:无序、无下标、允许重复
  • 方法:

    • V put (K key,V value)//将对象存入到集合中,关联键值。key重复则覆盖原值
      
    • Object get(Object key)//根据键获取对应的值
      
    • Set<K>//返回所有key
      
    • Collection<V> values()//返回包含所有值的Collection集合
      
    • Set<Map.Entry<K,V>> //键值匹配的Set集合
      

Map接口的使用

image-20220720211129317

public static void main(String[] args) {
        //创建Map集合
        Map<String,String> map = new HashMap<>();
        //1.添加元素
        map.put("cn","中国");
        map.put("uk","英国");
        map.put("usa","美国");
        map.put("cn","zhongguo");//Key重复,Value覆盖
        System.out.println("元素个数:"+map.size());
        System.out.println(map.toString());
        //2.删除
//        map.remove("usa");
//        System.out.println(map.size());
        //3.遍历【重要】
        //3.1使用KeySet()
        System.out.println("------KeySet()------");
//        Set<String> keyset = map.keySet();
//        for (String key:keyset) {
//            System.out.println(key+"---"+map.get(key));
//        }
        Set<String> keyset = map.keySet();
        for (String key:map.keySet()) {
            System.out.println(key+"---"+map.get(key));
        }
        //3.2使用entrySet()方法
        System.out.println("------entrySet()------");
//        Set<Map.Entry<String,String>> entries = map.entrySet();
//        for (Map.Entry<String,String>entry:entries) {
//            System.out.println(entry.getKey()+"---"+entry.getValue());
//        }
        for (Map.Entry<String,String>entry:map.entrySet()) {
            System.out.println(entry.getKey()+"---"+entry.getValue());
        }
        //4.判断
        System.out.println(map.containsKey("cn"));
        System.out.println(map.containsValue("泰国"));
}

HashMap【重点】

  • JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value
  • 默认初始容量16,加载因子0.75
  • 存储结构:数组+链表+红黑树
  • 增、删、遍历、判断方法与上述一致

源码分析总结:

  • HashMap刚创建时,table是null,size是0,节省空间,当添加第一个元素时,table容量调整为16
  • 当元素个数大于阈值(16*0.75 = 12)时,会进行扩容,扩容后的大小为原来的两倍,目的是减少调整元素的个数
  • jdk1.8 当每个链表长度 >8 ,并且数组元素个数 ≥64时,会调整成红黑树,目的是提高效率
  • jdk1.8 当链表长度 <6 时 调整成链表
  • jdk1.8 以前,链表时头插入,之后为尾插入

HashTable

  • JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value

子类:Properties

  • HashTable的子类,要求key和value都是String。通常用于配置文件的读取

TreeMap

  • 实现了SortedMap接口(是map的子接口),可以对key自动排序

Collections工具类

  • 概念:集合工具类,定义了除了存取以外的集合常用方法

  • sort排序

Collections.sort(list);
  • binarySearch二分查找
int i = Collections.binarySearch(list,12);
System.out.println(i);
  • copy复制
List<Integer> dest = new ArrayList<>();
for (int j = 0; j < list.size(); j++) {
    dest.add(0);//满足大小相同,list有多少个数,dest就有多少个0
}
Collections.copy(dest,list);//dest和list大小应该相同
System.out.println(dest.toString());
  • revers反转
Collections.reverse(list);
System.out.println("反转之后:"+list);
  • shuffle打乱
Collections.shuffle(list);
System.out.println("打乱之后:"+list);
  • 补充:
//补充1:list转成数组
System.out.println("---list转成数组---");
Integer[] arr = list.toArray(new Integer[0]);
System.out.println(arr.length);
System.out.println(Arrays.toString(arr));
//补充2:数组转成集合
System.out.println("---数组转成集合---");
String[] names = {"张三","李四","王五"};
//该集合是一个受限集合,不能添加或删除
List<String> list1 = Arrays.asList(names);
System.out.println(list1);
//把基本类型数组转成集合时,需要修改为包装类
Integer[] nums = {100,200,300,400,500};
List<Integer> list2 = Arrays.asList(nums);
System.out.println(list2);
posted @ 2022-10-11 22:10  啦啦米老鼠  阅读(13)  评论(0)    收藏  举报