集合知识点详解

本文详细介绍了Java集合框架中的ArrayList、LinkedList、HashSet和TreeSet的特性和使用,包括添加、删除、遍历等操作,以及泛型在集合中的应用,强调了泛型的安全性和重用性。同时,讲解了Map接口的实现类HashMap和TreeMap,以及如何通过Comparator或Comparable实现自定义排序。

 Collection集合

集合的概念:

        对象的容器,实现了对对象常用的操作

集合和数组的区别:

  1. 数组长度固定,集合长度不固定
  2. 数组可以存储基本类型和引用类型,集合只能存储引用类型

集合的添加删除等操作:

接口 Collection List Set 不能被实例化,其子类的实现类可以被实例化

package file.homework;
import java.util.ArrayList;
import java.util.Collection;
@SuppressWarnings({"all"})
public class HomeWork03 {
    public static void main(String[] args) {
        Collection collection =  new ArrayList();
        collection.add("jack");//添加
        collection.add("mark");
        collection.remove("jack");//删除
        collection.size();//个数
        System.out.println(collection.contains("jack"));//元素是否存在 true
        System.out.println(collection.isEmpty());//集合是否为空 false
    }
}

 集合的遍历:

        增强for循环:快捷键 I

for (Object o :collection) {
            System.out.println(o);
        }

         迭代器(iterator):快捷键itit

Iterator iterator = collection.iterator();//collection集合对象
        while (iterator.hasNext()) {
            Object obj =  iterator.next();
            System.out.println(obj);
        }
Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            String str =  (String)iterator.next();//强转String
            System.out.println(str);
        }

        迭代器迭代过程中的删除不能用集合的删除方法,会抛出异常,需用本身的删除方法

Iterator iterator = collection.iterator();
        while (iterator.hasNext()) {
            String str =  (String)iterator.next();
            iterator.remove();//删除元素
        }

综合运用

集合中添加的是对象的地址,即使删除对象也是删除在集合里面的地址。堆中仍保留该new出来的对象

package com.Colle;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Colle {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Collection col = new ArrayList();
        col.add(new books("三国演义","罗贯中",10.1));
        col.add(new books("小李飞刀","古龙",5));
        col.add(new books("红楼梦","曹雪芹",18.1));
        //得到col的迭代器
        Iterator iterator = col.iterator();
        //用while循环来遍历
        while (iterator.hasNext()) {//判断是否有数据
            //返回下一个元素,类型是Object
            Object obj =  iterator.next();
            //books book =  (books)iterator.next(); 也可以
            System.out.println("obj="+  obj);
        }
    }

}
class books{
    private String name;
    private String author;
    private double price;

    public books(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    public String getName() {
        return name;
    }

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

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "books{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

List

常用方法(列表迭代器)

使用列表迭代器

List实现类 

  • ArrayList 【重点】
    • 数组结构实现,必须要连续空间,查询快、增删慢
    • jdk1.2版本,运行效率块、线程不安全
  • Vector
    • 数组结构实现,查询快、增删慢
    • jdk1.0版本,运行
  • LinkedList
    • 双向链表结构实现,无需连续空间,增删快,查询慢

 ArrayList

        遍历元素

                列表迭代器     

ListIterator li = arrayList.listIterator();
while(li.hasNext()){
  Student s = (Student)li.next(); //从前往后遍历
}

while(li.hasPrevious()){
  Student s = (Student)li.previous();//从后往前遍历
}

         源码分析

                DEFAULT_CAPACITY = 10; //默认容量

                 //注意:如果没有向集合中添加任何元素时,容量0,添加一个后,容量为10

                 //每次扩容是原来的1.5倍

Vector

public static void main(String[] args) {
        Vector vector = new Vector();
        vector.add("jack");
        vector.add("mARK");
        vector.add("tom");
        Enumeration en = vector.elements();//使用枚举遍历
        while (en.hasMoreElements()) {
            Object obj =  en.nextElement();
            System.out.println(obj);
        }
    }

LinkedList(双向链表)

列表迭代器(同list一样)

ListIterator li = linkedlist.listIterator();
while(li.hasNext()){
  System.out.println(li.nextIndex() + ":" + li.next()); //从前往后遍历
}

while(li.hasPrevious()){
  System.out.println(li.previousIndex() + ":" + li.previous()); //从后往前遍历
}

LinkedList和ArrayList区别

ArrayList是数组 而 LinkedList是双向链表

 泛型

  • 本质是参数化类型,把类型作为参数传递
  • 常见形式有泛型类、泛型接口、泛型方法
  • 语法 T成为类型占位符,表示一种引用类型,可以写多个逗号隔开
  • 好处 1. 提高代码重用性 2. 防止类型转换异常,提高代码安全性
  • 泛型可以用于引用类型和基本数据类型的包装类(泛型不能直接使用基本数据类型)

定义一个泛型类

public class MyGeneric<T>{// 写一个泛型类
  //使用泛型T
  //1 创建变量
  T t; 
  public void show(T t){//2 泛型作为方法的参数
    System.out.println(t);
  } 
  public T getT(){//3 泛型作为方法的返回值
    return t;
  }
}

 使用泛型注意:

        1. 泛型只能使用引用类型

         2. 不同泛型类型对象之间不能相互赋值

        3.使用数组的泛型不允许初始化,静态方法或属性不能使用泛型

        (静态和类相关,类的加载在创建对象之前,泛型是在对象的创建所发生的)


public class TestGeneric{
  public static void main(String[] args){
    //使用泛型类创建对象
    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();
    
  }
}

泛型接口

泛型接口的类型,在继承接口或者实现接口时确定 

package com.customgeneric;

public class CustomInterfaceGeneric {
    public static void main(String[] args) {

    }
}
/*
* 泛型接口使用说明:
* 接口中,静态成员不能使用泛型
* 泛型接口的类型,在继承接口或者实现接口时确定
*
* */

//在继承接口 指定泛型接口的类型
interface  IA extends IUsb<String ,Double>{}
//IA接口继承了接口IUsb(则指定了U为String类型,R为Double类型),故class AA 要实现IUsb接口中的所有方法
class AA implements IA{
    @Override
    public Double get(String s) {
        return null;
    }

    @Override
    public void hi(Double aDouble) {}

    @Override
    public void run(Double r1, Double r2, String u1, String u2) {}

    @Override
    public Double method(String s) {
        return IA.super.method(s);
    }
}

//实现接口时,直接指定泛型接口的类型
class BB implements IUsb<Integer,Float>{
    @Override
    public Float get(Integer integer) {
        return null;
    }

    @Override
    public void hi(Float aFloat) {}

    @Override
    public void run(Float r1, Float r2, Integer u1, Integer u2) {}
}

//没有指定类型,默认为Object
//即使不指定,最好写成 class CC implementsIUsb<Object,Object>{...}
class CC implements IUsb{
    @Override
    public Object get(Object o) {
        return null;
    }

    @Override
    public void hi(Object o) {}

    @Override
    public void run(Object r1, Object r2, Object u1, Object u2) { }
}
interface IUsb<U,R>{
    //U name;  不能这样使用
    //普通方法中,可以使用泛型接口
    R get(U u);
    void hi(R r);
    void run(R r1,R r2,U u1,U u2);
    //在JDK8中,可以在接口中使用默认方法,也可以使用泛型
    default R method(U u){
        return null;
    }
}

泛型方法

语法格式:在方法的返回值类型(void/String/int)前面写<T>

调用泛型方法时,不需要填写泛型类型,只填写参数即可,编译器自己会确定类型

package com.customgeneric;

import java.util.ArrayList;

public class CustomMethodGeneric {
    public static void main(String[] args) {
        Car car = new Car();
        car.fly("宝马",100);//当调用方法时,传入参数,编译器就会确定类型
        car.fly(300,100.678);
        Fish<String, ArrayList> fish = new Fish<>(); //T--> String  R-->ArrayList
        fish.hello(new ArrayList(),11.3f);
    }
}
//泛型方法可以定义在普通类,也可定义在泛型类中
class Car{
    public void run(){}//普通方法
    public <T,R> void fly(T t,R r){
        System.out.println(t.getClass());//String
        System.out.println(r.getClass());//Integer  主方法中的100会自动装箱,封装成Integer
    }//泛型方法
}
//泛型类
class Fish<T,R>{
    public void run(){}//普通方法
    public <U,I> void eat(U u,I i){}//泛型方法
    //非泛型方法,而是方法使用了泛型
    public void hi(T t){}
    //泛型方法可以使用类声明的泛型,也可以使用自己声明的泛型
    public <K> void hello(R r,K k){//T使用了类声明的,K 是用了自己声明的
        System.out.println(r.getClass());//ArrayList
        System.out.println(k.getClass());//Float
    }
}

泛型好处

1.提高代码重用性

2.防止类型转换异常,提高代码安全性

泛型集合

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

特点:

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

Student类

public class Student  {
    private String name;
    private int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

泛型集合 

 public static void main(String[] args) {
        ArrayList<String> ar = new ArrayList<>();
        ar.add("jack");
        ar.add("Tom");
       // ar.add(100);报错,类型不匹配。只能是String
        Iterator<String> stringIterator = ar.iterator();
        while (stringIterator.hasNext()) {
            String next =  stringIterator.next();
            System.out.println(next);
        }
        ArrayList<Student> ar1 = new ArrayList<>();
        ar1.add(new Student("Jery",13));
        ar1.add(new Student("Amy",17));
        for (Object o :ar1) {
            System.out.println(o);
        }
    }

 Set

HashSet

基于hashMap实现

存储结构:哈希表(数组+链表+红黑树) 红黑树是JDK1.8之后加的

输出顺序无序,但每次的输出的顺序一致,只是与输入顺序有可能不一致

存储过程(重复依据)

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

特点

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

新建集合 HashSet<String> hashSet = new HashSet<>();

添加元素 hashSet.add( );

删除元素 hashSet.remove( );

遍历操作

​ 1. 增强for for( type type : hashSet)

​ 2. 迭代器 Iterator<String> it = hashSet.iterator( );

判断 hashSet.contains( ); hashSet.isEmpty();

TreeSet

特点

  • 基于排列顺序实现元素不重复
  • 实现SortedSet接口,对集合元素自动排序
  • 元素对象的类型必须实现Comparable接口,指定排序规则
  • 通过CompareTo方法确定是否为重复元素

存储结构:红黑树()

红黑树是一种自平衡的二叉搜索树,它在插入和删除操作后会通过一系列的旋转和重新着色操作来保
持树的平衡。红黑树的每个节点都有一个额外的表示节点颜色的属性,可以是红色或黑色。

红黑树具有以下特性:

每个节点要么是红色,要么是黑色。
根节点是黑色。
所有叶子节点(NIL节点)都是黑色。
如果一个节点是红色的,则其两个子节点都是黑色的。
从任意节点到其每个叶子节点的路径上包含相同数量的黑色节点。

创建集合 TreeSet<String> treeSet = new TreeSet<>()

添加元素 treeSet.add();

删除元素 treeSet.remove();

遍历 1. 增强for 2. 迭代器

判断 treeSet.contains();

补充:TreeSet集合的使用

Comparator 实现定制比较(比较器)

Comparable 可比较的

// 重写compare
@override
public int compare(Person o1, Person o2){
  int n1 = o1.getAge()-o2.getAge();
  int n2 = o1.getName().comareTo(o2.getName());
  return n1 == 0 ? n2 : n1;
}
代码实现

Person类 

在实现Comparable接口时,使用泛型可以指定比较的对象类型。这样在使用compareTo()方法时, 编译器会检查传入的参数类型是否与泛型类型一致,从而避免了类型不匹配的错误

实现Comparable接口就要实现其compareTo方法

package file.homework;
public class Person implements Comparable<Person>{
    private String name;
    private  int age;

    public Person(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 "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    /*
    * 使用int类型来接受比较的结果是因为compareTo()方法需要返回一个整数值来
    * 表示两个对象的比较结果。根据约定,如果两个对象相等,则返回0;如果当前对象
    * 小于参数对象,则返回负数;如果当前对象大于参数对象,则返回正数
    * */
    @Override
    public int compareTo(Person o) {
        int n1 = this.name.compareTo(o.getName());
        int n2 = this.age-o.getAge();
        return n1==0?n2:n1;
    }
}

main方法

package file.homework;

import java.util.Iterator;
import java.util.TreeSet;

@SuppressWarnings({"all"})
public class HomeWork03 {
    public static void main(String[] args) {
        TreeSet<Person> people = new TreeSet<>();
        people.add(new Person("jack",23));
        people.add(new Person("amy",22));
        people.add(new Person("tom",29));
        people.add(new Person("小名",22));
        people.add(new Person("丁凯",23));
        people.add(new Person("雄安红",29));
        people.add(new Person("雄安红",29));
        //System.out.println(people.size()+people.toString());
        Iterator<Person> iterator = people.iterator();
        while (iterator.hasNext()) {
            Person next =  iterator.next();
            System.out.println(next);
        }
    }

}

 代码实现(Comparator比较器)

 值得注意的是:在比较器或者是实现Comparable接口中。根据先比较年龄还是姓名决定输出的排序结果。如果实现了Comparator比较器就无需再次实现Comparable接口了。

package file.homework;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

@SuppressWarnings({"all"})
public class HomeWork03 {
    public static void main(String[] args) {
        TreeSet<Person> people = 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 n2==0?n1:n2;
            }
        });
        people.add(new Person("jack",23));
        people.add(new Person("amy",22));
        people.add(new Person("tom",29));
       // people.add(new Person("tom",29));
        people.add(new Person("小名",22));
        people.add(new Person("丁凯",23));
        people.add(new Person("雄安红",29));
        people.add(new Person("雄安红",29));
//        System.out.println(people.size()+people.toString());
        Iterator<Person> iterator = people.iterator();
        while (iterator.hasNext()) {
            Person next =  iterator.next();
            System.out.println(next);
        }
    }

}

Map集合

hashMap、treeMap 都用keySet、entrySet遍历

特点

1. 用于存储任意键值对(key - value)

2. 键:无序、无下标、不允许重复(唯一) key的值可以为null

3. 值:无序、无下标、允许重复

HashMap

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

使用key可使hashcode和equals作为重复

增、删、遍历、判断与上述一致

原码分析总结:

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

代码实现

keySet的返回值是Set集合,里面存放的所有的key

entrySet的返回值也是Set集合,把里面的每一个Key,Value封装成一个个Entry

entrySet效率高于keySet

package file.homework;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@SuppressWarnings({"all"})
public class HomeWork03 {
    public static void main(String[] args) {
        HashMap<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1,"jack");
        hashMap.put(1,"amy");
        hashMap.put(null,"tom");
        hashMap.put(3,"jery");
        //使用keySet
        Set<Integer> keys = hashMap.keySet();
        for (Integer o :keys) {
            System.out.println(o+":"+hashMap.get(o));
        }
        //使用entrySet
        Set<Map.Entry<Integer, String>> entries = hashMap.entrySet();
        for (Map.Entry<Integer, String> o :entries) {
            System.out.println(o);
        }
    }
}

package file.homework;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@SuppressWarnings({"all"})
public class HomeWork03 {
    public static void main(String[] args) {
        HashMap<Person, String> hashMap = new HashMap<>();
        hashMap.put(new Person(null,0),"山东");
        hashMap.put(new Person("amy",13),"北京");
        hashMap.put(new Person("jery",34),"上海");
        hashMap.put(new Person("tom",23),"天津");
        //使用keySet
        Set<Person> people = hashMap.keySet();
        for (Person o :people) {
            System.out.println(o + hashMap.get(o));
        }
        System.out.println("======");
        //使用entrySet
        Set<Map.Entry<Person, String>> entries = hashMap.entrySet();
        for (Map.Entry<Person, String> personStringEntry :entries) {
            System.out.println(personStringEntry);
        }
    }
}

TreeMap

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

遍历方式:keySet    entrySet

implements Comparable方法

package file.homework;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

@SuppressWarnings({"all"})
public class HomeWork03 {
    public static void main(String[] args) {
        TreeMap<Person, String> treeMap = new TreeMap<>();
        treeMap.put(new Person("amy",13),"北京");
        treeMap.put(new Person("jery",34),"上海");
        treeMap.put(new Person("tom",23),"天津");
        //使用keySet
        Set<Person> people = treeMap.keySet();
        for (Person o :people) {
            System.out.println(o + treeMap.get(o));
        }
        System.out.println("======");
        //使用entrySet
        Set<Map.Entry<Person, String>> entries = treeMap.entrySet();
        for (Map.Entry<Person, String> personStringEntry :entries) {
            System.out.println(personStringEntry);
        }
    }
}

Comparator(比较器)

package file.homework;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
@SuppressWarnings({"all"})
public class HomeWork03 {
    public static void main(String[] args) {
        TreeMap<Person, String> treeMap = new TreeMap<>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                int n1= o1.getName().compareTo(o2.getName());
                int n2 = o1.getAge() - o2.getAge();
                return n1==0?n2:n1;
            }
        });
        treeMap.put(new Person("amy",13),"北京");
        treeMap.put(new Person("jery",34),"上海");
        treeMap.put(new Person("tom",23),"天津");
        //使用keySet
        Set<Person> people = treeMap.keySet();
        for (Person o :people) {
            System.out.println(o + treeMap.get(o));
        }
        System.out.println("======");
        //使用entrySet
        Set<Map.Entry<Person, String>> entries = treeMap.entrySet();
        for (Map.Entry<Person, String> personStringEntry :entries) {
            System.out.println(personStringEntry);
        }
    }
}

Collections工具类

13.42 Collections工具类_哔哩哔哩_bilibili

list转数组,数组的长度若定义的比列表的短,则转成数组后列表长度和数组长度相等。如是定义的长度大于列表的长度,则转成数组后多余的为null 

// list转成数组
Integer[] arr = list.toArray(new Integer[10]);
sout(arr.length);
sout(Array.toString(arr));

// 数组转成集合
// 此时为受限集合,不能 添加和删除!
String[] names = {"张三","李四","王五"};
List<String> list2 = Arrays.asList(names);

// 把基本类型数组转为集合时,需要修改为包装类
Integer[] nums = {100, 200, 300, 400, 500};
List<Integer> list3 = Arrays.asList(nums);

总结

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值