类集---List接口与Set接口

本文详细介绍了Java集合框架中的List接口与Set接口,包括ArrayList、Vector和LinkedList的区别,以及HashSet和TreeSet的特性。重点讨论了List接口的存储结构和操作,强调了在自定义类中覆写equals()方法的重要性。此外,文章还探讨了Set接口的无序存储特性,讲解了Comparable和Comparator接口在排序中的作用,以及HashSet和TreeSet的去重原理。最后,文章介绍了迭代器、ListIterator、Enumeration和foreach循环在集合输出中的应用,特别是fail-fast机制的概念和作用。
摘要由CSDN通过智能技术生成

类集—List接口与Set接口

Collection接口

List接口

List具体实现三个常用子类(ArrayList、Vector、LinkedList)

集合输出

1.Collection接口

java类集所有类均在java.util包下。

java类集本质上是动态数组(当元素个数达到最大值时,动态增加容量),在JDK1.2引出。作用为解决数组定长问题。

java集合类框架是加上就是java针对于数据结构的一种实现。

在细谈List接口和Set接口之前我们先来看一下源代码:

//List接口
public interface List<E> extends Collection<E> {
   }
//Set接口
public interface Set<E> extends Collection<E> {
   }

通过源码可以发现,List接口与Set接口均继承了Collection接口。那么我们先来研究Collection接口:

public interface Collection<E> extends Iterable<E> {
   }
//迭代器接口
public interface Iterable<T> {
   
    Iterator<T> iterator();
}

我们通过源码可以看到,Collection接口继承了Iterable接口,但需要注意的是Iterable接口是迭代器接口,继承该类的类标志着才可以进行遍历(如for、foreach)。

Collection接口为单个集合保存的最大接口,该接口继承了迭代器接口,表明Collection子类支持迭代。

从JDK1.5开始Collection接口追加了泛型应用,这样的直接好处是可以避免ClassCastException,里面保存的所有数据类型应该是相同的。在JDK1.5之前Iterable接口中的iterable()方法是直接定义在Collection接口中的,之后抽象为单独接口。

接下来看一下Collection接口中比较重要的几个方法:

1.boolean add(E e);//向集合中添加数据
2.boolean addAll(Collection<? extends E> c);//一次性可向集合中添加一组数据
3.void clear();//将集合中的数据清空
4.boolean contains(Object o);//查看该集合中是否存在某元素,需要equals()方法
5.boolean remove(Object o);//将集合中某一元素移除,需要equals()方法
6.boolean equals(Object o);//判断地址是否相等
7.int size();//返回集合大小
8.Object[] toArray();//将集合中元素转变为数组
9.Iterator<E> iterator();//取得集合的迭代器,用于元素输出

以上几个方法中尤其用到最多的是add()、iterator()方法。Collection接口为我们定义了存储数据的标准,但是无法区分存储类型。所以在实际开发中并不是直接使用Collection接口,而是使用它的子接口List(允许数据重复)、Set(不允许数据重复)。

Collection接口继承结构:

在这里插入图片描述

2.List接口

List接口是有序集合,允许元素重复,在进行单个集合处理时优先考虑List接口。

首先先来学习一下List接口扩展的(List接口独有)的两个方法:
1.E set(int index, E element);//修改集合中下标为index处元素值且返回修改前数值
2.E get(int index);//获取集合中下标为index的数值

List子接口与Collection接口相比,最大的特点是扩展了get()方法,可以根据索引下标获取集合中元素。但List还是接口,故具体操作需要依靠其子类。List常用的三个子类为ArrayList、Vector、LinkedList。

List接口继承关系架构:

在这里插入图片描述

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
   }

如上图所示,AbstractList抽象类存在的意义为将ArrayList、Vector、LinkedList三个子类共有的方法提取至AbstractList抽象类中实现,特有方法再由子类具体实现。

2.1ArrayList类(常用,优先考虑)

该类从名称上可以知道其底层具体实现依靠数组。

我们先来学习一下ArrayList类的构造方法:

1.无参构造(调用无参构造后并不是直接开辟空间,而是先将其置为空,在第一次添加元素时将数组开辟长度为10(默认初始长度))
public ArrayList() {
   
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
   };
2.有参构造(可在调用有参构造时自行设定数组长度,但一般建议若要自行设定就大于10,否则建议使用无参构造。因若自行设定小于10的数组长度,就可能增加扩容次数,降低效率)
public ArrayList(int initialCapacity) {
   //调用有参构造时自行设定数组初始长度
        if (initialCapacity > 0) {
   //若大于0,开辟数组长度
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
   //若等于0,将数组置为空
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
   //小于0时非法抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
private static final Object[] EMPTY_ELEMENTDATA = {
   };
3.有参构造接收Collection对象
public ArrayList(Collection<? extends E> c) {
   
        elementData = c.toArray();//将集合转变为数组
        if ((size = elementData.length) != 0) {
   
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
   
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

ArrayList简单实现自定义类对象保存:

import java.util.ArrayList;
import java.util.List;

class Person{
   
    private String name;
    private Integer age;

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

    public String getName() {
   
        return name;
    }

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

    public Integer getAge() {
   
        return age;
    }

    public void setAge(Integer age) {
   
        this.age = age;
    }

    @Override
    public String toString() {
   
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Test{
   
    public static void main(String[] args) {
   
        List<Person> list=new ArrayList<>();
        list.add(new Person("lala",12));
        list.add(new Person("kk",19));
        list.add(new Person("lala",11));
        list.add(new Person(null,9));
        list.add(new Person(null,null));
        System.out.println(list);
        System.out.println("数组长度为:"+list.size());
        System.out.println("修改元素值:"+list.set(3,new Person("张三",99)));
        System.out.println("取得元素值:"+list.get(3));
    }
}
//[Person{name='lala', age=12}, Person{name='kk', age=19}, Person{name='lala', age=11}, Person{name='null', age=9}, Person{name='null', age=null}]
//数组长度为:5
//修改元素值:Person{name='null', age=9}
//取得元素值:Person{name='张三', age=99}
//通过以上输出结果表明ArrayList为有序集合,先进先出,且可接收属性为null
那么若想移除元素或者判断某元素是否存在时以上代码还可以直接使用吗?
//在以上代码中直接调用remove()方法及contains()方法
import java.util.ArrayList;
import java.util.List;

class Person{
   
    private String name;
    private Integer age;

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

    public String getName() {
   
        return name;
    }

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

    public Integer getAge() {
   
        return age;
    }

    public void setAge(Integer age) {
   
        this.age = age;
    }

    @Override
    public String toString() {
   
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Test{
   
    public static void main(String[] args) {
   
        List<Person> list=new ArrayList<>();
        list.add(new Person("lala",12));
        list.add(new Person("kk",19));
        list.add(new Person("lala",11));
        list.add(new Person(null,9));
        list.add(new Person(null,null));
        System.out.println("移除元素:"+list.remove(new Person("lala",12)));
        System.out.println("判断该元素是否存在:"+list.contains(new Person("kk",19)));
    }
}
//移除元素:false
//判断该元素是否存在:false
//由以上输出结果我们可以发现调用contains()及remove()方法均失败,这是为什么呢?我们可以发现在list添加元素时直接使用匿名数组,那么在移除或者判断时也这样显然会失败,原因是我们都知道一旦有new就说明在堆上开辟了新空间,地址不同当然会操作失败,所以在此种情况下要使用移除判断元素是否存在就必须在自定义类中覆写equals()方法

import java.util.ArrayList;
import java.util.List;

class Person{
   
    private String name;
    private Integer age;

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

    public String getName() {
   
        return name;
    }

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

    public Integer getAge() {
   
        return age;
    }

    public void setAge(Integer age) {
   
        this.age = age;
    }

    @Override
    public String toString() {
   
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public boolean equals(Object obj) {
   
        if(obj==this){
   
            return true;
        }else if(obj==null||!(obj instanceof Person)){
   
            return false;
        }
        Person per=(Person) obj;
        return per.name.equals(this.name)&&per.age.equals(this.age);
    }
}
public class Test{
   
    public static void main(String[] args) {
   
        List<Person> list=new ArrayList<>();
        list.add(new Person("lala"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值