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

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

已在 Random-ZH 群组中发布
嗨嗨!Java 开发人员需要了解多少知识?你可以在这个问题上争论很长时间,但事实是,在面试中你将被理论所驱使。即使在那些您将没有机会在工作中使用的知识领域。 Java 开发人员访谈问答分析。 第 15 - 1 部分好吧,如果你是初学者,你的理论知识将会受到非常重视。由于还没有经验和伟大的成就,剩下的就是检查知识库的强度。今天,我们将通过研究 Java 开发人员最流行的面试问题来继续加强这一基础。让我们飞!

Java核心

9. Java中静态绑定和动态绑定有什么区别?

这个问题我在第18题关于静态多态和动态多态的这篇文章中已经回答过,建议你阅读一下。

10. 是否可以在接口中使用私有或受保护的变量?

你不能。因为当你声明一个接口时,Java编译器会自动在接口方法之前添加publicabstract关键字,在数据成员之前添加publicstaticfinal关键字。实际上,如果添加privateprotected,就会产生冲突,编译器会抱怨访问修饰符,并显示以下消息:“Modifier '<selected modifier>' not allowed here.”为什么编译器要添加publicstaticFinal界面中的变量?我们来算一下:
  • public - 接口允许客户端与对象交互。如果变量不是公开的,客户端将无法访问它们。
  • static - 无法创建接口(或者更确切地说,它们的对象),因此变量是静态的。
  • Final - 由于该接口用于实现 100% 抽象,因此该变量具有其最终形式(并且不会更改)。

11.什么是类加载器以及它的用途是什么?

类加载器- 或类加载器 - 提供 Java 类的加载。更准确地说,加载是由其后代(特定的类加载器)确保的,因为 ClassLoader本身是抽象的。每次加载 .class 文件时,例如,在调用相应类的构造函数或静态方法之后,此操作都会由ClassLoader类的后代之一执行。继承人分为三种类型:
  1. Bootstrap ClassLoader是一个基本的加载器,在 JVM 级别实现,没有来自运行时环境的反馈,因为它是 JVM 内核的一部分并用本机代码编写。该加载器充当所有其他 ClassLoader 实例的父级。

    主要负责加载JDK内部类,通常是位于$JAVA_HOME/jre/lib目录下的rt.jar等核心库。不同的平台可能对该类加载器有不同的实现。

  2. 扩展类加载器是一个扩展加载器,是基本加载器类的后代。负责加载标准 Java 基类的扩展。从 JDK 扩展目录加载,通常是$JAVA_HOME/lib/ext或 java.ext.dirs 系统属性中提到的任何其他目录(此选项可用于控制扩展的加载)。

  3. System ClassLoader是在 JRE 级别实现的系统加载器,负责将所有应用程序级别的类加载到 JVM 中。它加载在类环境变量-classpath-cp命令行选项中找到的文件。

Java 开发人员访谈问答分析。 第 15 - 2 部分类加载器是 Java 运行时的一部分。当 JVM 请求一个类时,类加载器会尝试查找该类并使用该类的完全限定名称将类定义加载到运行时中。java.lang.ClassLoader.loadClass()方法负责在运行时加载类定义。它尝试根据类的全名加载类。如果该类尚未加载,它将请求委托给父类加载器。此过程递归发生,如下所示:
  1. 系统类加载器尝试在其缓存中查找该类。

    • 1.1. 如果找到该类,则加载成功完成。

    • 1.2. 如果未找到该类,则将加载委托给扩展类加载器。

  2. 扩展类加载器尝试在自己的缓存中查找该类。

    • 2.1. 如果找到该类,则它成功完成。

    • 2.2. 如果未找到该类,则将加载委托给引导类加载器。

  3. Bootstrap 类加载器尝试在自己的缓存中查找该类。

    • 3.1. 如果找到该类,则加载成功完成。

    • 3.2. 如果找不到该类,底层的 Bootstrap 类加载器将尝试加载它。

  4. 如果加载:

    • 4.1. 成功 - 类加载完成。

    • 4.2. 如果失败,控制权将转移到扩展类加载器。

  5. 5.扩展类加载器尝试加载类,如果加载:

    • 5.1. 成功 - 类加载完成。

    • 5.2. 如果不成功,控制权将转移到系统类加载器。

  6. 6.系统类加载器尝试加载类,如果加载:

    • 6.1. 成功 - 类加载完成。

    • 6.2. 没有成功通过——产生异常——ClassNotFoundException。

类加载器这个话题涉及面很广,不应该被忽视。为了更详细地了解它,我建议您阅读这篇文章,我们不会徘徊并继续前进。

12. 什么是运行时数据区?

Run-Time Data Ares - JVM 运行时数据区域。JVM定义了程序执行过程中需要的一些运行时数据区域。其中一些是在 JVM 启动时创建的。其他的是线程本地的,仅在创建线程时创建(并在线程销毁时销毁)。JVM 运行时数据区域如下所示: Java 开发人员访谈问答分析。 第 15 - 3 部分
  • PC寄存器是每个线程本地的,包含线程当前正在执行的JVM指令的地址。

  • JVM 堆栈是一个内存区域,用于存储局部变量和临时结果。每个线程都有自己独立的堆栈:一旦线程终止,该堆栈也会被销毁。值得注意的是,栈相对于堆的优势在于性能,而堆在存储规模上当然更有优势。

  • 本机方法堆栈 - 存储数据元素的每线程数据区域,类似于 JVM 堆栈,用于执行本机(非 Java)方法。

  • 堆 - 被所有线程用作存储,其中包含在运行时创建的对象、类元数据、数组等。该区域在 JVM 启动时创建,在 JVM 关闭时销毁。

  • 方法区 - 该运行时区域对所有线程都是公共的,并且在 JVM 启动时创建。它存储每个类的结构,例如运行时常量池、构造函数和方法的代码、方法数据等。

13.什么是不可变对象?

文章这一部分,第14题和第15题中,已经有这个问题的答案了,看一下,别浪费时间了。

14. String类有什么特别之处?

在前面的分析中,我们反复讨论了String 的某些特性(对此有一个单独的部分)。现在我们来总结一下String的特点:
  1. 它是 Java 中最流行的对象,有多种用途。从使用频率上来说,甚至不逊色于原始类型。

  2. 无需使用 new 关键字即可创建此类的对象 - 直接通过引号String str = “string”;

  3. String一个不可变的类:当创建该类的对象时,它的数据不能改变(当你在某个字符串上添加+“另一个字符串”时,结果你将得到一个新的第三个字符串)。String 类的不变性使其成为线程安全的。

  4. String类是finalized的(有final修饰符),所以不能被继承。

  5. String有自己的字符串池,它是堆中的一块内存区域,用于缓存它创建的字符串值。在本系列的这一部分中,在问题 62 中,我描述了字符串池。

  6. Java 有String 的类似物,也设计用于处理字符串 - StringBuilderStringBuffer,但不同之处在于它们是可变的。您可以在本文中阅读有关它们的更多信息。

Java 开发人员访谈问答分析。 第 15 - 4 部分

15.什么是类型协方差?

为了理解协方差,我们将看一个例子。假设我们有一个动物类:
public class Animal {
 void voice() {
   System.out.println("*тишина*");
 }
}
还有一些Dog类扩展它:
public class Dog extends Animal {

 @Override
 public void voice() {
   System.out.println("Гав, гав, гав!!!");
 }
}
我们记得,我们可以轻松地将继承类型的对象分配给父类型:
Animal animal = new Dog();
这只不过是多态性。是不是方便、灵活?那么,动物名单呢?我们可以给出一个包含通用Animal 的列表和包含Dog对象的列表吗?
List<Dog> dogs = new ArrayList<>();
List<Animal> animals = dogs;
在这种情况下,将狗列表分配给动物列表的行将以红色下划线显示,即 编译器不会通过此代码。尽管这个赋值看起来很合乎逻辑(毕竟,我们可以将Dog对象赋值给Animal类型的变量),但它无法完成。这是因为如果允许的话,我们将能够将Animal对象放入最初打算成为Dog 的列表中,同时认为列表中只有Dogs。然后,例如,我们将使用get()方法从列表中获取一个对象,认为它是一只狗,并在其上调用Dog对象的某些方法,这是Animal没有的。正如您所理解的,这是不可能的 - 将会发生错误。但是,幸运的是,编译器不会错过将后代列表分配给父级列表的逻辑错误(反之亦然)。在 Java 中,您只能将列表对象分配给具有匹配泛型的列表变量。这称为不变性。如果他们能做到这一点,那就被称为协方差。也就是说,协方差是指我们是否可以将ArrayList<Dog>类型的对象设置为List<Animal>类型的变量。原来Java中不支持协方差?不管怎么样! 但这是以它自己特殊的方式完成的。设计是用来做什么的扩展了 Animal。它与我们想要设置列表对象的变量的泛型以及后代的泛型一起放置。这种通用构造意味着任何Animal类型的后代类型都可以(并且Animal类型也属于这种概括)。反过来,Animal不仅可以是一个类,还可以是一个接口(不要被extends关键字所迷惑)。我们可以像这样完成之前的任务: Java 开发人员访谈问答分析。 第 15 - 5 部分
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
因此,您将在 IDE 中看到编译器不会抱怨此构造。让我们检查一下这个设计的功能。假设我们有一个方法,可以让传递给它的所有动物发出声音:
public static void animalsVoice(List<? extends Animal> animals) {
 for (Animal animal : animals) {
   animal.voice();
 }
}
让我们给他一份狗的清单:
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
animalsVoice(dogs);
在控制台中我们将看到以下输出:
汪汪汪!!!汪汪汪!!!汪汪汪!!!
这意味着这种协方差方法是成功的。让我注意一下,这个通用名包含在列表中?扩展 Animal我们不能插入任何类型的新数据:既不能插入Dog类型,也不能插入Animal类型:
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
animals.add(new Dog());
dogs.add(new Animal());
实际上,在最后两行中,编译器将以红色突出显示对象的插入。这是因为我们无法百分百确定哪个类型的对象列表将通过通用<? 扩展动物>Java 开发人员访谈问答分析。 第 15 - 6 部分我还想谈谈逆变,因为通常这个概念总是与协变联系在一起,并且通常他们会一起被问到。这个概念在某种程度上与协方差相反,因为该构造使用继承人类型。假设我们想要一个列表,该列表可以分配不是Dog对象祖先的类型对象列表。然而,我们事先并不知道这些具体类型是什么。在这种情况下,形式的构造?super Dog,所有类型都适合 - Dog类的祖先:
List<Animal> animals = new ArrayList<>();
List<? super Dog> dogs = animals;
dogs.add(new Dog());
dogs.add(new Dog());
我们可以使用这样的泛型安全地将Dog类型的对象添加到列表中,因为在任何情况下它都具有其任何祖先的所有实现方法。但是我们将无法添加Animal类型的对象,因为不能确定内部是否存在该类型的对象,而不是Dog等类型的对象。毕竟,我们可以从此列表的元素请求Dog类的方法,而Animal则没有。在这种情况下,会出现编译错误。另外,如果我们想实现前面的方法,但使用这个泛型:
public static void animalsVoice(List<? super Dog> dogs) {
 for (Dog dog : dogs) {
   dog.voice();
 }
}
我们会在for循环 中遇到编译错误,因为我们无法确定返回的列表包含Dog类型的对象并且可以自由使用其方法。如果我们调用这个列表上的dogs.get(0)方法。- 我们将得到一个Object 类型的对象。也就是说,为了让AnimalsVoice()方法起作用,我们至少需要添加一些小的操作来缩小类型数据:
public static void animalsVoice(List<? super Dog> dogs) {
 for (Object obj : dogs) {
   if (obj instanceof Dog) {
     Dog dog = (Dog) obj;
     dog.voice();
   }
 }
}
Java 开发人员访谈问答分析。 第 15 - 7 部分

16.Object类中有哪些方法?

系列的第 11 段中,我已经回答了这个问题,因此,如果您还没有这样做,我强烈建议您阅读它。今天我们就到此结束。下一部分见! Java 开发人员访谈问答分析。 第 15 - 8 部分
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION