java类集框架之Collection及其子接口List、Set详解

1. 类集概述

java类集框架位于java.util包下,是JDK1.2产生的,它的本质其实就是动态数组。
动态数组:当元素个数达到最大值时,动态增加容量,解决数组定长的问题
在java的类集中,提供了两个最为核心的接口:Collection、Map
Collection接口及其子接口:每次进行数据操作时,都是对单个对象进行处理
Map接口:对键值对进行操作处理

2. 关于Collection接口
2.1 Collection的定义和常用方法

Collection接口是单个对象保存的最顶层的父接口它的构造方法如下:
public interface Collection extends Iterable
看一下他有哪些常用方法:
在这里插入图片描述
其中我们最常使用有两个方法:
add() :向集合中添加元素
iterator():取得集合的迭代器
由于Collection接口制定了数据的存储标准,而没有区分具体的存储类型,因此我们在使用时一般不直接使用Collection接口,而是使用它的两个子接口
List:允许元素重复
Set:不允许元素重复

2.2 List接口

List接口除了有Collection接口提供的那些方法之外。还有两个自己独有的方法
get(int index):根据指定索引获取元素
set(int index, E element): 修改指定索引处的元素,返回修改前的元素
在List接口下有三个重要子类:ArrayList、LinkedList、Vector
ArrayList:
public class ArrayList extends AbstractList implements List

LinkedList:
public class LinkedList extends AbstractSequentialList implements List
public abstract class AbstractSequentialList extends AbstractList

Vector:
public class Vector extends AbstractList implements List

AbstractList:
public abstract class AbstractList extends AbstractCollection implements List
我们可以看到ArstractList已经实现了List,但是ArrayList它们还要自己实现List接口。这是因为对于数组来说有一些基本的增删改查操作,我们把这些方法就放在ArstractList中,但是ArrayList等又有一些自己特有的方法,这时候就需要实现List接口去扩展自己的方法。
在这里插入图片描述
下面我们来具体看看List下的子类
2.2.1 ArrayList
ArrayList底层是一个对象数组,声明一个ArrayList对象时长度为0,只有第一次使用时,长度才会被置为10。这是一种懒加载策略。对集合的增删改查都是异步处理,性能较高,线程不安全。
2.2.2 Vector
底层实现是一个对象数组,声明一个Vector,初始化长度是10
对集合的修改都采用同步处理(直接在方法上使用内建锁),性能较低,线程安全
当数组长度不够用时,扩容策略变为原来数组的2倍
2.2.3 LinkedList
基于链表实现的动态数组

我们都直到List接口允许存储重复元素,如果我们想用List来存储自定义对象时,这时我们就需要自己覆写equals()方法了。因为当我们在使用List中的contains()和remove()方法时,它们都需要用到equals方法,对于基本类型和引用类型而言,Object已经帮他们覆写了equals()。但是自定义类并没有覆写,因此我们需要自己覆写。
下面通过一个例子,来看看如何使用List来存储自定义类对象。

class Person{
    private String name;
    private int 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 boolean equals(Object obj) {
        if(obj == this){
            return true;
        }if(obj == null){
            return false;
        }if(!(obj instanceof Person)){
            return false;
        }
        Person per = (Person)obj;
        return this.age == per.age && this.name.equals(per.name);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class Test {
   public static void main(String[] args) {
        Person per1 = new Person("张三",18); 1
        Person per2 = new Person("李四",20);  2
        Person per3 = new Person("王五",22);   3
        List<Person> list = new ArrayList<>(); 
        list.add(per1);
        list.add(per2);
        list.add(per3);
      System.out.println(list.contains(new Person("张三",18)));
      list.remove(new Person("王五",22));
       System.out.println(list);
       // System.out.println(list.contains(per1));
   }
}
3. Set接口

Set接口没有扩充方法,Set接口中的方法与Collection完全一致,常用两个子类HashSet、TreeSet
3.1 HashSet ( 无序存储) – HashMap – 底层使用哈希表+红黑树
不允许元素重复,并且无序存储(根据hash码来存放元素)
允许存放null,有且仅有一个null

重复元素的判断
TreeSet与TreeMap依靠Comparator或Comparable接口来区分重复元素
自定义类要想保存在TreeSet或TreeMap中:
Ⅰ. 要么该类直接实现Comparable接口,覆写compare to方法
Ⅱ. 要么实现一个比较器传入TreeSet或TreeMap来进行外部比较

而HashSet与HashMap并不依赖比较接口。此时要想区分自定义元素是否重复,需要同时覆写Object中的hashCode以及equals( )。

3.2 TreeSet (有序存储)–TreeMap – 底层基于红黑树
不允许元素重复(用Compareable或者Compartor判断是否重复),并且按照升序排序,不允许存放Null(会空指针异常)
要想使用自定义类作为TreeSet存储(想利用Treeset排序),该类必须覆写Compareable接口,或者向TreeSet传入比较器(即Compartor接口)。看看比较器是什么:

java.lang.Comparable接口(内部比较器):
若一个类实现了Comparable接口,就意味着该类支持排序
public int compareTo(Object o),类中所有属性都要参与运算。
a. >0 表示当前对象大于比较对象
b. =0 表示当前对象等于比较对象
c. <0 表示当前对象小于比较对象

Comparator(外部排序接口)
若要控制某个自定义类的顺序,而该类本身不支持排序(该类本身没有实现Comparable),我们可以建立一个该类的“比较器”来进行排序
“比较器”:实现了Comparator接口的类作为比较器,通过该类比较器来进行类的排序
public int compare(T o1,T o2):
返回正数表示 o1 > o2
返回0表示 o1 = o2
返回小数表示 o1 < o2
实现了Comparator接口进行第三方排序(是一种策略模式)此方法更加灵活,可以轻松改变策略进行第三方的排序算法。
看一个传入外部比较器的例子:

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
class Person{
    private String name;
    private int 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;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
class AscComparator implements Comparator<Person>{
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge()-o2.getAge();
    }
}
public class Test {
    public static void main(String[] args) {
        Set<Person> set = new TreeSet<>(new AscComparator());
        set.add(new Person("张三",18));
        set.add(new Person("李四",25));
        System.out.println(set);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章