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

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

Random-JA グループに公開済み
みなさん、またこんにちは!私たちはジュニア、ミドル、シニアの開発者向けの250 以上の質問に対する回答を引き続き探しています。質問は非常に興味深いもので、私自身もそれを分析するのが好きです。そのような瞬間に、理論的知識のギャップや、最も予期しない場所でギャップを発見することができます。前の部分はこの記事にインタビューの質問と回答の分析。 パート 2 - 1あります。しかし、始める前に、次のことを思い出していただきたいと思います。
  1. 情報が再度重複しないように、この一連の記事に関連する質問は省略します。これらの資料には、Java Core の面接で最も一般的な (よくある) 質問が含まれているため、これらの資料を読むことをお勧めします。
  2. DOU に関する質問はウクライナ語で行われますが、ここではすべてロシア語で答えます。
  3. 答えをもっと詳しく説明することもできますが、各質問に対する答えを書くと記事全体が書けてしまう可能性があるため、ここでは書きません。そして、面接ではそこまで詳しく聞かれることはありません。
必要に応じて、より深い研究のためにリンクを残します。飛んでみましょう!

11. Object クラスのすべてのメソッドに名前を付けます

Object クラスには 11 のメソッドがあります。
  • Class<?> getClass() — 現在のオブジェクトのクラスを取得します。
  • int hashCode() — 現在のオブジェクトのハッシュ コードを取得します。
  • booleanquals (Object obj) - 現在のオブジェクトと別のオブジェクトの比較。
  • Object clone() - 現在のオブジェクトのコピーを作成して返します。
  • String toString() — オブジェクトの文字列表現を取得します。
  • void Notice() - このオブジェクトのモニターで待機している 1 つのスレッドを起動します (スレッドの選択はランダムです)。
  • void NoticeAll() - このオブジェクトのモニターを待機しているすべてのスレッドを起動します。
  • void wait() - 現在のモニター上で現在のスレッドをスタンバイ モード (フリーズ) に切り替えます。何らかの Notice または NotifyAll がスレッドをウェイクアップするまで、同期ブロック内でのみ動作します。
  • void wait(long timeout) - 現在のモニター (現在同期されているモニター) 上の現在のスレッドもフリーズしますが、この状態を終了するためのタイマーを使用します (または、再度、notify または NoticeAll がウェイクアップするまで)。
  • void wait(long timeout, int nanos) - 上で説明したメソッドと似ていますが、フリーズを終了するためのより正確なタイマーが使用されます。
  • void Finalize() - このオブジェクトを削除する前に、ガベージ コレクターはこのメソッドを (最後に) 呼び出します。占有されているリソースをクリーンアップするために使用されます。
hashCodeequals clonetoString 、および Finalize メソッドを正しく使用するには、現在のタスクと状況を考慮して再定義する必要があります。

12. リソースを扱う場合の try-with-resources と try-catch-finally の違いは何ですか?

通常、try-catch-finally を使用する場合、最後のブロックはリソースを閉じるために使用されます。Java 7 では、新しいタイプの演算子try-with-resourcesが導入されました。これは、リソースを解放するためのtry-catch-finallyに似ていますが、よりコンパクトで読みやすくなっています。try-catch-finally がどのようなものかを思い出してみましょう。
String text = "some text......";
BufferedWriter bufferedWriter = null;
try {
   bufferedWriter = new BufferedWriter(new FileWriter("someFileName"));
   bufferedWriter.write(text);
} catch (IOException e) {
   e.printStackTrace();
} finally {
   try {
       bufferedWriter.close();
   } catch (IOException e) {
       e.printStackTrace();
   }
}
次に、 try-with-resources を使用してこのコードを書き直してみましょう。
String text = "some text......";
try(BufferedWriter bufferedWriter =new BufferedWriter(new FileWriter("someFileName"))) {
   bufferedWriter.write(text);
} catch (IOException e) {
   e.printStackTrace();
}
なんだか楽になってきましたね。簡略化に加えて、いくつかのポイントがあります。
  1. try-with-resourcesでは、括弧内で宣言されたリソース (閉じられる) は、 AutoCloseable インターフェースとその唯一のメソッドclose()を実装する必要があります。

    closeメソッドは暗黙的なfinallyブロックで実行されます。そうでない場合、プログラムはどのようにして特定のリソースを閉じる方法を正確に理解するのでしょうか?

    ただし、リソースの実装とその終了メソッドを独自に作成することはほとんどないでしょう。

  2. ブロック実行のシーケンス:

    1. ブロックを試してください
    2. 最後に暗黙的に。
    3. 前のステップで例外をキャッチするcatchブロック。
    4. 最後に明示的に。

    原則として、リストの下位にある例外は上位にある例外を中断します。

try-catch-finallyを使用するときにtryで例外が発生する状況を想像してください。したがって、特定のcatchブロックがすぐに実行を開始し、そこで別の例外 (たとえば、エラーをより詳細に説明するメッセージを含む) を記述し、メソッドでこの例外をさらにスローするようにしたいとします。次に、 finallyブロックが実行され、そこでも例外がスローされます。しかし、これは違います。このメソッドは最終的にこれら 2 つの例外のうちどちらをスローしますか? Finallyブロックによって例外がスローされました。ただし、 try-with-resourcesにもポイントが 1 つあります。次に、同じ状況でのtry-with-resourcesの動作を見てみましょう。close()メソッド、つまり暗黙的なfinallyでリソースをクローズしようとすると、 tryブロックで例外が発生します。これらの例外のうちどれがキャッチされますか? tryブロックによって投げられたものです。暗黙的なfinallyclose()メソッドから)からの例外は無視されます。この無視は例外抑制とも呼ばれます。

13. ビット演算とは何ですか?

ビット単位の演算は、論理演算とビット単位のシフトを含むビット文字列に対する演算です。 論理演算:
  • ビットごとのAND - ビット値を比較し、その過程で 0 (偽) に設定されたビットは、結果の対応するビットを 0 に設定します。つまり、比較される両方の値でビットが 1 (真) であった場合、結果も1になります。

    - AND&として表されます

    例: 10111101 & 01100111 = 00100101

  • ビット単位のOR は、前の演算の逆の演算です。1 に設定されたビットは、結果内の同様のビットを 1 に設定します。したがって、両方の比較値でビットが 0 だった場合、結果のビットも 0 になります。

    - OR|として表されます。

    例: 10100101 | 01100011 = 11100111

  • bitwise NOT - 1 つの値に適用され、ビットを反転 (反転) します。つまり、1 だったビットは 0 になります。そして0だったものは1になります。

    - NOT~として表されます

    例: ~10100101 = 01011010

  • ビット 単位の排他的 OR - ビット値を比較し、両方の値のビットが 1 に等しい場合、結果は 0 になり、両方の値のビットが 0 の場合、結果は 0 になります。結果が 1 になるには、ビットのうちの 1 つだけが 1 に等しく、2 番目のビットが 0 に等しくなる必要があります。

    - XOR^として示されます。

    例: 10100101 ^ 01100011 = 11000110

ビット単位のシフト- >>または<< は、値のビットを指定された方向に、指定された数だけシフトします。空いた位置はゼロで埋められます。例えば:
  1. 01100011 >> 4 = 00000110
  2. 01100011 << 3 = 00011000
負の数値を右シフトする場合にも例外があります。覚えているとおり、最初のビットは符号を担当し、このビットが 1 に等しい場合、その数値は負になります。負の数値を移動すると、符号ビットを維持する必要があるため、空いた位置は 0 ではなく 1 で埋められます。例: 10100010 >> 2 = 11101000 同時に、Java には追加の符号なし右シフト演算子 >>> が存在します。この演算子は >> に似ており、シフトの際には、空いた位置は 0 で埋められます。数値は負か正です。例: 10100010 >>> 2 = 00101000 ビット単位の演算の詳細については、こちらをご覧ください。インタビューの質問と回答の分析。 パート 2 - 2Java でのビット単位のシフトの使用例として、 HashMap のhash()メソッドを挙げることができます。このメソッドは、キーの特別な内部ハッシュ コードを決定するために使用されます。このメソッドを使用すると、インタビューの質問と回答の分析。 パート 2 ~ 3HashMap 内のデータを均等に分散して、データを最小限に抑えることができます。衝突の数。

14. Java のオブジェクトとなる標準の不変クラスは何ですか?

Immutableは、元のパラメータの変更を許可しないオブジェクトです。変更したいパラメータを含む、指定されたタイプの新しいオブジェクトを返すメソッドが含まれる場合があります。いくつかの標準的な不変オブジェクト:
  • Java で最も有名な不変オブジェクトは String です。
  • 標準型をラップするラッパー クラスのインスタンス: Boolean、Character、Byte、Short、Integer、Long、Double、Float。
  • 通常、特に大きな数値に使用されるオブジェクト - BigInteger と BigDecimal。
  • スタックトレース (例外スタックトレースなど) の単位であるオブジェクト StackTraceElement。
  • File クラスのオブジェクト - ファイルを変更できますが、同時にそれ自体は不変です。
  • UUID - 要素の一意の ID としてよく使用されます。
  • java.time パッケージのすべてのクラス オブジェクト。
  • ロケール - 地理的、政治的、または文化的地域を定義するために使用されます。

15. 通常のオブジェクトに対する不変オブジェクトの利点は何ですか?

  1. このようなオブジェクトは、マルチスレッド環境で使用しても安全です。これらを使用すると、スレッドの競合状態によるデータの損失を心配する必要がなくなります。通常のオブジェクトを操作する場合とは異なり、この場合は慎重に検討し、並列環境でオブジェクトを使用するためのメカニズムを考案する必要があります。
  2. 不変オブジェクトはマップ内で適切なキーです。なぜなら、可変オブジェクトを使用した後にオブジェクトの状態が変化すると、HashMap を使用するときに混乱が生じる可能性があるからです。オブジェクトはまだ存在しますが、containsKey()を使用すると存在しない可能性があります。見つけられた。
  3. 不変オブジェクトは、プログラムの実行中に決して変更すべきではない不変 (定数) データを格納するのに最適です。
  4. 「失敗に対する原子性」 - 不変オブジェクトが例外をスローした場合でも、望ましくない (壊れた) 状態に留まりません。
  5. これらのクラスはテストが簡単です。
  6. コピー コンストラクターやクローン実装などの追加のメカニズムは必要ありません。

OOPに関する質問

インタビューの質問と回答の分析。 パート 2 ~ 4

16. 手続き型プログラミングと比較した場合、OOP には一般的にどのような利点がありますか?

OOP の利点は次のとおりです。
  1. 複雑なアプリケーションは手続き型プログラミングよりも簡単に作成できます。すべてが小さなモジュール (相互作用するオブジェクト) に分割され、その結果、プログラミングはオブジェクト間の関係に帰着するからです。
  2. OOP を使用して作成されたアプリケーションは、(設計概念に従っている限り) 変更がはるかに簡単です。
  3. データとその操作は単一のエンティティを形成するため、アプリケーション全体に散らばることはありません (手続き型プログラミングではよく起こります)。
  4. 情報のカプセル化により、最も重要なデータがユーザーから保護されます。
  5. クラスを使用すると、それぞれが独自の属性値を持つ多数のオブジェクトを作成できるため、同じコードを異なるデータで再利用することができます。
  6. 継承とポリモーフィズムにより、(同様の機能を複製する代わりに) 既存のコードを再利用および拡張することもできます。
  7. 手続き型アプローチよりもアプリケーションの拡張が簡単です。
  8. OOP アプローチにより、実装の詳細を抽象化することができます。

17. OOP の欠点を教えてください

残念ながら、次のようなものも存在します。
  1. OOP では、何かを書く前に習得する必要のある多くの理論的知識が必要です。インタビューの質問と回答の分析。 パート 2 ~ 5
  2. OOP の考え方は、理解して実際に適用するのはそれほど簡単ではありません (ある程度の哲学者である必要があります)。
  3. OOP を使用すると、システムの構成がより複雑になるため、ソフトウェアのパフォーマンスがわずかに低下します。
  4. OOP アプローチでは、すべてがクラス、インターフェイス、メソッドで構成され、通常の変数よりも多くのメモリを消費するため、より多くのメモリが必要になります。
  5. 初期分析に必要な時間は、手順分析に比べて長くなります。

18. 静的および動的ポリモーフィズムとは何ですか

ポリモーフィズムにより、オブジェクトは同じクラスまたはインターフェイスに対して異なる動作を行うことができます。多型には 2 つのタイプがあり、早期バインディングおよび後期バインディングとも呼ばれます。 静的多態性、または以前のバインディング:
  • コンパイル時 (プログラムのライフサイクルの初期) に発生します。
  • コンパイル時にどのメソッドを実行するかを決定します。
  • メソッドのオーバーロードは静的多態性の一例です。
  • 早期バインディングには、プライベート、静的、および端末メソッドが含まれます。
  • 継承は早期バインディングには関与しません。
  • 静的多相性には、特定のオブジェクトが関係するのではなく、クラスに関する情報が関係します。クラスの型は変数名の左側に表されます。
動的多態性、または遅延バインディング:
  • 実行時 (プログラムの実行中) に発生します。
  • 動的ポリモーフィズムは、メソッドが実行時にどのような特定の実装を持つかを決定します。
  • メソッドのオーバーライドは動的多態性の一例です。
  • 遅延バインディングは、特定のオブジェクト、その型の参照、またはそのスーパークラスの割り当てです。
  • 継承は動的ポリモーフィズムに関連しています。
早期バインディングと遅延バインディングの違いについて詳しくは、この記事をご覧ください。

19. OOP における抽象化の原理を定義する

OOP の抽象化は、重要でない詳細を除外して、オブジェクトの一連の重要な特性を強調表示する方法です。つまり、OOP アプローチでプログラムを設計するときは、実装の詳細を深く掘り下げることなく、モデル全般に焦点を当てます。Java では、インターフェイスが抽象化を担当します。たとえば、マシンがあって、これがインターフェースになります。そして、それとのさまざまなインタラクション (たとえば、エンジンの始動、ギアボックスの使用) は、実装の詳細には触れずに使用する機能です。結局のところ、車を運転している瞬間には、ギアボックスがどのようにその目的を正確に果たすか、キーがどのようにエンジンを始動させるか、またはステアリングホイールがどのように車輪を回転させるかを正確に考えません。また、この機能の 1 つの実装 (たとえば、エンジン) が置き換えられたとしても、それに気付かない可能性があります。これはあなたには関係ありません。実装の詳細には立ち入りません。あなたにとって、その行動が実行されることが重要です。実際、これは実装の詳細からの抽象化です。今日はここで終わります。続きます。インタビューの質問と回答の分析。 パート 2 ~ 6
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION