java基础-Java集合框架-Collection子接口-小总结

14 篇文章 0 订阅

Java集合框架-Collection接口相关总结面试题

  1. 集合Collection中存储的如果是自定义类的对象,需要定义类重写哪个方法?为什么?

    需要重写equals()方法,因为Collection集合中的接口方法需要对比元素对象,此处需要调用equals()方法

    List:equals()方法

    Set:(需要重写HashSet,LinkedHashSet)equals(),HashCode()

    TreeSet方法中:在排序中需要注意自然排序和定制排序

  2. ArrayList,LinkedList,Vector三者的相同点与不同点?

    相同点:都实现了List接口,三者都是存储单列数据的容器,且三者存储的数据都是有序,可重复的。ArrayList和Vector底层都是数组实现的

    不同点:ArrayList和LinkedList不是线程安全的,Vector是线程安全的,

    LinkedList底层使用双向链表实现的。

    从效率来看ArrayList遍历效率高(因为可以根据数组的索引下标直接获取元素),但是插入和删除效率低,相对二LinkedList遍历效率相较于ArrayList低,但是LinkedList插入和删除操作的效率高(因为只要找到相应位置修改前后节点的prev 和 next 属性就行)。

    ArrayList,Vector存在扩容情况,ArrayList扩容是原来的1.5倍,Vector扩容是原来的两倍。

  3. List接口的常用方法有哪些(增,删,改,查,插入,长度,遍历)

    增:add(E e)

    删除:remove(E e)

    改:set(E e);

    查:get(int index);

    插入:add(int index,E e)

    长度:size()

    遍历:interator()

Collection总结

  • Collection结构的常用方法:
    • add(E e), addAll(Collection col),remove(E e),removeAll(Collection col),size(),isEmpty(),clear();
    • contains(Object obj),containsAll(Collection coll),retainAll(Collection coll),equals(Object obj)
    • hasCode(),toArray(),iterator()
  • Collection集合与数组间的转换
    • toArray():集合转数组
    • Arrays.asList():数组转集合
  • 使用Collection集合存储对象,要求对象所属的类满足:
    • 向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals()方法。
  • 遍历Collection的两种方式:
    • 迭代器iterator()
    • 增强for循环
  • java.utils包下定义的迭代器接口:Iterator
    • 说明
      • Iterator对象称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素。
      • GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中的各个元素,而又不需要暴露该对象的内部细节。迭代器模式,就是为容器而生。
    • 作用:遍历集合Collection元素
    • 如果获取实例:
      • coll.iterator()
    • 遍历代码的实现
      • Iterator iterator1 = collection.iterator();
        while(;iterator1.hasNext()😉{
        System.out.println(iterator1.next());
        }
    • remove方法:
      • Iterator内部定义了一个remove()方法,可以在遍历的时候,删除集合中的元素。此方法不同于集合直接调用remove()。(此方法有线程安全问题,会触发fast-fail机制)

      • 注意:

        • Iterator可以删除集合中的元素,但是是遍历过程中通过迭代器对象的remove方法,不是集合对象的remove方法
        • 如果还未调用next()或在一次次调用next方法之后已经调用了remove方法,再调用remove都会报错IllegalStateException

Collection子接口:List接口总结

  • 存储数据的特点:
    • 存储有序的、可重复的数据
  • 常用的方法:(记住)
    • 增:add(E e)
    • 删除:remove(E e)
    • 改:set(E e);
    • 查:get(int index);
    • 插入:add(int index,E e)
    • 长度:size()
    • 遍历:
      • interator()
      • 增强for循环
      • 普通for循环
  • 常用的实现类:
    • ArrayList,LinkedList,Vector

Collection子接口:Set接口总结

  • 存储的数据特点:无序的。不可重复的元素
    • 具体的:
      • 以HashSet为例说明:
        • 1.无序性:不等于随机性。存储的数据在底层数组中并非照数组索引顺序添加,而是根据数据的哈希值决定的。
        • 不可重复性:保证添加的元素根据equals()判断,如果返回true则添加失败(即相同元素只能添加一个)
  • 元素的添加过程以(HashSet为例):
    • 我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,
    • 此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置)
    • 判断此在数组中的次索引位置是否已经有元素了
      • 如果此位置上没有其他元素,则元素a添加成功,放入数组中。—>成功情况1
      • 如果此位置上有其他元素b(或者以链表形式存在多个元素),则比较元素a与元素b的hash值:
        • 如果元素a与元素b的hash值不相同,则元素a添加成功。—>成功情况2
        • 如果元素a与元素b的hash值相同,则需要进一步根据判断元素a所在类的equals()方法,判断元素a和元素b是否相同
          • 如果equals()返回true,表示元素a与元素b相同,则元素a添加失败
          • 如果equals()返回false,表示元素a与元素b不相同,则元素a添加成功 -->成功情况3
    • 对于添加成功的情况2和情况3而言:元素a与一家存在指定索引位置上数据以链表的方式存储。但是在jdk7和jdk8两个版本中,插入的方式有所不同
      • 在jdk7中使用头插法:元素a直接放到数组中(也就是链表的第一个元素),指向原来的元素
      • 在jdk8中使用尾插法:原来的元素在数组中,在链表的尾部添加上元素a
      • 总结:七上八下
  • 常用方法
    • Set没有额外定义新的方法,使用的都是Collection中声明过的方法
  • 常用实现类
    • Collection接口:单列集合,用来存储一个一个的对象
      • Set接口:存储无序的、不可重复的数据
        • HashSet:作为Set接口的主要实现类:线程不安全;可以存储null值
        • LinkedHashSet:作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历,在添加数据的同时,每个数据还维护了两个引用,记录此数据的前一个数据和后一个数据
          • 对于频繁遍历操作,LinkedHashSet效率高于HashSet
        • TreeSet:可以按照添加对象的指定属性,进行排序
  • 存储对象所在类的要求:
    • HashSet/LinkedHashSet:需要重写equals和hashCode()方法
      • 向Set中添加的数据,其所在的类一定要重写equals和hashCode方法
      • 重写equals和hashCode方法尽量保持一致性:相等的对象必须具有相等的散列码
    • TreeSet:需要在自然排序操作和定制排序操作选一个进行编写
      • 自然排序中,比较两个对象是否相同的标准为:compareTo()为0,不再是equals()方法
      • 定制排序中,比较两个对象是否相同的标准为: 比较器的compare()方法为0,不再是equals()方法

面试题:

package com.jl.java.base.collection.set;

import org.junit.Test;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;

/**
 * @author jiangl
 * @version 1.0
 * @date 2021/4/23 11:49
 */
public class SetTestQuestion2 {



    @Test
    public void test(){
        //HashSet先计算hashCode 再set
        HashSet set = new HashSet();
        Person person1 = new Person(1001,"AA");
        Person person2 = new Person(1002,"BB");

        set.add(person1);
        set.add(person2);
        System.out.println(set);//[Person{id=1001, name='AA'}, Person{id=1002, name='BB'}]
        person1.setName("CC");
        //此时person1的hashcode变了
        set.remove(person1);
        System.out.println(set);//[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}]
        //new Person(1001,"CC") 新的 hashcode
        set.add(new Person(1001,"CC"));
        System.out.println(set);//[Person{id=1002, name='BB'}, Person{id=1001, name='CC'}, Person{id=1001, name='CC'}]
        set.add(new Person(1001,"AA"));
        System.out.println(set);//[Person{id=1001, name='AA'}, Person{id=1002, name='BB'}, Person{id=1002, name='CC'}]

    }
}

class Person{
    int id;
    String name;

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Person person = (Person) o;
        return id == person.id && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}
package com.jl.java.base.collection.set;

import org.junit.Test;

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

/**
 * 在List内去除重复的数字值,要求尽量简单
 * @author jiangl
 * @version 1.0
 * @date 2021/4/23 11:49
 */
public class SetTestQuestion {

    public static List duplicateList(List list){
        HashSet set = new HashSet();
        set.addAll(list);
        return new ArrayList(set);
    }


    @Test
    public void test(){
        List list = new ArrayList();
        list.add("dasf");
        list.add("dasf");
        list.add("das1f");
        list.add("das1f");
        list.add("da2sf");
        list.add("d22asf");
        list.add("d22asf");
        System.out.println(list);
        System.out.println(duplicateList(list));
    }
}
package com.jl.java.base.collection.set;

import org.junit.Test;

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

/**
 * 1.定义一个Employee类
 * 该来包含:private成员变量name,age,birthday,其中birthday为MyDate类的对象
 * 并为每一个属性定义getter setter方法:
 * 并重写toString方法输出name,age,birthday
 *
 * MyDate类包含:
 * private成员变量year month day;并为每一个属性定义getter setter方法
 *
 * 创建该类的5个对象,并把这些对象放入TreeSet集合中
 * 分别按以下两种方式对集合中的元素进行排序,并且遍历输出
 *
 * 1.Employee实现Comparable接口,并按name排序
 * 2.创建TreeSet时传入Comparator对象,按生日日期的先后排序
 * @author jiangl
 * @version 1.0
 * @date 2021/4/23 11:32
 */
public class TreeSetTestQuestion {
    @Test
    public void test() {
        TreeSet<Employee> treeSet = new TreeSet<>();
        treeSet.add(new Employee("Jack",10,new MyDate(1992,8,19)));
        treeSet.add(new Employee("Tom",20,new MyDate(1993,1,19)));
        treeSet.add(new Employee("Alice",18,new MyDate(2093,3,19)));
        treeSet.add(new Employee("Bill",38,new MyDate(1093,3,19)));
        treeSet.add(new Employee("Selina",8,new MyDate(1992,8,19)));
        treeSet.add(new Employee("Bob",5,new MyDate(2993,8,19)));
        //按name排血
        Iterator<Employee> iterator = treeSet.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

    @Test
    public void test1() {
        TreeSet<Employee> treeSet = new TreeSet<>(new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                int year = Integer.compare(o1.getBirthday().getYear(), o2.getBirthday().getYear());
                if(year != 0){
                    return year;
                }
                int month = Integer.compare(o1.getBirthday().getMonth(), o2.getBirthday().getMonth());
                if(month != 0){
                    return month;
                }
                return Integer.compare(o1.getBirthday().getDay(), o2.getBirthday().getDay());
            }
        });
        treeSet.add(new Employee("Jack",10,new MyDate(1992,8,19)));
        treeSet.add(new Employee("Tom",20,new MyDate(1992,8,20)));
        treeSet.add(new Employee("Alice",18,new MyDate(1992,7,19)));
        treeSet.add(new Employee("Bill",38,new MyDate(1093,3,19)));
        treeSet.add(new Employee("Selina",8,new MyDate(1992,8,19)));
        treeSet.add(new Employee("Bob",5,new MyDate(2010,8,19)));
        //按name排血
        Iterator<Employee> iterator = treeSet.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

class Employee implements Comparable{
    private String name;
    private int age;
    private MyDate birthday;

    public Employee() {
    }

    public Employee(String name, int age, MyDate birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    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 MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Employee employee = (Employee) o;
        return Objects.equals(name, employee.name) && Objects.equals(age, employee.age) && Objects.equals(birthday, employee.birthday);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, birthday);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", birthday=" + birthday +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        if(o instanceof Employee){
            Employee employee = (Employee) o;
            return this.name.compareTo(((Employee) o).getName());
        }
        throw new RuntimeException("格式不匹配");
    }
}

class MyDate{
    private int year;
    private int month;
    private int day;

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public MyDate() {
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        MyDate myDate = (MyDate) o;
        return year == myDate.year && month == myDate.month && day == myDate.day;
    }

    @Override
    public int hashCode() {
        return Objects.hash(year, month, day);
    }

    @Override
    public String toString() {
        return "MyDate{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值