1前書き

クラス構造と初期化は、すべてのJavaプログラマーが精通しているべき基本です。この記事はあなたが遭遇するかもしれないトピックに関するインタビューの質問のいくつかに対する答えを提供します。

** Q1. クラス、メソッド、フィールドまたはローカル変数に適用した場合の

final

キーワードの意味


final

キーワードは、さまざまな言語の構成要素に適用されると、複数の異なる意味を持ちます。


  • final

    クラスはサブクラス化できないクラスです


  • final

    メソッドはサブクラスでオーバーライドできないメソッドです


  • final

    フィールドは、フィールド内で初期化する必要があるフィールドです。

コンストラクタまたは初期化子ブロックであり、その後は変更できません
**

final

変数は代入することができる変数です(そして

一度だけ割り当てられ、その後は決して修正されない


Q2.

default

メソッドとは何ですか?

Java 8より前は、インタフェースは抽象メソッドしか持つことができませんでした。

体なしのメソッド。 Java 8以降、インタフェースメソッドはデフォルトの実装を持つことができます。実装クラスがこのメソッドをオーバーライドしない場合は、デフォルトの実装が使用されます。そのようなメソッドは

default

キーワードで適切にマークされています。


default

メソッドの主な使用例の1つは、既存のインタフェースにメソッドを追加することです。そのようなインターフェースメソッドを

default

としてマークしなければ、このインターフェースの既存の実装はすべて壊れます。

default

実装を持つメソッドを追加すると、レガシーコードとこのインタフェースの新しいバージョンとのバイナリ互換性が保証されます。

この良い例は、クラスをfor-eachループのターゲットにすることを可能にする

Iterator

インターフェースです。このインタフェースはJava 5で初めて登場しましたが、Java 8では2つの追加メソッド、

forEach

、および

spliterator

を受け取りました。それらは実装のデフォルトメソッドとして定義されているため、下位互換性を損なうことはありません。

public interface Iterable<T> {

    Iterator<T> iterator();

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

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


Q3.

static

クラスのメンバーとは何ですか?

クラスの静的フィールドおよびメソッドは、クラスの特定のインスタンスにバインドされていません。代わりに、それらはクラスオブジェクト自体にバインドされています。


static

メソッドの呼び出しや

static

フィールドのアドレス指定はコンパイル時に解決されます。インスタンスのメソッドやフィールドとは反対に、参照をたどって参照している実際のオブジェクトを決定する必要がないからです。


Q4. 抽象メンバーを持たないクラスが抽象として宣言されてもよいですか. そのようなクラスの目的は何ですか?

はい、クラスに

abstract

メンバーが含まれていなくても、クラスは

abstract

と宣言できます。抽象クラスとして、それをインスタンス化することはできませんが、それはある階層のルートオブジェクトとして機能することができ、その実装に役立つメソッドを提供します。


Q5. コンストラクタチェーンとは何ですか?

コンストラクタチェーンは、互いに順番に呼び出す複数のコンストラクタを提供することによってオブジェクトの構成を単純化する方法です。

最も具体的なコンストラクタはすべての可能な引数を取り、最も詳細なオブジェクト設定に使用できます。特定性の低いコンストラクタは、引数の一部にデフォルト値を指定することによって、より特定性の高いコンストラクタを呼び出すことができます。チェーンの先頭で、引数のないコンストラクタはデフォルト値でオブジェクトをインスタンス化することができます。

これは、一定の日数以内に利用可能なパーセントでの割引をモデル化するクラスを使った例です。引数のないコンストラクタを使用するときに指定しない場合は、デフォルト値の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. メソッドのオーバーライドとオーバーロードとは何ですか?それらはどう違いますか?

スーパークラスと同じシグネチャでメソッドを定義すると、メソッドのオーバーライドはサブクラスで行われます。これにより、ランタイムは、メソッドを呼び出す実際のオブジェクトタイプに応じてメソッドを選択できます。メソッド

toString



equals

、および

hashCode

は、サブクラスで頻繁にオーバーライドされます。

メソッドのオーバーロードは同じクラスで発生します。オーバーロードは、名前は同じだが引数の型や数が異なるメソッドを作成すると発生します。これにより、指定した引数の種類に応じて特定のコードを実行できますが、メソッドの名前は変わりません。

これが

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.

static

メソッドをオーバーライドできますか?

いいえ、できません。定義上、実行時に実際のインスタンスのタイプ(動的メソッド検索と呼ばれるプロセス)によって実装が決定されている場合にのみ、メソッドをオーバーライドできます。

static

メソッドの実装はコンパイル時に参照の型を使って決定されるため、オーバーライドしても意味がありません。スーパークラスとまったく同じシグネチャで

static

メソッドをサブクラスに追加できますが、これは技術的にオーバーライドされません。


Q8. 不変クラスとは何ですか?またどのように作成できますか?

不変クラスのインスタンスは、作成後に変更することはできません。

変更するとは、インスタンスのフィールドの値を変更して状態を変更することを意味します。不変クラスには多くの利点があります。それらはスレッドセーフであり、考慮しなければならない可変状態がない場合、それらについて推論する方がはるかに簡単です。

クラスを不変にするには、次のことを確認する必要があります。

  • すべてのフィールドは

    private



    final

    と宣言されるべきです。これは

それらはコンストラクタで初期化され、これまでに変更されてはいけません
から。
** クラスには、メソッドを変更するための設定メソッドや他のメソッドを含めないでください。

フィールドの値
** コンストラクタを介して渡されたクラスのすべてのフィールドは、どちらかになります。

不変であるか、またはその値がfieldの前にコピーされるべきです。
初期化(または、このクラスの状態を次のように変更することもできます。
これらの値を保持し、それらを修正する。
** クラスのメソッドはオーバーライドできません。すべての方法


final

にするか、コンストラクタを

private

にして

static

factoryメソッドを介してのみ呼び出す必要があります。


Q9.

equals()

または

==

の2つの

enum

値をどうやって比較しますか?

実際には、両方を使うことができます。

enum

値はオブジェクトなので、

equals()

と比較できますが、

static

定数として実装されているので、

==

と比較してもかまいません。

これは主にコードスタイルの問題ですが、文字スペースを節約したい(そしておそらく不要なメソッド呼び出しをスキップしたい)場合は、enumを

==

と比較する必要があります。


Q10. イニシャライザブロックとは何ですか?

static

イニシャライザブロックとは何ですか?

イニシャライザブロックは、インスタンスの作成中に実行されるクラススコープ内の中括弧で囲まれたコードブロックです。これを使用して、インプレース初期化ワンライナーよりも複雑なものでフィールドを初期化できます。

実際、コンパイラはこのブロックをすべてのコンストラクタ内にコピーするだけなので、すべてのコンストラクタから共通のコードを抽出するのに適した方法です。

静的初期化子ブロックは、その前に

static

修飾子がある中括弧付きのコードブロックです。クラスのロード中に1回実行され、静的フィールドの初期化や一部の副作用に使用できます。


Q11. マーカーインターフェースとはJavaのマーカーインタフェースの注目すべき例は何ですか?

マーカーインタフェースは、メソッドのないインタフェースです。通常はクラスによって実装されるか、特定のプロパティを表すために別のインタフェースによって拡張されます。標準のJavaライブラリで最も広く知られているマーカーインタフェースは次のとおりです。


  • Serializable

    は、このクラスが

シリアル化
**

Cloneable



clone

メソッドを使用してオブジェクトのクローンを作成できます


Cloneable

インタフェースが配置されている場合、このメソッドは

CloneNotSupportedException

);
**

Remote

はRMIで使用され、どのメソッドが可能かを示すインタフェースを指定します。

リモートで呼び出されます。

==== * Q12。シングルトンとは何ですか?またそれをJavaでどのように実装できますか?**

シングルトンはオブジェクト指向プログラミングのパターンです。シングルトンクラスは1つのインスタンスのみを持ち、通常はグローバルに表示されアクセス可能です。

Javaでシングルトンを作成する方法は複数あります。以下は、その場で初期化される

static

フィールドを持つ最も単純な例です。

static

フィールドはスレッドセーフな方法で初期化されることが保証されているため、初期化はスレッドセーフです。コンストラクタは

private

なので、外部コードがクラスの複数のインスタンスを作成することはできません。

public class SingletonExample {

    private static SingletonExample instance = new SingletonExample();

    private SingletonExample() {}

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

しかし、このアプローチには深刻な欠点があります。インスタンスは、このクラスが最初にアクセスされたときにインスタンス化されます。このクラスの初期化が重い操作であり、インスタンスが実際に必要になるまで(おそらく絶対に必要とされないまで)それを延期したいが、同時にそれをスレッドセーフにしておきます。この場合、

double-checked locking

と呼ばれる手法を使うべきです。

==== * Q13。 var-argとは何ですか? var-argに対する制限は何ですか?メソッド本体の中でどのように使えますか?**

Var-argはメソッドの可変長引数です。メソッドはvar-argを1つだけ持つことができ、それは引数のリストの最後に来なければなりません。これは、型名の後に省略符号と引数名を続けたものとして指定されます。メソッド本体の内部では、var-argが指定された型の配列として使用されています。

これは標準ライブラリの例です。コレクション、可変数の要素を受け取り、すべての要素をコレクションに追加する

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。スーパークラスのオーバーライドされたメソッドにアクセスできますか?同様の方法で、スーパースーパークラスのオーバーライドされたメソッドにアクセスできますか?**

スーパークラスのオーバーライドされたメソッドにアクセスするには、

super

キーワードを使用できます。しかし、スーパースーパークラスのオーバーライドされたメソッドにアクセスするための同様の方法はありません。

標準ライブラリの例として、

LinkedHashMap

クラスは

HashMap

を拡張し、その機能を再利用して、反復順序を維持するためにその値の上にリンクリストを追加します。

LinkedHashMap

は、そのスーパークラスの

clear

メソッドを再利用してから、リンクリストの先頭と末尾の参照を消去します。

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




  • «** 前へ