開発者ドキュメント

Java Type Systemのインタビューの質問


1前書き

Java Type Systemは、Java開発者のための技術面接でよく出てくるトピックです。この記事では、よく寄せられるいくつかの重要な質問について説明します。


2質問


Q1. 型階層における

Object

クラスの位置を説明します. どの型が

Object

を継承していますか. 配列は

Object

を継承しますか?ラムダ式をオブジェクト変数に代入できますか?


java.lang.Object

は、Javaのクラス階層の最上位にあります。すべてのクラスは、明示的、暗黙的(

extends

キーワードがクラス定義から省略されている場合)、または継承チェーンを介して推移的に継承されます。

ただし、

Object

から継承されない8つのプリミティブ型、つまり

boolean



byte



short



char



int



float



long

、および

double

があります。

Java言語仕様によると、配列もオブジェクトです。

それらは

Object

参照に代入することができ、すべての

Object

メソッドをそれらに対して呼び出すことができます。


Object

は機能的なインターフェイスではないため、ラムダ式を

Object

変数に直接代入することはできません。しかし、ラムダを機能インターフェース変数に割り当ててから、それを

Object

変数に割り当てることができます(または、それを機能インターフェースにキャストすることによって単にオブジェクト変数に割り当てることもできます)。


Q2. プリミティブ型と参照型の違いを説明する

参照型は最上位の

java.lang.Object

クラスから継承され、継承可能です(

final

クラスを除く)。プリミティブ型は継承せず、サブクラス化することもできません。

基本的に型指定された引数値は常にスタックを介して渡されます。つまり、参照ではなく値によって渡されます。これには次のような意味があります。メソッド内でプリミティブ引数値に加えられた変更は、実際の引数値には反映されません。

プリミティブ型は通常、基礎となるハードウェア値型を使用して格納されます。

例えば、

int

値を格納するために、32ビットメモリセルを使用することができます。

参照型は、参照型のすべてのインスタンスに存在するオブジェクトヘッダーのオーバーヘッドをもたらします。

オブジェクトヘッダーのサイズは、単純な数値のサイズに関連して非常に重要になります。オブジェクトオーバーヘッドのスペースを節約するために、プリミティブ型が最初に導入されたのはこのためです。欠点は、技術的にはJavaのすべてがオブジェクトではないことです。プリミティブ値は

Object

クラスから継承しません。


Q3. さまざまなプリミティブ型とそれらが占めるメモリの量を説明する

Javaには8つのプリミティブ型があります。


  • boolean

    – 論理

    true

    /

    false

    の値。ブールのサイズはではありません

JVM仕様で定義されており、実装によって異なります。


  • byte

    – 符号付き8ビット値


  • short

    – 符号付き16ビット値


  • char

    – 符号なし16ビット値


  • int

    – 符号付き32ビット値


  • long

    – 符号付き64ビット値


  • float

    – 対応する32ビット単精度浮動小数点値

IEEE 754規格に準拠
**

double

– 対応する64ビット倍精度浮動小数点値

IEEE 754規格に準拠しています。


Q4. 抽象クラスとインタフェースの違いは何ですか?一方と他方のユースケースは何ですか?

抽象クラスは、その定義に

abstract

修飾子を持つ

class

です。インスタンス化することはできませんが、サブクラス化することはできます。インターフェースは

interface

キーワードで記述された型です。インスタンス化することもできませんが、実装することはできます。

抽象クラスとインタフェースの主な違いは、クラスは複数のインタフェースを実装できますが、抽象クラスを1つだけ拡張できるという点です。


abstract

クラスは通常、あるクラス階層で基本型として使用され、それを継承するすべてのクラスの主な意図を表します。


abstract

クラスはすべてのサブクラスで必要とされるいくつかの基本的なメソッドを実装することもできます。たとえば、JDKのほとんどのマップコレクションは、サブクラスで使用される多くのメソッド(

equals

メソッドなど)を実装する

AbstractMap

クラスを継承しています。

インターフェースは、クラスが同意する何らかの規約を指定します。実装されたインターフェースは、クラスの主な意図だけでなく、いくつかの追加の契約も意味します。

たとえば、クラスが

Comparable

インタフェースを実装している場合、これは、このクラスの主な目的が何であれ、このクラスのインスタンスを比較できることを意味します。


Q5. インタフェース型のメンバ(フィールドとメソッド)に対する制限は何ですか?

インターフェースはフィールドを宣言できますが、修飾子を指定しなくても、

public



static

、および

final

として暗黙的に宣言されます。そのため、インターフェイスフィールドを

private

として明示的に定義することはできません。本質的に、インタフェースはインスタンスフィールドではなく定数フィールドのみを持つことができます。

インタフェースのすべてのメソッドも暗黙のうちに

public

です。それらは(暗黙のうちに)

abstract

または

default

のいずれかになることもできます。


Q6. 内部クラスと静的な入れ子クラスの違いは何ですか?

簡単に言えば、入れ子になったクラスは基本的に他のクラスの中で定義されたクラスです。

入れ子になったクラスは、性質がまったく異なる2つのカテゴリに分類されます。

内部クラスは、それを囲むクラスを最初にインスタンス化しないとインスタンス化できないクラスです。つまり、内部クラスのインスタンスは、それを囲むクラスのインスタンスに暗黙的にバインドされます。

これは内部クラスの例です –

OuterClass1.this

構文の形式で外部クラスインスタンスへの参照にアクセスできることがわかります。

public class OuterClass1 {

    public class InnerClass {

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

    }

}

そのような内部クラスをインスタンス化するには、外部クラスのインスタンスが必要です。

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

静的な入れ子クラスはかなり異なります。構文的には、定義内に

static

修飾子を持つネストしたクラスです。

実際には、このクラスは、それを包含するクラスのインスタンスにバインドせずに、他のクラスと同じようにインスタンス化することができます。

……
パブリッククラスOuterClass2 {

パブリックスタティッククラスStaticNestedClass {
    }

}
……

このようなクラスをインスタンス化するために、外部クラスのインスタンスは必要ありません。

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


Q7. Javaには多重継承がありますか?

Javaはクラスの多重継承をサポートしていません。つまり、クラスは単一のスーパークラスからしか継承できません。

しかし、単一のクラスで複数のインターフェースを実装することができ、それらのインターフェースのメソッドのいくつかは

default

として定義され、実装されているかもしれません。これにより、さまざまな機能を1つのクラスに安全に混在させることができます。


Q8. ラッパークラスとは何ですか?オートボクシングとは何ですか?

Javaの8つのプリミティブ型のそれぞれには、プリミティブ値をラップし、それをオブジェクトのように使用するために使用できるラッパークラスがあります。

これらのクラスは、それに対応して、

Boolean



Byte



Short



Character



Integer



Float



Long

、および

Double

です。これらのラッパーは、たとえば、参照オブジェクトのみを受け付けるジェネリックコレクションにプリミティブ値を入れる必要がある場合に便利です。

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

手動でプリミティブを前後に変換する手間を省くために、自動ボックス化/自動ボックス化解除として知られる自動変換がJavaコンパイラによって提供されています。

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


Q9. equals()と==

の違いを説明してください

モバイルバージョンを終了