JAVA后端面试《容器》

容器

常见的容器图录:
集合图谱

1.Collection和Collections的区别?

  • Collection: java.util.Collection是集合类的一个顶级接口,为各种具体的集合提供了最大化的统一操作方式。
  • Collections: 是集合类的一个工具类,它提供了一系列静态法,用于对集合中元素进行排序,搜索等各种操作。

2.List、Set、Map之间的区别是什么?

在这里插入图片描述

3.HashMap和HashTable的区别?

  • 方法上: HashMap去掉了HashTablecontains方法,但是加上了containsValue()containsKey() 方法。
  • 性能上: HashTable 是线程安全的,而HashMap是非线程安全的,所以在单线程的环境下HashMap性能上要好一些。
  • 空键值: HashMap允许空键值(null键null值),而HashTable不允许。
  • 遍历方法: HashTable使用Enumeration遍历,HashMap使用Iterator进行遍历。

4.如何决定使用 HashMap 还是 TreeMap?

  • 对于在Map中插入删除定位元素这类操作,HashMap是更佳的选择。
  • 如果你需要对一个有序的Key集合进行遍历,TreeMap是更好的选择。

5.谈谈HashMap的实现原理?

  • 概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null键和null值。此类不保证映射的顺序,特别是它不保证该顺序永恒不变。
  • 数据结构: 在JAVA编程语言中,最基本的结构就是两种:数组和模拟指针(引用)。HashMap也不例外。HashMap实际上就是一个“链表散列”的数据结构,即链表和数组的结合体。
  • 往HashMap中put元素时,首先会根据key的hashcode重新计算hash值,根据hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,原来的放在链尾。如果数组中该位置没有元素,就直接将该元素存放到数组该位置上。
  • 需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)。

6.说下HashSet的实现原理?

  • HashSet底层由HashMap实现。
  • HashSet的值存放在HashMap的key上,而value中的值都是统一的一个private static final Object PRESENT = new Object();。
  • HashSet跟HashMap一样,都是一个存放链表的数组。

7.ArrayList和LinkedList的区别是什么?

  • 数据结构: ArrayList的底层数据结构是数组(支持随机访问),而LinkedList的底层数据结构是双向循环链表(不支持随机访问)。
  • 时间复杂度: ArrayList的时间复杂度是O(1),LinkedList的时间复杂度是O(n)。

8.如何实现数组和List之间的转换?

  • List转换为数组:ArrayList的toArray方法。
  • 数组转换为List:Arrays的asList方法。

9.ArrayList和Vector的区别是什么?

  • 线程安全: Vector是同步的,所以是线程安全的。ArrayList是不同步的,所以是非线程安全的。
  • 速度: 单线程环境下,ArrayList的速度要更快一些。
  • 扩容: 当容量超过初始值时,ArrayList扩容原有初始容量的50%,而Vector扩容原有初始容量的100%,他们的初始容量都是10。

10.Array和ArrayList的区别?

  • 容纳类型: 数组可以容纳基本数据类型和对象,而ArrayList只能容纳对象。
  • 大小 : 数组是指定大小的。而ArrayList大小默认是10,且支持自动扩容。
  • 功能: ArrayList的方法要多于数组。

11.在 Queue 中 poll()和 remove()有什么区别?

  • poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空,但是 remove() 失败的时候会抛出异常。

12.哪些集合类是线程安全的?

  • vector:是同步的。
  • statck:堆栈类,先进后出。
  • hashtable:是同步的。
  • enumeration:枚举,相当于迭代器。

13.迭代器Iterator是什么?

  • 迭代器是一种设计模式,是一个对象,用于遍历和选择集合中的元素。迭代器通常被称为“轻量级对象”,因为创建它的代价很小。

14.Iterator怎么使用?有什么特点?

  • 特点: Iterator功能比较简单,只能单向移动,是Java迭代器最简单的实现
  • 1.调用iterator()方法返回一个Iterator
  • 2.调用next() 方法获取集合中下一个元素。(第一次调用时,返回的是集合的第一个元素)。
  • 3.调用hasNext() 方法检查集合中是否还有元素。
  • 4.调用remove() 将迭代器新返回的元素删除。

15.Iterator和ListIterator的区别?

  • 遍历对象: Iterator可以用来遍历Set和List集合,而ListIterator只能遍历List。
  • 遍历方向: Iterator对集合只能是前向遍历,而ListIterator既可以前向也可以后向。
  • 功能: ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。

16.ArrayList循环遍历并删除元素,怎么保证去重?

  • 1.倒序删除的方式避免删除元素后带来的集合元素移动的问题。
  • 2.使用迭代器且使用迭代器的remove方法。
  • 3.正序删除且每删掉一个元素,遍历的下标减1,往回移动一个位置
class T1{
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c","d","b","b");
        System.out.println("去重前list = " + list);
        remove(list);//和remove3(list)的结果一样
            /*输出:  去重前list = [a, b, c, d, b, b]
                     去重后list = [a, b, c, d]   */
        //remove2(list);
            /*输出:去重前list = [a, b, c, d, b, b]
                    去重后list = [a, c, d, b]   */

        System.out.println("去重后list = " + list);

    }
    //1.迭代器删除
    public static void remove(ArrayList<String> list)
    {
        Iterator<String> it = list.iterator();
        int count = 0;//统计遇见"b"的次数
        while (it.hasNext())
        {
            String s = it.next();
            if (s.equals("b"))
            {
                if (count!=0){
                    it.remove();
                }
                count++;//进来一次,计数一次
            }
        }
    }
    //2.倒序删除
    public static void remove2(ArrayList<String> list)
    {
        int count=0;//统计遇见"b"的次数
        for(int i=list.size()-1;i>=0;i--)
        {
            String s = list.get(i);
            if(s.equals("b"))
            {
                if(count!=0){
                    list.remove(i);
                }
                count++;//进来一次,计数一次
            }
        }
    }
    //3.每删掉一个,遍历的下标减1.往回移动一个位置
    public static void remove3(ArrayList<String> list){
        int count = 0;
        for (int i = 0; i <=list.size()-1 ; i++) {
            String s = list.get(i);
            if ("b".equals(s)){
                if (count!=0) {
                    list.remove(i);
                    i--;
                }
                count++;
            }
        }

    }
}

17.HashSet去重原理?如何将自定义类对象存入HashSet并进行去重呢?

  • 原理:依赖hashCode()方法和equals()方法。
    • HashSet的add()方法实际上调用的是HashMap的put方法,把要添加进HashSet的元素当做key存入,而value则一个固定值:一个Object类对象。
    • 先用hashCode方法获得传入元素的哈希值,在集合中查找是否包含相同哈希值的元素,如果哈希值相同,则继续执行equals方法,返回true不添加,返回false就添加。哈希值不同直接添加。
  • 自定义类对象添加HashSet进行去重:
    • 1.类中重写hashCode方法和equals方法
    • 2.equals方法中比较所有属性值
    • 3.hashCode()方法要保证属性相同的对象返回值相同:对象的成员变量值相同即为同一个元素。
class Student {
    private String name;
    private int age;
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    public static void main(String[] args) {
        HashSet set = new HashSet();
       /*   Student s1 =new Student("zs",12);
            Student s2 =new Student("ww",12);
            Class<? extends Student> aClass  = s1.getClass();
            Class<? extends Student> aClass1 = s2.getClass();
            System.out.println(aClass==aClass1);//true  */
        System.out.println("---------------");
        set.add(new Student("zs",12));
        set.add(new Student("ls",13));
        set.add(new Student("ww",14));
        set.add(new Student("zs",12));
        set.add(null);

        Iterator it = set.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
         /*输出结果:---------------
					 null
					 Student{name='zs', age=12}
					 Student{name='ls', age=13}
					 Student{name='ww', age=14}  */
        }
    }

    @Override
    public boolean equals(Object o) {
        //如果内存地址值相同直接返回true
        if (this == o) return true;
        //如果传入对象为null或者类不相同直接返回false
        if (o == null || getClass() != o.getClass()) return false;
        //进行到这一步,则证明是同一个类,直接向下转型为Student
        Student student = (Student) o;
        //并且比较两个对象的属性值是否相等,相等的话就返回true,实现去重
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
发布了18 篇原创文章 · 获赞 6 · 访问量 1868

猜你喜欢

转载自blog.csdn.net/weixin_43766298/article/details/103468318