Java Class Structure and Initialization Interview Questions – Java类结构和初始化面试题

最后修改: 2016年 12月 9日

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

1. Introduction

1.介绍

Class structure and initialization are the basics that every Java programmer should be familiar with. This article provides answers to some of the interview questions on the topic that you may encounter.

类结构和初始化是每个Java程序员都应该熟悉的基础知识。本文就你可能遇到的关于该主题的一些面试问题提供答案。

Q1. Describe the Meaning of the Final Keyword When Applied to a Class, Method, Field or a Local Variable.

Q1.描述当应用于类、方法、字段或局部变量时,最终关键字的含义

The final keyword has multiple different meanings when applied to different language constructs:

final关键字在应用于不同的语言结构时有多种不同的含义。

  • A final class is a class that cannot be subclassed
  • A final method is a method that cannot be overridden in subclasses
  • A final field is a field that has to be initialized in the constructor or initializer block and cannot be modified after that
  • A final variable is a variable that may be assigned (and has to be assigned) only once and is never modified after that

Q2. What Is a Default Method?

Q2.什么是默认方法?

Prior to Java 8, interfaces could only have abstract methods, i.e. methods without a body. Starting with Java 8, interface methods can have a default implementation. If an implementing class does not override this method, then the default implementation is used. Such methods are suitably marked with a default keyword.

在Java 8之前,接口只能有抽象的方法,即没有主体的方法。从Java 8开始,接口方法可以有一个默认的实现。如果一个实现类没有覆盖这个方法,那么就使用默认实现。这样的方法可以用default关键字进行适当的标记。

One of the prominent use cases of a default method is adding a method to an existing interface. If you don’t mark such interface method as default, then all existing implementations of this interface will break. Adding a method with a default implementation ensures binary compatibility of legacy code with the new version of this interface.

default方法的一个突出用例是向现有的接口添加一个方法。如果你不把这种接口方法标记为default,那么这个接口的所有现有实现都会被破坏。添加一个带有default实现的方法可以确保遗留代码与该接口的新版本的二进制兼容。

A good example of this is the Iterator interface which allows a class to be a target of the for-each loop. This interface first appeared in Java 5, but in Java 8 it received two additional methods, forEach, and spliterator. They are defined as default methods with implementations and thus do not break backward compatibility:

一个很好的例子是Iterator接口,它允许一个类成为for-each循环的目标。这个接口首次出现在Java 5中,但在Java 8中,它获得了两个额外的方法:forEach,和spliterator。它们被定义为带有实现的默认方法,因此不会破坏后向兼容性。

public interface Iterable<T> {

    Iterator<T> iterator();

    default void forEach(Consumer<? super T> action) { /* */ }

    default Spliterator<T> spliterator() { /* */ }
}

Q3. What Are Static Class Members?

Q3.什么是静态类成员?

Static fields and methods of a class are not bound to a specific instance of a class. Instead, they are bound to the class object itself. The call of a static method or addressing a static field is resolved at compile time because, contrary to instance methods and fields, we don’t need to walk the reference and determine an actual object we’re referring to.

静态类的字段和方法并不与类的特定实例绑定。相反,它们被绑定到类对象本身。对静态方法的调用或对静态字段的寻址是在编译时解决的,因为与实例方法和字段相反,我们不需要行走引用并确定我们所引用的实际对象。

Q4. May a Class Be Declared Abstract If It Does Not Have Any Abstract Members? What Could Be the Purpose of Such Class?

Q4.如果一个类没有任何抽象成员,它是否可以被宣布为抽象?这种类的目的是什么?

Yes, a class can be declared abstract even if it does not contain any abstract members. As an abstract class, it cannot be instantiated, but it can serve as a root object of some hierarchy, providing methods that can be useful to its implementations.

是的,一个类可以被声明为抽象,即使它不包含任何抽象成员。作为一个抽象类,它不能被实例化,但是它可以作为一些层次结构的根对象,提供对其实现有用的方法。

Q5. What Is Constructor Chaining?

Q5.什么是构造函数链?

Constructor chaining is a way of simplifying object construction by providing multiple constructors that call each other in sequence.

构造函数链是一种简化对象构造的方法,它提供了多个构造函数,并依次相互调用。

The most specific constructor may take all possible arguments and may be used for the most detailed object configuration. A less specific constructor may call the more specific constructor by providing some of its arguments with default values. At the top of the chain, a no-argument constructor could instantiate an object with default values.

最具体的构造函数可以接受所有可能的参数,可以用于最详细的对象配置。一个不那么具体的构造函数可以通过提供一些默认值的参数来调用更具体的构造函数。在链的顶端,一个无参数的构造函数可以用默认值来实例化一个对象。

Here’s an example with a class that models a discount in percents that are available within a certain amount of days. The default values of 10% and 2 days are used if we don’t specify them when using a no-arg constructor:

下面是一个例子,该类以百分数的形式模拟了一定天数内的折扣。如果我们在使用无参数构造函数时没有指定,则使用默认值10%和2天。

public class Discount {

    private int percent;

    private int days;

    public Discount() {
        this(10);
    }

    public Discount(int percent) {
        this(percent, 2);
    }

    public Discount(int percent, int days) {
        this.percent = percent;
        this.days = days;
    }

}

Q6. What Is Overriding and Overloading of Methods? How Are They Different?

Q6.什么是方法的重写和重载?它们有什么不同?

Overriding of a method is done in a subclass when you define a method with the same signature as in superclass. This allows the runtime to pick a method depending on the actual object type that you call the method on. Methods toString, equals, and hashCode are overridden quite often in subclasses.

当你在子类中定义了一个与超类中相同签名的方法时,就可以对该方法进行重写。这允许运行时根据你调用该方法的实际对象类型来选择一个方法。方法toStringequalshashCode在子类中经常被重写。

Overloading of a method happens in the same class. Overloading occurs when you create a method with the same name but with different types or number of arguments. This allows you to execute a certain code depending on the types of arguments you provide, while the name of the method remains the same.

一个方法的重载发生在同一个类中。当你创建一个名字相同但参数类型或数量不同的方法时,就会发生重载。这允许你根据你提供的参数类型来执行某种代码,而方法的名称保持不变。

Here’s an example of overloading in the java.io.Writer abstract class. The following methods are both named write, but one of them receives an int while another receives a char array.

下面是java.io.Writer抽象类中重载的一个例子。下面的方法都被命名为write,但是其中一个接收int,而另一个接收char阵列。

public abstract class Writer {

    public void write(int c) throws IOException {
        // ...
    }

    public void write(char cbuf[]) throws IOException {
        // ...
    }

}

Q7. Can You Override a Static Method?

Q7.你能覆盖一个静态方法吗?

No, you can’t. By definition, you can only override a method if its implementation is determined at runtime by the type of the actual instance (a process known as the dynamic method lookup). The static method implementation is determined at compile time using the type of the reference, so overriding would not make much sense anyway. Although you can add to subclass a static method with the exact same signature as in superclass, this is not technically overriding.

不,你不能。根据定义,只有当一个方法的实现在运行时由实际实例的类型决定时,你才能覆盖它(这个过程被称为动态方法查找)。静态方法的实现是在编译时通过引用的类型确定的,所以覆盖无论如何都没有什么意义。尽管你可以在子类中添加一个static方法,其签名与超类中的完全相同,但这在技术上并不是重写。

Q8. What Is an Immutable Class, and How Can You Create One?

Q8.什么是不可变的类,以及如何创建一个类?

An instance of an immutable class cannot be changed after it’s created. By changing we mean mutating the state by modifying the values of the fields of the instance. Immutable classes have many advantages: they are thread-safe, and it is much easier to reason about them when you have no mutable state to consider.

一个不可变的类的实例在创建后不能被改变。我们所说的改变是指通过修改实例的字段的值来改变状态。不可变类有很多优点:它们是线程安全的,而且当你没有可变的状态需要考虑时,对它们进行推理要容易得多。

To make a class immutable, you should ensure the following:

要使一个类成为不可变的,你应该确保以下几点。

  • All fields should be declared private and final; this infers that they should be initialized in the constructor and not changed ever since;
  • The class should have no setters or other methods that mutate the values of the fields;
  • All fields of the class that were passed via constructor should either be also immutable, or their values should be copied before field initialization (or else we could change the state of this class by holding on to these values and modifying them);
  • The methods of the class should not be overridable; either all methods should be final, or the constructor should be private and only invoked via static factory method.

Q9. How Do You Compare Two Enum Values: With equals() or With ==?

Q9.你如何比较两个枚举值 用equals()或用==?

Actually, you can use both. The enum values are objects, so they can be compared with equals(), but they are also implemented as static constants under the hood, so you might as well compare them with ==. This is mostly a matter of code style, but if you want to save character space (and possibly skip an unneeded method call), you should compare enums with ==.

事实上,你可以同时使用。enum值是对象,所以它们可以用equals()进行比较,但是它们也是作为引擎下的static常量实现的,所以你也可以用==进行比较。这主要是代码风格的问题,但如果你想节省字符空间(并可能跳过一个不需要的方法调用),你应该用==比较枚举。

Q10. What Is an Initializer Block? What Is a Static Initializer Block?

Q10.什么是初始化块?什么是静态初始化块?

An initializer block is a curly-braced block of code in the class scope which is executed during the instance creation. You can use it to initialize fields with something more complex than in-place initialization one-liners.

初始化块是在类的范围内的一个大括号的代码块,它在实例创建时被执行。你可以用它来初始化一些比原地初始化单行线更复杂的字段。

Actually, the compiler just copies this block inside every constructor, so it is a nice way to extract common code from all constructors.

实际上,编译器只是在每个构造函数中复制这个块,所以这是一种从所有构造函数中提取通用代码的好方法。

A static initializer block is a curly-braced block of code with the static modifier in front of it. It is executed once during the class loading and can be used for initializing static fields or for some side effects.

静态初始化块是一个大括号的代码块,前面有 static修饰符。它在类的加载过程中被执行一次,可用于初始化静态字段或一些副作用的处理。

Q11. What Is a Marker Interface? What Are the Notable Examples of Marker Interfaces in Java?

Q11.什么是标记器接口?在Java中,有哪些值得注意的标记器接口的例子?

A marker interface is an interface without any methods. It is usually implemented by a class or extended by another interface to signify a certain property. The most widely known marker interfaces in standard Java library are the following:

一个标记性的接口是一个没有任何方法的接口。它通常由一个类实现或由另一个接口扩展,以表示某种属性。在标准Java库中最广为人知的标记接口有以下几种。

  • Serializable is used to explicitly express that this class can be serialized;
  • Cloneable allows cloning objects using the clone method (without Cloneable interface in place, this method throws a CloneNotSupportedException);
  • Remote is used in RMI to specify an interface which methods could be called remotely.

Q12. What Is a Singleton and How Can It Be Implemented in Java?

Q12.什么是Singleton,如何在Java中实现它?

Singleton is a pattern of object-oriented programming. A singleton class may only have one instance, usually globally visible and accessible.

单子是面向对象编程的一种模式。一个单子类可能只有一个实例,通常是全局可见和可访问的。

There are multiple ways of creating a singleton in Java. The following is the most simple example with a static field that is initialized in-place. The initialization is thread-safe because static fields are guaranteed to be initialized in a thread-safe manner. The constructor is private, so there is no way for outer code to create more than one instance of the class.

在Java中,有多种创建单子的方法。下面是最简单的例子,有一个static字段,它被就地初始化。该初始化是线程安全的,因为static字段被保证以线程安全的方式初始化。构造函数是private,所以外部代码不可能创建一个以上的类实例。

public class SingletonExample {

    private static SingletonExample instance = new SingletonExample();

    private SingletonExample() {}

    public static SingletonExample getInstance() {
        return instance;
    }
}

But this approach could have a serious drawback — the instance would be instantiated when this class is first accessed. If initialization of this class is a heavy operation, and we would probably like to defer it until the instance is actually needed (possibly never), but at the same time keep it thread-safe. In this case, we should use a technique known as double-checked locking.

但是这种方法可能会有一个严重的缺点–当这个类第一次被访问时,这个实例就会被实例化。如果这个类的初始化是一个繁重的操作,我们可能希望把它推迟到真正需要这个实例的时候(可能永远不需要),但同时又要保持它的线程安全。在这种情况下,我们应该使用一种被称为双重检查锁的技术。

Q13. What Is a Var-Arg? What Are the Restrictions on a Var-Arg? How Can You Use It Inside the Method Body?

Q13.什么是 “变量”?对Var-Arg的限制是什么?如何在方法体中使用它?

Var-arg is a variable-length argument for a method. A method may have only one var-arg, and it has to come last in the list of arguments. It is specified as a type name followed by an ellipsis and an argument name. Inside the method body, a var-arg is used as an array of specified type.

Var-arg是一个方法的可变长度的参数。一个方法只能有一个var-arg,并且它必须在参数列表中排在最后。它被指定为一个类型名,后面是一个省略号和一个参数名。在方法主体中,var-arg被用作指定类型的数组。

Here’s an example from the standard library — the Collections.addAll method that receives a collection, a variable number of elements, and adds all elements to the collection:

这里有一个来自标准库的例子–Collections.addAll方法,它接收一个集合,一个可变数量的元素,并将所有元素添加到集合中。

public static <T> boolean addAll(
  Collection<? super T> c, T... elements) {
    boolean result = false;
    for (T element : elements)
        result |= c.add(element);
    return result;
}

Q14. Can You Access an Overridden Method of a Superclass? Can You Access an Overridden Method of a Super-Superclass in a Similar Way?

Q14.你能访问超类的重写方法吗?你能以类似的方式访问超超类的重载方法吗?

To access an overridden method of a superclass, you can use the super keyword. But you don’t have a similar way of accessing the overridden method of a super-superclass.

要访问一个超类的重写方法,你可以使用super关键字。但是你没有一个类似的方法来访问超超类的重载方法。

As an example from the standard library, LinkedHashMap class extends HashMap and mostly re-uses its functionality, adding a linked list over its values to preserve iteration order. LinkedHashMap re-uses the clear method of its superclass and then clears head and tail references of its linked list:

作为标准库中的一个例子,LinkedHashMap类扩展了HashMap,并主要重复使用其功能,在其值上添加一个链接列表以保持迭代顺序。LinkedHashMap重用了其超类的clear方法,然后清除了其链接列表的头和尾引用。

public void clear() {
    super.clear();
    head = tail = null;
}
Next »

Java 8 Interview Questions(+ Answers)

« Previous

Java Concurrency Interview Questions (+ Answers)