Java Type System Interview Questions – Java类型系统面试问题

最后修改: 2016年 11月 20日

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

1. Introduction

1.介绍

Java Type System is a topic often brought up on technical interviews for Java developers. This article reviews some important questions that are asked most often and may be tricky to get right.

Java类型系统是Java开发人员技术面试中经常提到的一个话题。本文回顾了一些最常被问到的重要问题,这些问题可能很棘手,要答对。

2. Questions

2.问题

Q1. Describe the Place of the Object Class in the Type Hierarchy. Which Types Inherit from Object, and Which Don’t? Do Arrays Inherit from Object? Can a Lambda Expression Be Assigned to an Object Variable?

Q1.描述一下对象类在类型层次中的位置 哪些类型继承于Object,哪些不继承?数组是否继承于对象?兰姆达表达式可以分配给一个对象变量吗?

The java.lang.Object is at the top of the class hierarchy in Java. All classes inherit from it, either explicitly, implicitly (when the extends keyword is omitted from the class definition) or transitively via the chain of inheritance.

java.lang.Object在Java中处于类层次结构的顶端。所有的类都从它那里继承,可以是显性的,也可以是隐性的(当类定义中省略了extends关键字时),也可以是通过继承链来继承的。

However, there are eight primitive types that do not inherit from Object, namely boolean, byte, short, char, int, float, long and double.

然而,有八个原始类型不继承于Object,即booleanbyteshortcharintfloatlongdouble

According to the Java Language Specification, arrays are objects too. They can be assigned to an Object reference, and all Object methods may be called on them.

根据Java语言规范,数组也是对象。它们可以被分配给一个Object引用,并且所有的Object方法都可以在它们身上调用。

Lambda expressions can’t be assigned directly to an Object variable because Object is not a functional interface. But you can assign a lambda to a functional interface variable and then assign it to an Object variable(or simply assign it to an Object variable by casting it to a functional interface at the same time).

Lambda表达式不能直接分配给Object变量,因为Object不是一个函数接口。但是你可以把lambda赋值给一个函数接口变量,然后再把它赋值给Object变量(或者干脆把它赋值给一个Object变量,同时把它转换为一个函数接口)。

 

Q2. Explain the Difference Between Primitive and Reference Types.

Q2.解释原始类型和引用类型之间的区别

Reference types inherit from the top java.lang.Object class and are themselves inheritable (except final classes). Primitive types do not inherit and cannot be subclassed.

引用类型继承自顶层的java.lang.Object类,并且自身可以继承(final类除外)。原始类型不继承,也不能被子类化。

Primitively typed argument values are always passed via the stack, which means they are passed by value, not by reference. This has the following implication: changes made to a primitive argument value inside the method do not propagate to the actual argument value.

原始类型的参数值总是通过堆栈传递,这意味着它们是通过值传递的,而不是通过引用。这有如下含义:在方法内部对原始参数值的改变不会传播到实际参数值。

Primitive types are usually stored using the underlying hardware value types.

原始类型通常使用底层硬件值类型来存储。

For instance, to store an int value, a 32-bit memory cell can be used. Reference types introduce the overhead of object header which is present in every instance of a reference type.

例如,为了存储一个int值,可以使用一个32位内存单元。引用类型引入了对象头的开销,它存在于引用类型的每个实例中。

The size of an object header can be quite significant in relation to a simple numeric value size. This is why the primitive types were introduced in the first place — to save space on object overhead. The downside is that not everything in Java technically is an object — primitive values do not inherit from Object class.

相对于一个简单的数值大小,一个对象头的大小可能是相当重要的。这就是为什么一开始就引入了原始类型–以节省对象开销的空间。缺点是,从技术上讲,Java中并非所有东西都是对象–原始值不继承于Object类。

 

Q3. Describe the Different Primitive Types and the Amount of Memory They Occupy.

问题3 描述不同的原始类型和它们所占用的内存量

Java has 8 primitive types:

Java有8种原始类型。

  • boolean — logical true/false value. The size of boolean is not defined by the JVM specification and can vary in different implementations.
  • byte — signed 8-bit value,
  • short — signed 16-bit value,
  • char — unsigned 16-bit value,
  • int — signed 32-bit value,
  • long — signed 64-bit value,
  • float — 32-bit single precision floating point value corresponding to the IEEE 754 standard,
  • double — 64-bit double precision floating point value corresponding to the IEEE 754 standard.

 

Q4. What Is the Difference Between an Abstract Class and an Interface? What Are the Use Cases of One and the Other?

Q4.抽象类和接口之间的区别是什么?一个和另一个的用例是什么?

An abstract class is a class with the abstract modifier in its definition. It can’t be instantiated, but it can be subclassed. The interface is a type described with interface keyword. It also cannot be instantiated, but it can be implemented.

抽象类是一个,在其定义中带有抽象修饰符。它不能被实例化,但它可以被子类化。接口是一个用interface关键字描述的类型。它也不能被实例化,但它可以被实现。

The main difference between an abstract class and an interface is that a class can implement multiple interfaces, but extend only one abstract class.

抽象类和接口的主要区别在于,一个类可以实现多个接口,但只能扩展一个抽象类。

An abstract class is usually used as a base type in some class hierarchy, and it signifies the main intention of all classes that inherit from it.

一个抽象类通常被用作一些类层次结构中的基础类型,它标志着所有继承于它的类的主要意图。

An abstract class could also implement some basic methods needed in all subclasses. For instance, most map collections in JDK inherit from the AbstractMap class which implements many methods used by subclasses (such as the equals method).

一个抽象类也可以实现所有子类需要的一些基本方法。例如,JDK中的大多数地图集合都继承自AbstractMap类,该类实现了许多被子类使用的方法(例如equals方法)。

An interface specifies some contract that the class agrees to. An implemented interface may signify not only the main intention of the class but also some additional contracts.

一个接口指定了类所同意的一些契约。一个实现的接口不仅可以表示类的主要意图,还可以表示一些额外的契约。

For instance, if a class implements the Comparable interface, this means that instances of this class may be compared, whatever the main purpose of this class is.

例如,如果一个类实现了Comparable接口,这意味着这个类的实例可以被比较,不管这个类的主要目的是什么。

 

Q5. What Are the Restrictions on the Members (Fields and Methods) of an Interface Type?

Q5.对接口类型的成员(字段和方法)的限制是什么?

An interface can declare fields, but they are implicitly declared as public, static and final, even if you don’t specify those modifiers. Consequently, you can’t explicitly define an interface field as private. In essence, an interface may only have constant fields, not instance fields.

一个接口可以声明字段,但它们被隐含地声明为publicstaticfinal,即使你没有指定这些修饰语。因此,你不能明确地将一个接口字段定义为private。从本质上讲,一个接口只能有常量字段,而不是实例字段。

All methods of an interface are also implicitly public. They also can be either (implicitly) abstract, or default.

一个接口的所有方法也是隐含的public。它们也可以是(隐含的)抽象,或默认

 

Q6. What Is the Difference Between an Inner Class and a Static Nested Class?

Q6.内层类和静态嵌套类之间的区别是什么?

Simply put – a nested class is basically a class defined inside another class.

简单地说–嵌套类基本上是一个定义在另一个类里面的类。

Nested classes fall into two categories with very different properties. An inner class is a class that can’t be instantiated without instantiating the enclosing class first, i.e. any instance of an inner class is implicitly bound to some instance of the enclosing class.

嵌套类分为两类,具有非常不同的属性。内层类是一个不先实例化包围类就不能实例化的类,也就是说,内层类的任何实例都隐含地与包围类的某个实例绑定。

Here’s an example of an inner class – you can see that it can access the reference to the outer class instance in the form of OuterClass1.this construct:

下面是一个内层类的例子–你可以看到它可以以OuterClass1.this结构的形式访问对外层类实例的引用。

public class OuterClass1 {

    public class InnerClass {

        public OuterClass1 getOuterInstance() {
            return OuterClass1.this;
        }

    }

}

To instantiate such inner class, you need to have an instance of an outer class:

要实例化这样的内部类,你需要有一个外部类的实例。

OuterClass1 outerClass1 = new OuterClass1();
OuterClass1.InnerClass innerClass = outerClass1.new InnerClass();

Static nested class is quite different. Syntactically it is just a nested class with the static modifier in its definition.

静态嵌套类则完全不同。从语法上讲,它只是一个在定义中带有static修饰词的嵌套类。

In practice, it means that this class may be instantiated as any other class, without binding it to any instance of the enclosing class:

在实践中,它意味着这个类可以作为任何其他的类被实例化,而不需要把它与任何包围类的实例绑定。

public class OuterClass2 {

    public static class StaticNestedClass {
    }

}

To instantiate such class, you don’t need an instance of outer class:

要实例化这样的类,你不需要外部类的实例。

OuterClass2.StaticNestedClass staticNestedClass = new OuterClass2.StaticNestedClass();

 

Q7. Does Java Have Multiple Inheritance?

Q7.Java是否有多重继承?

Java does not support the multiple inheritance for classes, which means that a class can only inherit from a single superclass.

Java不支持类的多重继承,这意味着一个类只能继承于一个超类。

But you can implement multiple interfaces with a single class, and some of the methods of those interfaces may be defined as default and have an implementation. This allows you to have a safer way of mixing different functionality in a single class.

但是你可以用一个类实现多个接口,这些接口的一些方法可以被定义为default,并有一个实现。这允许你有一个更安全的方式,在一个类中混合不同的功能。

 

Q8. What Are the Wrapper Classes? What Is Autoboxing?

Q8.什么是包装器类?什么是Autoboxing?

For each of the eight primitive types in Java, there is a wrapper class that can be used to wrap a primitive value and use it like an object. Those classes are, correspondingly, Boolean, Byte, Short, Character, Integer, Float, Long, and Double. These wrappers can be useful, for instance, when you need to put a primitive value into a generic collection, which only accepts reference objects.

对于Java中的八种原始类型中的每一种,都有一个封装类,可用于封装原始值并像对象一样使用它。这些类分别是:BooleanByteShortCharacterIntegerFloatLongDouble>。这些封装器很有用,例如,当你需要将一个原始值放入一个只接受引用对象的通用集合中时。

List<Integer> list = new ArrayList<>();
list.add(new Integer(5));

To save the trouble of manually converting primitives back and forth, an automatic conversion known as autoboxing/auto unboxing is provided by the Java compiler.

为了省去手动来回转换基元的麻烦,Java编译器提供了一种被称为自动装箱/自动拆箱的自动转换。

List<Integer> list = new ArrayList<>();
list.add(5);
int value = list.get(0);

 

Q9. Describe the Difference Between equals() and ==

Q9.描述 equals() 和 ==之间的区别

The == operator allows you to compare two objects for “sameness” (i.e. that both variables refer to the same object in memory). It is important to remember that the new keyword always creates a new object which will not pass the == equality with any other object, even if they seem to have the same value:

==运算符允许你比较两个对象的 “同一性”(即两个变量在内存中都指向同一个对象)。重要的是要记住,new关键字总是创建一个新的对象,它不会通过==与任何其他对象的平等性,即使它们似乎有相同的值。

String string1 = new String("Hello");
String string2 = new String("Hello");

assertFalse(string1 == string2);

Also, the == operator allows to compare primitive values:

另外,==运算符允许比较原始值。

int i1 = 5;
int i2 = 5;

assertTrue(i1 == i2);

The equals() method is defined in the java.lang.Object class and is, therefore, available for any reference type. By default, it simply checks that the object is the same via the == operator. But it is usually overridden in subclasses to provide the specific semantics of comparison for a class.

equals()方法被定义在java.lang.Object类中,因此可用于任何引用类型。默认情况下,它只是通过==运算符检查对象是否相同。但是它通常在子类中被重载,以便为一个类提供特定的比较语义。

For instance, for String class this method checks if the strings contain the same characters:

例如,对于String类,该方法检查字符串是否包含相同的字符。

String string1 = new String("Hello");
String string2 = new String("Hello");

assertTrue(string1.equals(string2));

 

Q10. Suppose You Have a Variable That References an Instance of a Class Type. How Do You Check That an Object Is an Instance of This Class?

Q10.假设你有一个引用某类实例的变量 你如何检查一个对象是否是这个类的实例?

You cannot use instanceof keyword in this case because it only works if you provide the actual class name as a literal.

在这种情况下,你不能使用instanceof关键字,因为它只在你提供实际的类名作为字面意思时才起作用。

Thankfully, the Class class has a method isInstance that allows checking if an object is an instance of this class:

值得庆幸的是,Class类有一个方法isInstance,可以检查一个对象是否是这个类的实例。

Class<?> integerClass = new Integer(5).getClass();
assertTrue(integerClass.isInstance(new Integer(4)));

 

Q11. What Is an Anonymous Class? Describe Its Use Case.

Q11.什么是匿名类?描述一下它的使用情况

Anonymous class is a one-shot class that is defined in the same place where its instance is needed. This class is defined and instantiated in the same place, thus it does not need a name.

匿名类是一个一次性的类,它被定义在需要其实例的同一个地方。这个类的定义和实例化都在同一个地方,因此它不需要一个名字。

Before Java 8, you would often use an anonymous class to define the implementation of a single method interface, like Runnable. In Java 8, lambdas are used instead of single abstract method interfaces. But anonymous classes still have use cases, for example, when you need an instance of an interface with multiple methods or an instance of a class with some added features.

在Java 8之前,你经常使用匿名类来定义单一方法接口的实现,比如Runnable。在Java 8中,lambdas被用来代替单一的抽象方法接口。但匿名类仍然有用武之地,例如,当你需要一个有多个方法的接口的实例或一个有一些附加功能的类的实例时。

Here’s how you could create and populate a map:

下面是你如何创建和填充地图的方法。

Map<String, Integer> ages = new HashMap<String, Integer>(){{
    put("David", 30);
    put("John", 25);
    put("Mary", 29);
    put("Sophie", 22);
}};
Next »

Java Concurrency Interview Questions (+ Answers)

« Previous

Java Collections Interview Questions