JavaRush /Java 博客 /Random-ZH /Java 开发人员访谈问答分析。第11部分

Java 开发人员访谈问答分析。第11部分

已在 Random-ZH 群组中发布
你好! 即使是速度最快的船,如果没有航向,也只会随波逐流。 如果您现在正在阅读我的文章,那么您肯定有一个目标。最重要的是不要误入歧途,而是要坚持到底——成为一名 Java 开发人员。今天我想继续为 Java 开发人员分析 250 多个问题,这将帮助您弥补理论中的一些空白。 Java 开发人员访谈问答分析。 第 11 - 1 部分

97. 重新定义 Equals 时是否施加了协议重新定义条件?

重写的equals()方法必须符合以下条件(规则):
  • 自反性- 对于任何值x,像x.equals(x)这样的表达式应该始终返回true(当x != null时)。

  • 对称性- 对于x和y的任何值只有当y.equals(x)返回true时, x.equals(y )形式的表达式才必须返回true

  • 传递性- 对于xyz的任何值,如果x.equals(y)返回true并且y.equals(z)也返回true,则x.equals(z)必须返回true

  • 一致性- 对于xy 的任何值,重复调用x.equals(y)将始终返回先前调用此方法的值,前提是用于比较两个对象的字段在调用之间没有更改。

  • 比较 null - 对于任何值x,调用x.equals(null)将返回false

98. 如果不重写 Equals 和 HashCode 会发生什么?

在这种情况下,hashCode()将返回一个根据存储给定对象的内存位置生成的数字。也就是说,两个具有完全相同字段的对象在调用非重写的hashCode()时会收到不同的值(毕竟它们存储在不同的内存位置)。未重写的equals()比较引用以查看它们是否指向同一对象。也就是说,通过==进行比较,如果对象具有相同的字段,则始终返回false。仅当比较对同一对象的引用时才为True 。有时不重写这些方法是有逻辑的。例如,您希望某个类的所有对象都是唯一的,而重写这些方法只会破坏唯一性的逻辑。最主要的是了解重写和非重写方法的细微差别,并根据情况使用这两种方法。

99. 为什么只有当 x.equals(y) 返回 true 时对称性才为 true?

有点奇怪的问题。如果对象 A 等于对象 B,则对象 B 等于对象 A。如果 B 不等于对象 A,那么相反的情况怎么可能呢?这是简单的逻辑。 Java 开发人员访谈问答分析。 第 11 - 2 部分

100.HashCode中什么是碰撞?怎么处理呢?

hashCode冲突是指两个不同的对象具有相同的hashCode值的情况。这怎么可能?事实上,哈希码映射到Integer类型,而 Integer 类型的范围从 -2147483648 到 2147483647,即大约 40 亿个不同的整数。这个范围虽然很大,但并不是无限的。因此,两个完全不同的对象可能具有相同的哈希码。这是极不可能的,但也是有可能的。实施不当的哈希函数还可能会增加相同哈希码的频率,例如,这会返回小范围内的数字,从而增加冲突的机会。为了防止冲突,您需要很好地实现 hashCode方法,以使值的分布最大,并且重复值的机会最小。

101.如果参与HashCode合约的元素改变其值会发生什么?

如果参与计算哈希码的元素发生了变化,那么对象本身的哈希码也会发生变化(如果哈希函数是好的)。因此,在HashMap中建议使用不可变(不可更改)对象作为键,因为它们的内部状态(字段)在创建后无法更改。因此,它们的哈希码在创建后也不会转换。如果您使用可变对象作为键,那么当您更改该对象的字段时,其哈希码将会更改,因此您可能会在HashMap中丢失该对。毕竟,它会存储在原始哈希码的桶中,更改后会在另一个桶中查找。 Java 开发人员访谈问答分析。 第 11 - 3 部分

102.为Student类编写Equals和HashCode方法,该类由String name和intage字段组成

public class Student {
int age;
String name;

 @Override
 public boolean equals(final Object o) {
   if (this == o) {
     return true;
   }
   if (o == null || this.getClass() != o.getClass()) {
     return false;
   }

   final Student student = (Student) o;

   if (this.age != student.age) {
     return false;
   }
   return this.name != null ? this.name.equals(student.name) : student.name == null;
 }

 @Override
 public int hashCode() {
   int result = this.age;
   result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
   return result;
 }
}
等于:
  • 首先,我们直接比较链接,因为如果链接指向同一个对象,那么继续检查有什么意义呢?无论如何,一切都会是真的

  • 检查 null 和匹配的类类型,因为如果对象是 null 或其他类型的参数,则意味着对象不相等 - false

  • 将参数对象转换为一种类型(如果它是父类型的对象)。

  • 比较原始类字段(毕竟,通过=!进行比较就足够了),如果字段不相等 - false

  • 检查非原始字段是否为 null 和equals(在String中,该方法被重写并将正确比较),如果两个字段均为 null 或equals,则检查结束并且该方法返回true

哈希码:
  • 将初始哈希码值设置为对象的Age Primitive 。

  • 将当前哈希码乘以 31(以获得更大的分布),并添加非原始字符串字段的哈希码(如果它不为空)。

  • 返回结果。

  • 由于此哈希码覆盖,具有相同名称int值的对象将始终返回相同的值。

103.使用if(objinstanceofStudent)和if(getClass()==obj.getClass())有什么区别?

让我们看看每种方法的作用:
  • instanceof检查左侧的对象引用是否是右侧类型或其某些子类型的实例。

  • getClass() == ...检查类型标识。

也就是说,如果getClass()检查类的完整标识,那么即使该对象只是一个子类型,instanceof也会返回true ,这可以在主动使用多态性时为我们提供更大的灵活性。实际上,如果您了解他们工作的特点并将其应用在正确的地方,这两种方法都很好。

104. 简要描述clone()方法。

Clone()是Object类的一个方法,其目的是创建并返回当前对象的克隆(当前对象的副本)。 Java 开发人员访谈问答分析。 第 11 - 4 部分要使用它,您需要实现Cloneable标记接口:
Student implements Cloneable
并重写clone()方法本身:
@Override
protected Object clone() throws CloneNotSupportedException {
 return super.clone();
}
毕竟,在Object类中它是受保护的,也就是说,它仅在Student类本身中可见,但对外部的类不可见。

105. 处理引用类型对象字段的clone()方法有什么特殊性?

克隆对象时,仅复制原始值和对象引用的值。这意味着,如果一个对象在其内部字段中有到另一个对象的链接,那么只有这个链接将被克隆,而另一个对象本身不会被克隆。事实上,这就是他们所说的表面克隆。那么,如果您需要克隆所有嵌套对象来进行全面克隆怎么办?如何确保这些不是链接的副本,而是堆中其他占用内存单元的对象的完整克隆?事实上,一切都非常简单 - 为此,您还需要重写这些内部对象的每个类中的clone()方法,并添加一个标记接口 - Cloneable。那么将不会复制对对象的引用,而是对象本身,因为现在它们也具有复制自身的能力。

例外情况

106.错误和异常有什么区别?

异常和错误都是Throwable类的子类。然而,它们也有不同之处。该错误表明主要是由于系统资源不足而出现的问题。我们的应用程序不应该检测这些类型的问题。一些错误的示例是系统崩溃和内存不足错误。错误大多发生在运行时,因为它们属于未经检查的类型。 Java 开发人员访谈问答分析。 第 11 - 5 部分异常是运行时和编译时可能发生的问题。通常,这种情况发生在开发人员编写的代码中。也就是说,异常更容易预测,并且更依赖于我们作为开发人员。同时,错误更加随机并且更加独立于我们,而是取决于应用程序运行所在的系统本身的问题。

107.checked和unchecked、异常、抛出、抛出的区别是什么。

正如我前面所说,异常是开发人员编写的代码在程序执行期间和编译期间发生的错误(由于某些异常情况)。 Checked是一种必须始终使用try-catch机制处理或抛出到上述方法中的异常。 Throws用于方法头中,指示该方法可能抛出的异常。也就是说,这就是将异常“抛出”到上述方法中的机制。 未经检查是一种不需要处理的异常,通常难以预测且不太可能发生。但是,如果需要,也可以对它们进行处理。 throw用于手动抛出异常,例如:
throw new Exception();

108. 例外情况的层次结构是什么?

异常的层次结构非常庞大和广泛,甚至过于广泛而无法在这里讲述它的所有内容。因此,我们将只考虑它的关键链接: Java 开发人员访谈问答分析。 第 11 - 6 部分在层次结构的最顶层,我们看到类 - Throwable - 一个通用类,异常层次结构的祖先,它又分为:
  • 错误- 严重的、无法检查的错误。
  • 异常- 检查异常。
异常分为各种非检查运行时异常和各种检查异常。

109.什么是检查异常和非检查异常?

正如我之前所说:
  • 检查- 您必须以某种方式处理的异常,也就是说,要么在try - catch块中处理它们,要么将它们“转发”到上面的方法。为此,在方法签名中,列出方法参数后,需要使用trows <exception type>关键字,它向方法的用户指示该方法可以抛出此异常(类似于警告)并传输处理此方法的用户的异常的责任。

  • 未检查的- 不需要处理的异常,因为它们在编译时不会检查,并且通常更难以预测。也就是说,与 Checked 的主要区别在于,对于它们来说,这些try-catch或 throwing 机制的工作原理相同,但它们不是强制性的。

101.编写在方法的try-catch块中拦截并处理异常的示例

try{                                                 // начало блока перехвата
 throw new Exception();                             // ручной бросок исключения
} catch (Exception e) {                              // данное исключение и его потомки будут перехватываться
 System.out.println("Упс, что-то пошло не так =("); // вывод некоторого исключения в консоль
}

102.使用自己的异常编写捕获和处理异常的示例

首先,让我们编写自己的异常类,它继承自Exception并使用错误消息重写其构造函数:
public class CustomException extends Exception {

 public CustomException(final String message) {
   super(message);
 }
}
好吧,那么我们将像上一个问题一样手动抛出并拦截它:
try{
 throw new CustomException("Упс, что-то пошло не так =(");
} catch (CustomException e) {
 System.out.println(e.getMessage());
}
同样,当您运行它时,您将在控制台中获得以下输出:
哎呀,出了点问题=(
Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 11 - 7您可以在此处了解有关例外情况的更多信息。好了,这就是今天的全部内容!下一部分见!
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION