CodeGym /Java 博客 /随机的 /探索 Java 开发人员职位面试中的问题和答案。第10部分
John Squirrels
第 41 级
San Francisco

探索 Java 开发人员职位面试中的问题和答案。第10部分

已在 随机的 群组中发布
你好!成为某件事的大师需要多少小时?我经常听到这样的话:“要成为某件事的大师,你需要花一万个小时。” 这是一个令人恐惧的数字,不是吗? 探索 Java 开发人员职位面试中的问题和答案。 第 10 - 1 部分不过,我想知道这是否属实。我不断地试图弄清楚我已经投入了多少时间来掌握编程艺术。当我跨过那条10000小时的特殊线并成为大师时,我会感受到不同吗?还是说我很久以前就已经跨过了那条线而没有意识到?不管怎样,你不必投入如此大量的时间来成为一名程序员。重要的是明智地利用你的时间。您的首要目标是获得面试机会。在面试中,未来的软件开发人员首先会被问及理论,因此这需要成为一种优势。事实上,当你准备面试时,你的工作就是发现基础 Java 理论知识中的所有空白,然后填补它们。今天我来这里就是为了帮助您做到这一点,因为今天我们将继续回顾最流行的面试问题。好吧,我们继续吧!

89. ArrayList 与 LinkedList 有何不同?

这是最常见的问题之一,还有关于 HashMap 内部结构的问题。没有它,面试就不完整,所以你的答案应该很容易脱口而出。除了明显的差异(它们有不同的名称)之外,它们的内部结构也有所不同。之前,我们讨论了ArrayListLinkedList的内部结构,因此我不会深入讨论它们的实现细节。我只是提醒您,ArrayList是使用内部数组实现的,其大小根据以下公式动态增加:

<size of the current array> * 3 / 2 + 1
此外, LinkedList 的实现使用内部双向链表,即每个元素都有对前一个和下一个元素的引用,但列表开头和结尾的元素除外。面试官喜欢问这样的问题:“ ArrayListLinkedList哪个更好?” 希望能抓住你。毕竟,如果你说其中一个更好,那么你就给出了错误的答案。 探索 Java 开发人员职位面试中的问题和答案。 第 10 - 2 部分相反,您应该澄清您所讨论的具体情况:通过索引访问元素或插入列表中间。然后,根据他们的回答,您可以解释哪一个更好。我之前描述了ArrayListLinkedList在每种情况下如何工作。让我们通过将它们放在一行中进行比较来总结这一点: 添加元素(add)
  1. 如果未指定索引,则新项目将自动添加到两种列表的末尾。在LinkedList中,新元素将成为新尾部(只会重写一对引用,因此算法复杂度为O(1))。

    add 方法将一个元素添加到数组中的最后一个空单元格 ( O(1) )。

  2. 通过索引添加项目通常意味着将其插入列表中间的某个位置。在LinkedList中,该方法将首先通过迭代尾部和头部的元素来搜索所需的位置 ( O(n/2) ),然后通过覆盖两侧元素的引用来插入值插入新元素 ( O(1) )。此操作的总体算法复杂度将为O(n/2)

    在相同的情况下(按索引添加),ArrayList找到所需的位置(O(1)),然后将位于右侧的所有元素(包括已存储在指定索引处的元素)向右移动一位(这可能需要创建一个新的内部数组并将元素复制到其中)(O(n/2))。总体复杂度为O(n/2)

  3. 将元素添加到LinkedList的开头类似于将元素添加到末尾:新元素成为新头 ( O(1) )。但对于 ArrayList,该操作需要将所有元素移动到右侧 ( O(n) )。

最重要的是,对于 LinkedList,算法复杂度范围从O(1)O(n/2)。另一个观察结果是,插入越接近列表的末尾或开头,插入速度就越快。对于ArrayList,算法复杂度从O(1)O(n)不等,插入越接近列表末尾,速度越快。 设置元素 (set) 此操作将元素写入列表中的指定位置,覆盖任何现有元素。在LinkedList中,此操作类似于添加,因为这里最大的挑战是找到元素的位置。通过更新一对引用来覆盖现有元素,因此我们的算法复杂度从O(1)O(n/2)不等,具体取决于所需位置与列表末尾或开头的距离。但对于ArrayList,此操作通过索引找到所需的单元格并将新元素写入其中。与集合操作一样,按索引搜索的算法复杂度为O(1)通过索引获取元素 (get)从LinkedList 获取元素遵循与其他操作中使用的相同搜索原则。复杂度取决于距终点或起点的距离,即从O(1)O(n/2)不等。如前所述,对于ArrayList,通过索引在内部数组中查找元素的复杂度为O(1)通过索引删除元素(remove) 对于LinkedList,同样的原理再次适用。首先,定位该元素,然后重写引用,已删除元素的邻居现在互相引用,消除了对已删除元素的引用,该元素随后将被垃圾收集器清理。换句话说,算法复杂度仍然相同——从O(1)O(n/2)不等。对于ArrayList来说,这个操作更像是添加一个新元素(add)。首先,该方法找到所需的元素 ( O(1) ),将其删除,然后将位于右侧的所有元素向左移动一步,以弥补删除所产生的间隙。删除元素与添加操作具有相同的算法复杂度 — 从O(1)O(n)。被删除的元素越接近列表的末尾,该操作的算法复杂度越低。现在我们已经介绍了所有主要操作。需要提醒大家的是,在比较这两种列表的时候,一定要弄清楚它们的具体使用场景,这样才能明确地回答面试官的问题。

90. ArrayList 与 HashSet 有何不同?

如果我们可以逐个操作地比较ArrayListLinkedList以确定哪一个更好,那么我们会发现在ArrayListHashSet之间进行这样的比较就没那么容易了,因为它们是完全不同的集合。你可以将一种甜点与另一种甜点进行比较,但比较甜点和咸味菜肴是一项挑战——它们截然不同。尽管如此,我还是会尝试指出它们之间的一些差异:
  • ArrayList实现了List接口,而HashSet实现了Set接口。

  • ArrayList允许您通过索引访问元素:get操作的算法复杂度为O(1),但HashSet只允许您通过迭代访问所需的元素,这会产生从O(1)O(n) 的算法复杂度。

  • ArrayList允许重复元素。在HashSet中,所有元素都是唯一的:任何添加 HashSet 中已存在的元素的尝试将失败(通过哈希码检查重复项,因此该集合的名称也由此而来)。

  • ArrayList是使用内部数组实现的,而HashSet是使用内部HashMap实现的。

  • ArrayList维护元素的插入顺序,但HashSet是无序集合,不维护元素的顺序。

  • ArrayList允许任意数量的空值,但你只能向HashSet添加一个空值毕竟元素必须是唯一的)。

91. 为什么Java有这么多不同的动态数组实现?

这更多的是一个哲学问题。我们还可以问为什么他们会想出这么多新奇的技术?为了方便。对于大量动态数组实现也是如此。它们都不能被称为最好或理想的实现。每种情况都有其优点。我们的工作是了解它们的差异以及它们的优点/缺点,以便能够使用最适合任何特定情况的集合。

92. 为什么Java有这么多不同的键值存储实现?

这里的情况与动态数组实现相同。绝对没有一个是普遍优于其他的:每个都有优点和缺点。当然,我们必须充分利用他们的优势。 示例: concurrent 包有很多多线程类,有自己的Concurrent集合。在多线程环境中处理数据时,ConcurrentHashMap 类在安全性方面比标准 HashMap 具有优势,但这是以性能较慢为代价。在任何情况下都不是最佳选择的实现将逐渐停止使用。 例如: Hashtable原本是打算成为线程安全的HashMap,但现在已经被遗忘并不再使用了,因为ConcurrentHashMap在多线程环境中工作时 甚至比Hashtable更好。

93. 如何对元素集合进行排序?

首先要说的是,表示集合元素的类必须实现Comparable接口,该接口由compareTo方法组成。或者您需要一个实现Comparator接口的类,包括其比较方法。这两种方法都指示如何比较给定类型的对象。这在排序时至关重要,因为排序算法需要了解使用什么原理来比较元素。这主要是通过直接在要排序的类中实现Comparable来完成的。使用比较器不太常见。假设您正在使用某个库中的类,并且它没有实现Comparable,但您需要对其对象的集合进行排序。由于您无法更改此类的代码(除非扩展它),因此您可以编写Comparator的实现来指示如何比较该类的对象。还有一个例子。如果您需要以不同的方式对同一类型的对象进行排序,那么您可以编写多个Comparator实现以在不同的情况下使用。通常,许多开箱即用的类(例如String)已经实现了Comparable接口。这意味着您无需担心如何比较这些类。您可以继续使用它们。 第一个也是最明显的方法是使用TreeSetTreeMap类。这些类根据类元素实现的比较器按排序顺序存储元素。不要忘记TreeMap对键进行排序,而不是对值进行排序。如果您使用Comparator而不是Comparable,那么您需要在创建集合时 将Comparator对象传递给集合的构造函数:

TreeSet treeSet = new TreeSet(customComparator);
但是如果您有不同类型的集合怎么办?你如何排序?在这种情况下,Collections实用程序类的第二种方法 — sort()方法 — 是合适的。该方法是静态的,因此您所需要做的就是在前面添加类的名称,然后传入要排序的列表。例如:

Collections.sort(someList);
如果您使用Comparator而不是Comparable 的实现,那么您需要将其作为第二个参数传递:

Collections.sort(someList, customComparator);
此操作将更改传递列表中元素的内部顺序:将使用比较器对列表进行排序。请注意,传递的列表必须是可变的,否则该方法将失败并抛出UnsupportedOperationException。第三种选择是使用Stream类的排序方法,该方法集合的元素进行排序。如果我们使用Comparable

someList = someList.stream().sorted().collect(Collectors.toList());
如果我们使用比较器

someList = someList.stream().sorted(customComparator).collect(Collectors.toList());
第四种方式是手动实现排序算法,例如冒泡排序 归并排序

对象类。equals() 和 hashCode()

94. 简要描述Java中的Object类。

在回顾的第二部分中,我们已经讨论了 Object类的方法。这里我要提醒大家,Object类是Java中每个类的祖先。它有 11 个方法,依次被所有类继承。 探索 Java 开发人员职位面试中的问题和答案。 第 10 - 3 部分

95. Java中equals()和hashCode()的用途是什么?

hashCode()是Object类的一个方法,被所有类继承。它的工作是生成一个代表特定对象的数字。可以在HashMap中找到此方法的实际示例,其中对键对象调用该方法以获取本地哈希码,这将确定键值对将存储在哪个存储桶(内部数组的单元格)中。此外,该方法一般用在equals()方法中,作为其识别对象的主要方式之一。 equals()是Object类的一个方法,其作用是比较对象并确定它们是否相等。这个方法用在我们需要比较对象的任何地方,因为标准的==比较运算符不适合对象,因为它只比较对象引用。

96. 请告诉我们 Java 中 equals() 和 hashCode() 之间的约定?

首先,我要说的是,为了使equals()hashCode()方法正常工作,必须正确重写它们。他们的新实现必须遵循以下规则:
  • equals返回true 的相同对象必须具有相同的哈希码。
  • 具有相同哈希码的对象不一定相等。
现在似乎是一个暂停的好地方,直到评论的下一部分!
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION