Java Interview Questions – Java面试问题

最后修改: 2018年 11月 24日

中文/混合/英文(键盘快捷键:t)

Table of Contents

目录

1. Introduction

1.绪论

This article contains answers to some of the most important job interview questions about core Java. The answers to some of them may not be obvious so this article will help to clear things up.

本文包含一些关于核心Java的最重要的工作面试问题的答案。其中有些问题的答案可能并不明显,所以本文将帮助大家理清头绪。

2. Core Java Questions for Beginners

2.初学者的核心Java问题

Q1. Is Data Passed by Reference or by Value in Java?

Q1.在Java中,数据是通过引用还是通过值传递?

Although the answer to this question is pretty simple, this question may be confusing for beginners. First, let’s clarify what the question is about:

虽然这个问题的答案相当简单,但这个问题对初学者来说可能会感到困惑。首先,让我们澄清一下这个问题是关于什么的。

  1. Passing by value – means that we pass a copy of an object as a parameter into a method.
  2. Passing by reference – means that we pass a reference to an object as a parameter into a method.

To answer the question we have to analyze two cases. They represent two types of data that we can pass to a method: a primitive and an object.

为了回答这个问题,我们必须分析两种情况。它们代表了我们可以传递给方法的两种类型的数据:一个基元和一个对象。

When we pass primitives to a method, its value is copied into a new variable. When it comes to objects, the value of the reference is copied into a new variable. So we can say that Java is a strictly pass-by-value language.

当我们向方法传递基元时,它的值被复制到一个新的变量中。当涉及到对象时,引用的值被复制到一个新的变量中。因此我们可以说,Java是一种严格的逐值传递语言。

We can learn more about that in one of our articles: Pass-By-Value as a Parameter Passing Mechanism in Java.

我们可以在我们的一篇文章中了解更多的信息。作为Java中参数传递机制的逐值传递

Q2. What Is the Difference Between Import and Static Imports?

Q2.进口和静态进口之间的区别是什么?

We can use regular imports to import a specific class or all classes defined in a different package:

我们可以使用常规导入来导入一个特定的类或定义在不同包中的所有类。

import java.util.ArrayList; //specific class
import java.util.*; //all classes in util package

We can also use them to import public nested classes of an enclosing class:

我们也可以用它们来导入一个包围类的公共嵌套类。

import com.baeldung.A.*

However, we should be aware that the import above doesn’t import class A itself.

然而,我们应该注意,上面的导入并没有导入类A本身。

There are also static imports that enable us to import static members or nested classes:

还有一些静态导入,使我们能够导入静态成员或嵌套类:

import static java.util.Collections.EMPTY_LIST;

The effect is that we can use the static variable EMPTY_LIST without prepending the fully qualified class name, i.e. as if it was declared in the current class.

其效果是,我们可以使用静态变量EMPTY_LIST,而不需要预留完全合格的类名,也就是说,就像它在当前类中声明一样。

Q3. Which Access Modifiers Are Available in Java and What Is Their Purpose?

Q3.在Java中哪些访问修饰符是可用的,它们的目的是什么?

There are four access modifiers in Java:

Java中,有四个访问修饰符。

  1. private
  2. default (package)
  3. protected
  4. public

The private modifier assures that class members won’t be accessible outside the class. It can be applied to methods, properties, constructors, nested classes, but not to top-level classes themselves.

private修饰符保证了类成员不会被类之外的人访问。它可以应用于方法、属性、构造函数、嵌套类,但不能应用于顶级类本身。

Unlike the private modifier, we can apply the default modifier to all types of class members and to the class itself. We can apply default visibility by not adding any access modifier at all. If we use default visibility our class or its members will be accessible only inside the package of our class. We should keep in mind that the default access modifier has nothing in common with the default keyword.

private修改器不同,我们可以将default修改器应用于所有类型的类成员和类本身。我们可以通过完全不添加任何访问修饰符来应用default可见性。如果我们使用default visibility,我们的类或其成员将只能在我们的类的包中被访问。我们应该记住,默认访问修饰符与default关键字没有任何共同之处。

Similar to the default modifier, all classes within one package can access protected members. What’s more, the protected modifier allows subclasses to access the protected members of a superclass, even if they are not within the same package. We can’t apply this access modifier to classes, only to class members.

default修饰符类似,一个包内的所有类都可以访问protected成员。更重要的是,protected修饰符允许子类访问超类的受保护成员,即使它们不在同一个包内。我们不能将这个访问修饰符应用于类,只能应用于类成员。

The public modifier can be used together with the class keyword and all class members. It makes classes and class members accessible in all packages and by all classes.

public修饰符可以与class关键字和所有类成员一起使用。它使类和类成员可以在所有包中被所有类访问。

We can learn more in the Java Access Modifiers article.

我们可以在Java Access Modifiers文章中了解更多。

Q4. Which Other Modifiers Are Available in Java and What Is Their Purpose?

Q4.Java中还有哪些修改器,它们的用途是什么?

There are five other modifiers available in Java:

在Java中还有其他五个修饰符可用。

  • static
  • final
  • abstract
  • synchronized
  • volatile

These do not control visibility.

这些并不控制能见度。

First of all, we can apply the static keyword to fields and methods. Static fields or methods are class members, whereas non-static ones are object members. Class members don’t need an instance to be invoked. They are called with the class name instead of the object reference name. This article goes into more detail about the static keyword.

首先,我们可以对字段和方法应用static关键字。静态字段或方法是类成员,而非静态的是对象成员。类成员不需要实例就能被调用。它们是用类名而不是对象引用名来调用的。这篇文章更详细地介绍了static关键字。

Then, we have the final keyword. We can use it with fields, methods, and classes. When final is used on a field, it means that the field reference cannot be changed. So it can’t be reassigned to another object. When final is applied to a class or a method, it assures us that that class or method cannot be extended or overridden. The final keyword is explained in more detail in this article.

然后,我们有final关键字。final被用于一个字段时,它意味着字段的引用不能被改变。final应用于一个类或一个方法时,它向我们保证该类或方法不能被扩展或覆盖。 final关键字在这篇文章中有更详细的解释。

The next keyword is abstract. This one can describe classes and methods. When classes are abstract, they can’t be instantiated. Instead, they are meant to be subclassed. When methods are abstract, they are left without implementation and can be overridden in subclasses.

下一个关键字是abstract。这个可以描述类和方法。当类是抽象的时,它们不能被实例化。相反,它们是要被子类化的。当方法是抽象的时,它们没有被实现,可以在子类中被重写。

The synchronized keyword may be the most advanced. We can use it with the instance as well as with static methods and code blocks. When we use this keyword, we make Java use a monitor lock to provide synchronization on a given code fragment. More information about synchronized can be found in this article.

synchronized关键字可能是最先进的。我们可以对实例以及静态方法和代码块使用它。当我们使用这个关键字时,我们让Java使用一个监控锁来对给定的代码片段提供同步。关于synchronized的更多信息可以在这篇文章中找到。

The last keyword we’re going to discuss is volatile. We can only use it together with instance fields. It declares that the field value must be read from and written to the main memory – bypassing the CPU cache. All reads and writes for a volatile variable are atomic. The volatile keyword is explained in detail in this article.

我们要讨论的最后一个关键词是volatile。我们只能和实例字段一起使用它。它声明字段值必须从主内存中读取和写入–绕过CPU缓存。对于volatile变量的所有读写都是原子的。在这篇文章中详细解释了volatile关键字。

Q5. What Is the Difference Between JDK, JRE, and JVM?

Q5.JDK、JRE和JVM之间的区别是什么?

JDK stands for Java Development Kit, which is a set of tools necessary for developers to write applications in Java. There are three types of JDK environments:

JDKJava Development Kit的缩写,它是开发人员用Java编写应用程序所需的一组工具。有三种类型的JDK环境。

  • Standard Edition – development kit for creating portable desktop or server applications
  • Enterprise Edition – an extension to the Standard Edition with support for distributed computing or web services
  • Micro Edition – development platform for embedded and mobile applications

There are plenty of tools included in the JDK which help programmers with writing, debugging, or maintaining applications. The most popular ones are a compiler (javac), an interpreter (java), an archiver (jar), and a documentation generator (javadoc).

JDK中包含了很多工具,它们帮助程序员编写、调试或维护应用程序。最受欢迎的工具是一个编译器(javac)、一个解释器(java)、一个存档器(jar)和一个文档生成器(javadoc)。

JRE is a Java Runtime Environment. It’s a part of the JDK, but it contains the minimum functionality to run Java applications. It consists of a Java Virtual Machine, core classes, and supporting files. For example, it doesn’t have any compiler.

JREJava Runtime Environment。它是JDK的一部分,但它包含运行Java应用程序的最低功能。它由一个Java虚拟机、核心类和支持文件组成。例如,它没有任何编译器。

JVM is the acronym for Java Virtual Machine, which is a virtual machine able to run programs compiled to bytecode. It’s described by the JVM specification, as it’s important to ensure interoperability between different implementations. The most important function of a JVM is to enable users to deploy the same Java application into different operating systems and environments without worrying about what lies underneath.

JVMJava虚拟机的首字母缩写,它是一种能够运行编译为字节码的程序的虚拟机。它由JVM规范描述,因为它对确保不同实现之间的互操作性很重要。JVM最重要的功能是使用户能够将同一个Java应用程序部署到不同的操作系统和环境中,而不必担心下面的东西

For more information, let’s check the Difference Between JVM, JRE, and JDK article.

欲了解更多信息,让我们查看JVM、JRE和JDK之间的区别文章。

Q6. What Is the Difference Between Stack and Heap?

Q6.堆栈和堆之间的区别是什么?

There are two parts of memory where all variables and objects are stored by the JVM. The first is the stack and the second is the heap.

内存有两个部分,所有的变量和对象都被JVM存储在这里。第一个是,第二个是

The stack is a place where the JVM reserves blocks for local variables and additional data. The stack is a LIFO (last in first out) structure. It means that whenever a method is called, a new block is reserved for local variables and object references. Each new method invocation reserves the next block. When methods finish their execution, blocks are released in the reversed manner they were started.

堆栈是JVM为局部变量和额外数据保留块的地方。堆栈是一个LIFO(后进先出)结构。这意味着每当一个方法被调用时,都会为局部变量和对象引用保留一个新的块。每个新方法的调用都会保留下一个块。当方法执行完毕后,区块会以相反的方式被释放。

Every new thread has its own stack.

每个新线程都有自己的堆栈。

We should be aware that the stack has much less memory space than the heap. And when a stack is full, the JVM will throw a StackOverflowError. It’s likely to occur when there is a bad recursive call and the recursion goes too deep.

我们应该意识到,堆栈的内存空间比堆少得多。而当堆栈满了,JVM会抛出一个StackOverflowError。这很可能发生在有一个糟糕的递归调用和递归过深的时候。

Every new object is created on the Java heap which is used for a dynamic allocation. There is a garbage collector which is responsible for erasing unused objects which are divided into young (nursery) and old spaces. Memory access to the heap is slower than access to the stack. The JVM throws an OutOfMemoryError when the heap is full.

每一个新的对象都是在Java的heap上创建的,它被用于动态分配。有一个g垃圾收集器,它负责清除未使用的对象,这些对象被分为幼年(苗圃)和老年空间。对堆的内存访问比对栈的访问要慢。当堆满时,JVM会抛出一个OutOfMemoryError

We can find more details in the Stack Memory and Heap Space in Java article.

我们可以在Java中的堆栈内存和堆空间文章中找到更多细节。

Q7. What Is the Difference Between the Comparable and Comparator Interfaces?

Q7.ComparableComparator接口之间的区别是什么?

Sometimes when we write a new class, we would like to be able to compare objects of that class. It’s especially helpful when we want to use sorted collections. There are two ways we can do this: with the Comparable interface or with the Comparator interface.

有时,当我们编写一个新的类时,我们希望能够对该类的对象进行比较。当我们想使用排序的集合时,这一点尤其有帮助。我们有两种方法可以做到这一点:使用Comparable接口或使用Comparator接口。

First, let’s look at the Comparable interface:

首先,让我们看一下Comparable接口。

public interface Comparable<T> {
    int compareTo(T var1);
}

We should implement that interface by the class whose objects we want to sort.

我们应该通过我们想对其对象进行分类的类来实现该接口。

It has the compareTo() method and returns an integer. It can return three values: -1, 0, and 1 which means that this object is less than, equal to or greater than the compared object.

它有compareTo()方法并返回一个整数。它可以返回三个值。-1、0和1,这意味着这个对象小于、等于或大于被比较对象。

It’s worth mentioning that the overridden compareT0() method should be consistent with the equals() method.

值得一提的是,重载的compareT0()方法应该与equals()方法一致。

On the other hand, we can use the Comparator interface. It can be passed to the sort() methods of the Collection interface or when instantiating sorted collections. That’s why it’s mostly used to create a one-time sorting strategy.

另一方面,我们可以使用Comparator接口。它可以被传递给Collection接口的sort()方法,或者在实例化排序的集合时被传递。这就是为什么它大多用于创建一次性的排序策略。

What’s more, it’s also useful when we use a third-party class that doesn’t implement the Comparable interface.

更重要的是,当我们使用一个没有实现可比较接口的第三方类时,它也很有用。

Like the compareTo() method, the overridden compare() methods should be consistent with the equals() method, but they may optionally allow comparison with nulls.

compareTo()方法一样,被覆盖的compare()方法应该与equals()方法一致,但是它们可以选择允许与空值进行比较。

Let’s visit the Comparator and Comparable in Java article for more information.

让我们访问Java中的Comparator和Comparable文章以了解更多信息。

Q8. What Is the void Type and When Do We Use It?

Q8.什么是void类型,我们何时使用它?

Every time we write a method in Java, it must have a return type. If we want the method to return no value, we can use the void keyword.

每次我们在Java中写一个方法时,它必须有一个返回类型。如果我们希望方法不返回任何值,我们可以使用void关键字。

We should also know that there is a Void class. It’s a placeholder class that may be used, for example, when working with generics. The Void class can neither be instantiated nor extended.

我们还应该知道,有一个Void类。这是一个占位符类,例如,在使用泛型时可以使用。Void类既不能被实例化也不能被扩展。

Q9. What Are the Methods of the Object Class and What Do They Do?

Q9.什么是对象类的方法,它们的作用是什么?

It’s important to know what methods the Object class contains and how they work. It’s also very helpful when we want to override those methods:

了解Object类包含哪些方法以及它们如何工作是很重要的。当我们想要覆盖这些方法时,这也是非常有帮助的。

  • clone() – returns a copy of this object
  • equals() – returns true when this object is equal to the object passed as a parameter
  • finalize() – the garbage collector calls this method while it’s cleaning the memory
  • getClass() – returns the runtime class of this object
  • hashCode() – returns a hash code of this object. We should be aware that it should be consistent with the equals() method
  • notify() – sends a notification to a single thread waiting for the object’s monitor
  • notifyAll() – sends a notification to all threads waiting for the object’s monitor
  • toString() – returns a string representation of this object
  • wait() – there are three overloaded versions of this method. It forces the current thread to wait the specified amount of time until another thread calls notify() or notifyAll() on this object.

Q10. What Is an Enum and How We Can Use It?

Q10.什么是枚举以及我们如何使用它?

Enum is a type of class that allows developers to specify a set of predefined constant values. To create such a class we have to use the enum keyword. Let’s imagine an enum of days of the week:

Enum是一种类型的类,允许开发者指定一组预定义的常量值。为了创建这样一个类,我们必须使用enum关键字。让我们想象一下,一个星期的日子的枚举。

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY 
}

To iterate over all constants we can use the static values() method. What’s more, enums enable us to define members such as properties and methods like regular classes.

为了遍历所有常量,我们可以使用静态的values()方法。更重要的是,枚举使我们能够像普通类一样定义成员,如属性和方法。

Although it’s a special type of class, we can’t subclass it. An enum can, however, implement an interface.

虽然它是一种特殊的类,但我们不能对它进行子类化。然而,枚举可以实现一个接口。

Another interesting advantage of Enums is that they are thread-safe and so they are popularly used as singletons.

Enums的另一个有趣的优点是它们是线程安全的,因此它们被普遍用作单子。

We can find more about Enums in one of our guides.

我们可以在我们的一个指南中找到更多关于Enums的信息。

Q11. What Is a JAR?

Q11.什么是aJAR?

JAR is a shortcut for Java archive. It’s an archive file packaged using the ZIP file format. We can use it to include the class files and auxiliary resources that are necessary for applications. It has many features:

JARJava archive的一个快捷方式。它是一个使用ZIP文件格式打包的档案文件。我们可以用它来包含应用程序所需的类文件和辅助资源。它有很多功能。

  • Security – we can digitally sign JAR files
  • Compression – while using a JAR, we can compress files for efficient storage
  • Portability – we can use the same JAR file across multiple platforms
  • Versioning – JAR files can hold metadata about the files they contain
  • Sealing – we can seal a package within a JAR file. This means that all classes from one package must be included in the same JAR file
  • Extensions – we can use the JAR file format to package modules or extensions for existing software

Q12. What Is a NullPointerException?

Q12.什么是a NullPointerException

The NullPointerException is probably the most common exception in the Java world.  It’s an unchecked exception and thus extends RuntimeException. We shouldn’t try to handle it.

NullPointerException可能是Java世界中最常见的异常。 它是一个未经检查的异常,因此扩展了RuntimeException。我们不应该尝试去处理它。

This exception is thrown when we try to access a variable or call a method of a null reference, like when:

当我们试图访问一个变量或调用一个空引用的方法时,就会抛出这个异常,比如当。

  • invoking a method of a null reference
  • setting or getting a field of a null reference
  • checking the length of a null array reference
  • setting or getting an item of a null array reference
  • throwing null

Q13. What Are Two Types of Casting in Java? Which Exception May Be Thrown While Casting? How Can We Avoid It?

Q13.在Java中,有哪两种类型的投递?铸造时可能会抛出哪些异常?我们如何避免它?

We can distinguish two types of casting in Java. We can do upcasting which is casting an object to a supertype or downcasting which is casting an object to a subtype.

我们可以在Java中区分两种类型的铸造。我们可以做上投,即把一个对象投到一个超类型,或者下投,即把一个对象投到一个子类型。

Upcasting is very simple, as we always can do that. For example, we can upcast a String instance to the Object type:

上报非常简单,因为我们总是可以做到这一点。例如,我们可以将一个String实例上传到Object类型。

Object str = "string";

Alternatively, we can downcast a variable. It’s not as safe as upcasting as it involves a type check. If we incorrectly cast an object, the JVM will throw a ClassCastExcpetion at runtime. Fortunately, we can use the instanceof keyword to prevent invalid casting:

另外,我们也可以下传一个变量。这并不像上投那样安全,因为它涉及到类型检查。如果我们错误地铸造了一个对象,JVM将在运行时抛出一个ClassCastExcpetion幸运的是,我们可以使用instanceof关键字来防止无效的铸造:

Object o = "string";
String str = (String) o; // it's ok

Object o2 = new Object();
String str2 = (String) o2; // ClassCastException will be thrown

if (o2 instanceof String) { // returns false
    String str3 = (String) o2;
}

We can learn more about typecasting in this article.

我们可以在这篇文章中了解更多关于类型转换的信息。

3. Core Java Questions for Advanced Programmers

3.高级程序员的核心Java问题

Q1. Why Is String an Immutable Class?

Q1.为什么字符串是一个不可变的类?

We should know that String objects are treated differently than other objects by the JVM. One difference is that String objects are immutable. It means that we can’t change them once we have created them. There are several reasons why they behave that way:

我们应该知道,String对象被JVM处理得与其他对象不同。其中一个区别是,String对象是不可变的。这意味着一旦我们创建了它们,我们就不能改变它们。有几个原因使它们表现得如此之好。

  1. They are stored in the string pool which is a special part of the heap memory. It’s responsible for saving a lot of space.
  2. The immutability of the String class guarantees that its hash code won’t change. Due to that fact, Strings can be effectively used as keys in hashing collections. We can be sure that we won’t overwrite any data because of a change in hash codes.
  3. They can be used safely across several threads. No thread can change the value of a String object, so we get thread safety for free.
  4. Strings are immutable to avoid serious security issues. Sensitive data such as passwords could be changed by an unreliable source or another thread.

We can learn more about the immutability of Strings in this article.

我们可以在这篇文章中了解更多关于字符串的不可变性

Q2. What Is the Difference Between Dynamic Binding and Static Binding?

Q2.动态捆绑和静态捆绑之间的区别是什么?

Binding in Java is a process of associating a method call with the proper method body. We can distinguish two types of binding in Java: static and dynamic.

Java中的绑定是一个将方法调用与适当的方法体联系起来的过程。我们可以将Java中的绑定区分为两种类型:静态和动态。

The main difference between static binding and dynamic binding is that static binding occurs at compile time and dynamic binding at runtime.

静态绑定和动态绑定的主要区别在于,静态绑定发生在编译时,动态绑定发生在运行时。

Static binding uses class information for binding. It’s responsible for resolving class members that are private or static and final methods and variables. Also, static binding binds overloaded methods.

静态绑定使用类信息进行绑定。它负责解决属于私有静态最终方法和变量的类成员。此外,静态绑定还绑定了重载方法。

Dynamic binding, on the other hand, uses object information to resolve bindings. That’s why it’s responsible for resolving virtual and overridden methods.

动态绑定,另一方面,使用对象信息来解析绑定。这就是为什么它负责解析虚拟和重写方法。

Q3. What Is JIT?

Q3.什么是JIT?

JIT stands for “just in time”. It’s a component of the JRE that runs in the runtime and increases the performance of the application. Specifically, it’s a compiler that runs just after the program’s start.

JIT是 “just in time “的缩写。它是JRE的一个组件,在运行时运行并提高应用程序的性能。具体来说,它是一个在程序启动后才运行的编译器。

This is different from the regular Java compiler which compiles the code long before the application is started. JIT can speed up the application in different ways.

这与普通的Java编译器不同,后者在应用程序启动前很久就开始编译代码了。JIT可以以不同的方式加快应用程序的速度。

For example, the JIT compiler is responsible for compiling bytecode into native instructions on the fly to improve performance. Also, it can optimize the code to the targeted CPU and operating system.

例如,JIT编译器负责将字节码即时编译成本地指令,以提高性能。此外,它还可以根据目标CPU和操作系统优化代码。

Additionally, it has access to many runtime statistics which may be used for recompilation for optimal performance. With this, it can also do some global code optimizations or rearrange code for better cache utilization.

此外,它还可以访问许多运行时的统计数据,这些数据可用于重新编译以获得最佳性能。有了这个,它还可以做一些全局性的代码优化,或者重新排列代码以提高缓存的利用率。

Q4. What Is Reflection in Java?

Q4.什么是Java中的反思?

Reflection is a very powerful mechanism in Java. Reflection is a mechanism of Java language which enables programmers to examine or modify the internal state of the program (properties, methods, classes etc.) at runtime. The java.lang.reflect package provides all required components for using reflection.

反射是Java中一个非常强大的机制。反射是Java语言的一种机制,它使程序员能够在运行时检查或修改程序的内部状态(属性、方法、类等)。java.lang.reflect包提供了使用反射的所有必要组件。

When using this feature, we can access all possible fields, methods, constructors that are included within a class definition. We can access them irrespective of their access modifier. It means that for example, we are able to access private members. To do that, we don’t have to know their names. All we have to do is to use some static methods of Class.

当使用这个功能时,我们可以访问包含在类定义中的所有可能的字段、方法、构造函数。我们可以访问它们,而不考虑它们的访问修饰符。这意味着,例如,我们能够访问私有成员。要做到这一点,我们不需要知道它们的名字。我们所要做的就是使用Class的一些静态方法。

It’s worth knowing that there is a possibility to restrict access via reflection. To do that we can use the Java security manager and the Java security policy file. They allow us to grant permissions to classes.

值得知道的是,有一种可能性是通过反射来限制访问。要做到这一点,我们可以使用Java安全管理器和Java安全策略文件。它们允许我们对类授予权限。

When working with modules since Java 9, we should know that by default, we aren’t able to use reflection on classes imported from another module. To allow other classes to use reflection to access the private members of a package we have to grant the “Reflection” Permission.

从Java 9开始使用模块时,我们应该知道,默认情况下,我们不能对从其他模块导入的类使用反射。为了允许其他类使用反射来访问一个包的私有成员,我们必须授予 “反射 “权限。

This article goes into more depth about Java Reflection.

这篇文章更深入地介绍了Java Reflection。

Q5. What Is a Classloader?

Q5.什么是a Classloader?

The classloader is one of the most important components in Java. It’s a part of the JRE.

类加载器是Java中最重要的组件之一。它是JRE的一部分。

Simply put, the classloader is responsible for loading classes into the JVM. We can distinguish three types of classloaders:

简单地说,类加载器负责将类加载到JVM。我们可以区分三种类型的类加载器。

  • Bootstrap classloader – it loads the core Java classes. They are located in the <JAVA_HOME>/jre/lib directory
  • Extension classloader – it loads classes located in <JAVA_HOME>/jre/lib/ext or in the path defined by the java.ext.dirs property
  • System classloader – it loads classes on the classpath of our application

A classloader loads classes “on demand”. It means that classes are loaded after they are called by the program. What’s more, a classloader can load a class with a given name only once. However, if the same class is loaded by two different class loaders, then those classes fail in an equality check.

一个类加载器 “按需 “加载类。这意味着类在被程序调用后被加载。更重要的是,一个类加载器只能加载一个给定名称的类一次。然而,如果同一个类被两个不同的类加载器加载,那么这些类就会在平等检查中失败。

There is more information about classloaders in the Class Loaders in Java article.

Java中的类加载器文章中有关于类加载器的更多信息。

Q6. What Is the Difference Between Static and Dynamic Class Loading?

Q6.静态和动态类加载之间的区别是什么?

Static class loading takes place when we have source classes available at compile time. We can make use of it by creating object instances with the new keyword.

静态类加载发生在我们在编译时有源类可用的时候。我们可以通过使用new关键字创建对象实例来利用它。

Dynamic class loading refers to a situation when we can’t provide a class definition at the compile time. Yet, we can do that at runtime. To create an instance of a class, we have to use the Class.forName() method:

动态类加载是指当我们不能在编译时提供类定义的情况。然而,我们可以在运行时做到这一点。为了创建一个类的实例,我们必须使用Class.forName()方法。

Class.forName("oracle.jdbc.driver.OracleDriver")

Q7. What Is the Purpose of the Serializable Interface?

Q7.Serializable接口的目的是什么?

We can use the Serializable interface to enable the serializability of a class, using Java’s Serialization API. Serialization is a mechanism for saving the state of an object as a sequence of bytes while deserialization is a mechanism for restoring the state of an object from a sequence of bytes. The serialized output holds the object’s state and some metadata about the object’s type and types of its fields.

我们可以使用Serializable接口来启用类的可序列化,使用Java的序列化API。序列化是一种将对象的状态保存为一串字节的机制,而反序列化是一种从一串字节恢复对象状态的机制。串行化的输出持有对象的状态和一些关于对象的类型及其字段类型的元数据。

We should know that subtypes of serializable classes are also serializable. However, if we want to make a class serializable, but its supertype is non-serializable we have to do two things:

我们应该知道,可序列化的类的子类型也是可序列化的。然而,如果我们想让一个类可序列化,但它的超类型是不可序列化的,我们必须做两件事。

  • implement the Serializable interface
  • assure that a no-argument constructor is present in the superclass

We can read more about Serialization in one of our articles.

我们可以在我们的一篇文章中阅读更多关于序列化的信息。

Q8. Is There a Destructor in Java?

Q8.在Java中是否有一个析构器?

In Java, the garbage collector automatically deletes the unused objects to free up the memory. Developers have no need to mark the objects for deletion, which is error-prone. So it’s sensible Java has no destructors available.

在Java中,垃圾收集器会自动删除未使用的对象以释放内存。开发人员不需要标记对象进行删除,这很容易出错。因此,Java没有可用的析构器是明智的。

In case the objects hold open sockets, open files, or database connections, the garbage collector is not able to reclaim those resources. We can release the resources in the close method and use try-finally syntax to call the method afterward before Java 7, such as the I/O classes FileInputStreamand FileOutputStreamAs of Java 7, we can implement the interface AutoCloseable and use try-with-resources statement to write shorter and cleaner code.  But it’s possible the API users forget to call the close method, so the finalize method and Cleaner class come into existence to act as the safety net. But please be cautioned they are not equivalent to the destructor.

如果对象持有开放的套接字、开放的文件或数据库连接,垃圾回收器无法回收这些资源。我们可以在close方法中释放资源,并在Java 7之前使用try-finally语法在之后调用该方法,例如I/O类FileInputStreamFileOutputStream从Java 7开始,我们可以实现接口AutoCloseable,并使用try-with-resources语句来编写更短、更干净的代码。 但是API用户有可能忘记调用close方法,所以finalize方法和Cleaner类的出现就是为了充当安全网。但请注意,它们并不等同于析构器。

It’s not assured both the finalize method and the Cleaner class will run promptly. They even get no chance to run before the JVM exits. Although we could call System.runFinalization to suggest that JVM run the finalize methods of any objects pending for finalization, it’s still non-deterministic.

不能保证finalize方法和Cleaner类都能及时运行。它们甚至没有机会在 JVM 退出前运行。尽管我们可以调用System.runFinalization来建议JVM运行任何待定对象的finalize方法,但这仍然是不确定的。

Moreover, the finalize method can cause performance issues, deadlocks, etc. We can find more information by looking at one of our articles: A Guide to the finalize Method in Java.

此外,finalize方法会导致性能问题、死锁等。我们可以通过查看我们的一篇文章来了解更多信息。Java中finalize方法的指南

As of Java 9, the Cleaner class is added to replace the finalize method because of the downsides it has. As a result, we have better control over the thread which does the cleaning actions.

从Java 9开始,添加了Cleaner 类来取代finalize 方法,因为它有很多缺点。因此,我们可以更好地控制进行清洁操作的线程。

But the java spec points out the behavior of cleaners during System.exit is implementation-specific and Java provides no guarantees whether cleaning actions will be invoked or not.

但java规范指出,清洁器在System.exit期间的行为是特定于实现的,Java不保证清洁动作是否会被调用。