JavaRush /Java Blog /Random-JA /Java開発者へのインタビューからの質問と回答の分析。パート15
Константин
レベル 36

Java開発者へのインタビューからの質問と回答の分析。パート15

Random-JA グループに公開済み
こんにちは、こんにちは!Java 開発者はどのくらい知っておく必要がありますか? この問題については長い間議論することもできますが、実際のところ、面接では理論に徹底的に駆り立てられることになります。仕事で使う機会のない知識分野であっても。 Java開発者へのインタビューからの質問と回答の分析。 パート 15 - 1あなたが初心者の場合、理論的な知識は非常に重要視されます。まだ経験も実績もありませんので、あとは知識ベースの強さを確認するだけです。今日は、Java 開発者にとって最も人気のある面接の質問を検討することで、まさにこの基盤を強化し続けます。飛んでみましょう!

Javaコア

9. Java における静的バインディングと動的バインディングの違いは何ですか?

静的ポリモーフィズムと動的ポリモーフィズムについては、 この記事の質問 18ですでに回答していますので、それを読むことをお勧めします。

10. インターフェイスでプライベート変数または保護された変数を使用することは可能ですか?

いいえ、あなたがすることはできません。これは、インターフェースを宣言すると、Java コンパイラーが自動的にpublic キーワードabstractキーワードをインターフェース メソッドの前に追加し、 public キーワードstaticキーワード、finalキーワードをデータ メンバーの前に追加するためです。実際には、privateまたはprotectedを追加すると競合が発生し、コンパイラはアクセス修飾子について「修飾子 '<選択された修飾子>' はここでは許可されていません」というメッセージを表示ます。インターフェイス内の変数? それを理解してみましょう:
  • public - このインターフェースにより、クライアントはオブジェクトと対話できるようになります。変数がパブリックでない場合、クライアントは変数にアクセスできません。
  • static - インターフェイス (またはそのオブジェクト) を作成できないため、変数は静的です。
  • Final - インターフェースは 100% の抽象化を達成するために使用されるため、変数は最終形式になります (変更されません)。

11. クラスローダーとは何ですか?また何に使用されますか?

クラスローダー- またはクラス ローダー - Java クラスのロードを提供します。より正確には、ロードはその子孫、つまり特定のクラスローダーによって保証されます。ClassLoader自体は抽象的です。.class ファイルがロードされるたびに (たとえば、対応するクラスのコンストラクターまたは静的メソッドを呼び出した後)、このアクションはClassLoaderクラスの子孫の 1 つによって実行されます。相続人には次の3種類があります。
  1. Bootstrap ClassLoaderは基本的なローダーであり、JVM レベルで実装され、JVM カーネルの一部でありネイティブ コードで記述されているため、ランタイム環境からのフィードバックがありません。このローダーは、他のすべての ClassLoader インスタンスの親として機能します。

    主に、JDK 内部クラス (通常は$JAVA_HOME/jre/libディレクトリにあるrt.jarおよびその他のコア ライブラリ) のロードを担当します。プラットフォームが異なれば、このクラス ローダーの実装も異なる場合があります。

  2. 拡張クラスローダーは、基本ローダー クラスの子孫である拡張ローダーです。標準 Java 基本クラスの拡張機能のロードを処理します。JDK 拡張機能ディレクトリ (通常は$JAVA_HOME/lib/extまたは java.ext.dirs システム プロパティに記載されているその他のディレクトリ) からロードされます (このオプションは拡張機能のロードを制御するために使用できます)。

  3. System ClassLoader は、JRE レベルで実装されたシステム ローダーで、すべてのアプリケーション レベルのクラスを JVM にロードします。クラス環境変数-classpathまたは-cpコマンド ライン オプションで見つかったファイルをロードします。

Java開発者へのインタビューからの質問と回答の分析。 パート15-2クラスローダーは Java ランタイムの一部です。JVM がクラスをリクエストすると、クラス ローダーはクラスを検索し、クラスの完全修飾名を使用してクラス定義をランタイムにロードしようとします。java.lang.ClassLoader.loadClass()メソッドは、実行時にクラス定義をロードします。完全名に基づいてクラスをロードしようとします。クラスがまだロードされていない場合は、リクエストを親クラス ローダーに委任します。このプロセスは再帰的に発生し、次のようになります。
  1. システム クラスローダーは、キャッシュ内でクラスを見つけようとします。

    • 1.1. クラスが見つかった場合、ロードは正常に完了します。

    • 1.2. クラスが見つからない場合、ロードは拡張クラスローダーに委任されます。

  2. 拡張クラスローダーは、独自のキャッシュ内でクラスを検索しようとします。

    • 2.1. クラスが見つかった場合は、正常に完了します。

    • 2.2. クラスが見つからない場合、ロードはブートストラップ クラスローダーに委任されます。

  3. ブートストラップ クラスローダーは、独自のキャッシュ内でクラスを検索しようとします。

    • 3.1. クラスが見つかった場合、ロードは正常に完了します。

    • 3.2. クラスが見つからない場合、基礎となるブートストラップ クラスローダーはそのクラスをロードしようとします。

  4. ロードしている場合:

    • 4.1. 成功 - クラスのロードが完了しました。

    • 4.2. 失敗すると、制御は拡張クラスローダーに移されます。

  5. 5. 拡張クラスローダーはクラスのロードを試みます。ロード中の場合は、次のようになります。

    • 5.1. 成功 - クラスのロードが完了しました。

    • 5.2. 失敗すると、制御はシステム クラスローダーに移されます。

  6. 6. システム クラスローダーはクラスのロードを試みます。ロード中の場合は、次のようになります。

    • 6.1. 成功 - クラスのロードが完了しました。

    • 6.2. 正常に通過しませんでした - 例外が生成されました - ClassNotFoundException。

クラスローダーのトピックは広大なため、無視すべきではありません。さらに詳しく知りたい場合は、この記事を読むことをお勧めします。長居せずに次に進みます。

12. 実行時データ領域とは何ですか?

ランタイム データ領域- JVM ランタイム データ領域。JVM は、プログラムの実行中に必要ないくつかのランタイム データ領域を定義します。それらの一部は、JVM の起動時に作成されます。その他はスレッドローカルであり、スレッドの作成時にのみ作成されます (スレッドが破棄されると破棄されます)。JVM ランタイム データ領域は次のようになります。 Java開発者へのインタビューからの質問と回答の分析。 パート 15 - 3
  • PC レジスタは各スレッドに対してローカルであり、スレッドが現在実行している JVM 命令のアドレスが含まれています。

  • JVM スタックは、ローカル変数および一時的な結果のストレージとして使用されるメモリ領域です。各スレッドには独自の個別のスタックがあります。スレッドが終了するとすぐに、このスタックも破棄されます。ヒープに対するスタックの利点はパフォーマンスですが、ストレージのスケールでは確かにヒープの方が有利であることは注目に値します。

  • ネイティブ メソッド スタック - ネイティブ (非 Java) メソッドを実行するための、JVM スタックと同様のデータ要素を格納するスレッドごとのデータ領域。

  • ヒープ - 実行時に作成されるオブジェクト、クラスのメタデータ、配列などを含むストアとしてすべてのスレッドによって使用されます。この領域は、JVM の起動時に作成され、シャットダウン時に破棄されます。

  • メソッド領域 - このランタイム領域はすべてのスレッドに共通であり、JVM の起動時に作成されます。ランタイム定数プールなどの各クラスの構造、コンストラクターとメソッドのコード、メソッド データなどを保存します。

13. 不変オブジェクトとは何ですか?

この記事のこの部分の質問 14 と 15 には、この質問に対する答えがすでにあるので、時間を無駄にせずに見てください。

14. String クラスの特別な点は何ですか?

分析の初めに、String の特定の機能について繰り返し説明しました(これについては別のセクションがありました)。次に、 Stringの機能を要約しましょう。
  1. これは Java で最も人気のあるオブジェクトであり、さまざまな目的に使用されます。使用頻度という点では原始型にも劣りません。

  2. このクラスのオブジェクトは、 new キーワードを使用せずに、引用符で直接作成できます。 String str = “string”;

  3. String不変クラスです。このクラスのオブジェクトを作成するとき、そのデータは変更できません (特定の文字列に +「別の文字列」を追加すると、結果として新しい 3 番目の文字列が得られます)。String クラスの不変性により、スレッド セーフになります。

  4. Stringクラスはファイナライズされている ( final修飾子がある) ため、継承できません。

  5. String には、作成した文字列値をキャッシュするヒープ内のメモリ領域である独自の文字列プールがあります。このシリーズのこのパート、質問 62 では、文字列プールについて説明しました。

  6. Java にはString の類似物、 StringBuilderStringBuffer という文字列を扱うように設計されたものがありますが、変更可能であるという違いがあります。詳細については、この記事を参照してください。

Java開発者へのインタビューからの質問と回答の分析。 パート 15 - 4

15. 型共分散とは何ですか?

共分散を理解するために、例を見てみましょう。動物クラスがあるとします。
public class Animal {
 void voice() {
   System.out.println("*тишина*");
 }
}
そしてそれを拡張するいくつかのDogクラス:
public class Dog extends Animal {

 @Override
 public void voice() {
   System.out.println("Гав, гав, гав!!!");
 }
}
覚えているように、継承型のオブジェクトを親型に簡単に割り当てることができます。
Animal animal = new Dog();
これは単なるポリモーフィズムにすぎません。便利で柔軟ですよね?さて、動物のリストはどうでしょうか?一般的なAnimalを含むリストにDogオブジェクトを含むリストを与えることはできますか?
List<Dog> dogs = new ArrayList<>();
List<Animal> animals = dogs;
この場合、犬のリストを動物のリストに割り当てる行には赤色の下線が引かれます。コンパイラはこのコードを渡しません。この割り当ては非常に論理的であるように見えますが (結局のところ、DogオブジェクトをAnimal型の変数に割り当てることができます)、それは実行できません。これは、それが許可されている場合、リストにはDogのみが含まれていると考えながら、本来Dogであることを意図していたリストにAnimalオブジェクトを含めることができるためです。そして、たとえば、get()メソッドを使用して、犬のリストからオブジェクトを取得し、それが犬であると考えて、そのオブジェクトに対してDogオブジェクトのメソッドを呼び出します。これは、 Animalにはありません。そして、ご理解のとおり、これは不可能です - エラーが発生します。しかし幸いなことに、コンパイラは、子孫のリストを親のリストに代入する際のこの論理エラーを見逃しません (またその逆も同様です)。Java では、一致するジェネリックを持つリスト変数にのみリスト オブジェクトを割り当てることができます。これを不変性といいます。もしこれができれば、それは共分散と呼ばれ、共分散と呼ばれます。つまり、共分散は、 ArrayList<Dog>型のオブジェクトをList<Animal>型の変数に設定できるかどうかです。Java では共分散がサポートされていないことがわかりましたか? たとえそれがどんなものであっても! しかし、これは独自の特別な方法で行われます。デザインは何に使用されますか? Animal を拡張します。これは、リスト オブジェクトを設定する変数のジェネリックとその子孫のジェネリックとともに配置されます。この一般的な構造は、 Animal型の子孫である任意の型が機能することを意味します( Animal型もこの一般化に当てはまります)。つまり、Animal はクラスであるだけでなく、インターフェイスにもなることができます ( extendsキーワードに騙されないでください)。前回の割り当ては次のように行うことができます。 Java開発者へのインタビューからの質問と回答の分析。 パート 15 - 5
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
その結果、IDE では、コンパイラーがこの構造に関して文句を言わないことがわかります。この設計の機能を確認してみましょう。渡されたすべての動物に音を鳴らすメソッドがあるとします。
public static void animalsVoice(List<? extends Animal> animals) {
 for (Animal animal : animals) {
   animal.voice();
 }
}
彼に犬のリストを渡してみましょう。
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());
dogs.add(new Dog());
dogs.add(new Dog());
animalsVoice(dogs);
コンソールに次の出力が表示されます。
ワンワンワン!!!ワンワンワン!!!ワンワンワン!!!
これは、共分散に対するこのアプローチがうまく機能することを意味します。このジェネリックがリストに含まれていることをお知らせします。Animal を拡張すると、どのタイプの新しいデータも挿入できません。DogタイプAnimalタイプでさえも挿入できません。
List<Dog> dogs = new ArrayList<>();
List<? extends Animal> animals = dogs;
animals.add(new Dog());
dogs.add(new Animal());
実際、最後の 2 行では、コンパイラはオブジェクトの挿入を赤色で強調表示します。これは、汎用の<?によって、どのタイプのオブジェクトのどのリストがデータを含むリストに割り当てられるのかを 100% 確信できないためです。Animal> を拡張しますまた、反変性Java開発者へのインタビューからの質問と回答の分析。 パート 15 - 6についてもお話したいと思います。通常、この概念は常に共変性と組み合わされており、原則として共変性についても一緒に尋ねられるからです。この構成では継承型を使用するため、この概念は共分散とはやや逆です。Dogオブジェクトの祖先ではないタイプ オブジェクトのリストを割り当てることができるリストが必要だとします。ただし、具体的にどのような種類になるかは事前にはわかりません。この場合、形式?の構造は次のようになります。super Dog 。すべてのタイプが適しています。Dogクラスの祖先です。
List<Animal> animals = new ArrayList<>();
List<? super Dog> dogs = animals;
dogs.add(new Dog());
dogs.add(new Dog());
いずれの場合も、その祖先の実装されたメソッドがすべて含まれているため、このようなジェネリックを使用して、型Dog のオブジェクトをリストに安全に追加できます。ただし、タイプAnimalのオブジェクトを追加することはできません。これは、内部にこのタイプのオブジェクトが存在し、たとえばDog ではないためです。結局のところ、このリストの要素から、AnimalにはないDogクラスのメソッドをリクエストできます。この場合、コンパイルエラーが発生します。また、前のメソッドを実装したい場合は、このジェネリックを使用します。
public static void animalsVoice(List<? super Dog> dogs) {
 for (Dog dog : dogs) {
   dog.voice();
 }
}
返されたリストにDog型のオブジェクトが含まれており、そのメソッドを自由に使用できるかどうかを確認できないため、forループ でコンパイル エラーが発生します。このリストでDogs.get(0)メソッドを呼び出すとします。- Object 型のオブジェクトを取得します。つまり、animalsVoice()メソッドが機能するには、少なくとも型データを絞り込む小さな操作を追加する必要があります。
public static void animalsVoice(List<? super Dog> dogs) {
 for (Object obj : dogs) {
   if (obj instanceof Dog) {
     Dog dog = (Dog) obj;
     dog.voice();
   }
 }
}
Java開発者へのインタビューからの質問と回答の分析。 パート 15 - 7

16. Object クラスにはどのようにメソッドがあるのですか?

このシリーズのこの部分の第 11 段落で、私はすでにこの質問に答えていますので、まだ読んでいない場合は読むことを強くお勧めします。今日はこれで終わります。次のパートでお会いしましょう! Java開発者へのインタビューからの質問と回答の分析。 パート 15 - 8
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION