こんにちは!知識は力である。最初の面接の前に知識が増えれば増えるほど、自信を持って面接に臨むことができます。 十分な知識があれば、混乱することは難しくなり、同時に面接官を驚かせることができるでしょう。したがって、今日は、これ以上苦労することなく、 Java 開発者向けの 250 以上の質問を検討することで理論的基礎を強化していきます。
103. 継承における例外をチェックするためのルールは何ですか?
私の質問が正しく理解できれば、継承時に例外を処理するためのルールについて尋ねていることになります。そのルールは次のとおりです。- 子孫/実装でオーバーライドまたは実装されたメソッドは、スーパークラス/インターフェイス メソッドの例外よりも上位の階層にあるチェック例外をスローできません。
public interface Animal {
void voice() throws IOException;
}
このインターフェイスの実装では、より一般的なスロー例外 (たとえば、Exception、Throwable ) をスローすることはできませんが、それをFileNotFoundExceptionなどの子孫例外に置き換えることはできます。
public class Cat implements Animal {
@Override
public void voice() throws FileNotFoundException {
// некоторая реализация
}
}
- サブクラス コンストラクターは、そのthrowsブロックに、オブジェクトの作成時に呼び出されるスーパークラス コンストラクターによってスローされるすべての例外クラスを含める必要があります。
public class Animal {
public Animal() throws ArithmeticException, NullPointerException, IOException {
}
次に、クラス継承者もコンストラクター内でそれらを指定する必要があります。
public class Cat extends Animal {
public Cat() throws ArithmeticException, NullPointerException, IOException {
super();
}
または、メソッドの場合と同様に、同じ例外ではなく、より一般的な例外を指定することもできます。私たちの場合、より一般的な例外 - Exceptionを指定するだけで十分です。これは、考慮される 3 つの例外すべての共通の祖先であるためです。
public class Cat extends Animal {
public Cat() throws Exception {
super();
}
104.finally ブロックが実行されない場合のコードを書いていただけますか?
まず、 finallyとは何かを思い出しましょう。前回は、例外をキャッチするメカニズムについて説明しました。tryブロックはキャッチ領域の概要を示し、catchブロックは特定の例外がスローされたときに機能するコードです。 Final は、 finally の後の 3 番目のコード ブロックで、catchと互換性がありますが、相互に排他的ではありません。このブロックの本質は、 tryまたはcatchの結果に関係なく(例外がスローされたかどうかに関係なく)、ブロック内のコードが常に機能することです。故障するケースは非常にまれであり、異常です。最も単純な失敗のケースは、上記のコードでSystem.exit(0)メソッドが呼び出され、プログラムが終了 (消滅) する場合です。try {
throw new IOException();
} catch (IOException e) {
System.exit(0);
} finally {
System.out.println("Данное сообщение не будет выведенно в консоль");
}
他にも、 finally が機能しない 状況がいくつかあります。
- 重大なシステムの問題、またはアプリケーションを「クラッシュ」させる何らかのエラーが原因で発生するプログラムの異常終了 (エラーの例としては、スタック メモリがオーバーフローしたときに発生するStackOwerflowErrorが考えられます)。
- デーモンスレッドがry...finallyブロックを通過すると、これと並行してプログラムが終了します。結局のところ、デーモンスレッドはバックグラウンド アクション用のスレッドです。つまり、デーモン スレッドは優先順位や必須ではなく、アプリケーションは作業が完了するのを待ちません。
- tryまたはcatchでの最も一般的な無限ループは、一度ループするとフローが永久にそこに留まります。
try { while (true) { } } finally { System.out.println("Данное сообщение не будет выведенно в консоль"); }
105. 1 つの catch ブロックで複数の例外を処理する例を書く
1) おそらく質問の仕方が間違っていたのでしょう。 私が理解している限り、この質問は1 つのtryブロックに対する複数のcatchを指します。try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
System.out.print("Упс, у вас упало исключение - " + e);
} catch (IOException e) {
System.out.print("Упс, у вас упало исключение - " + e);
} catch (Exception e) {
System.out.print("Упс, у вас упало исключение - " + e);
}
tryブロック で例外が発生した場合、catchブロックは上から下に交互に例外をキャッチしようとします。特定のcatchブロックが成功すると、例外を処理する権利が得られますが、その下にある残りのブロックは処理されなくなります。それをキャッチし、独自の方法で処理しようとすることができます。したがって、より狭い例外はcatchブロック チェーンの上位に配置され、より広範な例外は下位に配置されます。たとえば、最初のcatchブロックでExceptionクラスの例外がcatch された場合、チェックされた例外は残りのブロックに入ることができなくなります ( Exception の子孫を持つ残りのブロックはまったく役に立ちません)。 2) 質問が正しく行われた 場合、処理は次のようになります。
try {
throw new NullPointerException();
} catch (Exception e) {
if (e instanceof FileNotFoundException) {
// некоторая обработка с сужением типа (FileNotFoundException)e
} else if (e instanceof ArithmeticException) {
// некоторая обработка с сужением типа (ArithmeticException)e
} else if(e instanceof NullPointerException) {
// некоторая обработка с сужением типа (NullPointerException)e
}
catch で例外をキャッチしたら、 instanceofメソッドでその特定の型を見つけようとします。このメソッドは、オブジェクトが特定の型に属しているかどうかを確認するために使用されます。これにより、後で悪影響を及ぼさずにこの型に絞り込むことができます。考慮された両方のアプローチは同じ状況で使用できますが、2 番目のオプションが良いとは言えず、実際に見たことがないため、質問は間違っていると言いましたが、同時にマルチキャッチを使用した最初の方法は広く受け入れられています注意が広がっています。
106. 強制的に例外をスローできる演算子はどれですか? 例を書いてください
上記ですでに何度か使用していますが、それでもこのキーワードthrowを繰り返します。使用例 (例外を強制する):throw new NullPointerException();
107. main メソッドは throws 例外をスローできますか? その場合、どこに転送されますか?
まず第一に、main は通常のメソッドにすぎず、プログラムの実行を開始するために仮想マシンによって呼び出されることに注意してください。これに加えて、他のコードからも呼び出すことができます。つまり、throwsの後にチェック例外を指定するための通常の規則も適用されます。public static void main(String[] args) throws IOException {
したがって、例外も発生する可能性があります。mainが何らかのメソッドで呼び出されず、プログラムの起動ポイントとして開始された場合、 main によってスローされた例外は.UncaughtExceptionHandlerインターセプタによって処理されます。このハンドラーはスレッドごとに 1 つです (つまり、各スレッドに 1 つのハンドラー)。必要に応じて、独自のハンドラーを作成し、 Threadオブジェクトで呼び出されるsetDefaultUncaughtExceptionHandlerメソッドを使用して設定できます。
マルチスレッド化
108. マルチスレッドを扱うためのツールを知っていますか?
Java でマルチスレッドを使用するための基本/基本ツール:- Synchronized は、スレッドがメソッド/ブロックに入ったときに、他のスレッドからメソッド/ブロックを閉じる (ブロックする) メカニズムです。
- Volatile は、さまざまなスレッドによる変数への一貫したアクセスを保証するためのメカニズムです。つまり、変数にこの修飾子が存在する場合、すべての代入および読み取り操作はアトミックである必要があります。つまり、スレッドはこの変数をローカル メモリにコピーして変更するのではなく、元の値を変更します。
- Runnableは、特定のクラスで実装できるインターフェイス (特に、その run メソッド) です。
public class CustomRunnable implements Runnable {
@Override
public void run() {
// некоторая логика
}
}
このクラスのオブジェクトを作成したら、このオブジェクトを新しいThreadオブジェクトのコンストラクターに設定し、そのstart()メソッドを呼び出すことで、 新しいスレッドを開始できます。
Runnable runnable = new CustomRunnable();
new Thread(runnable).start();
start メソッドは、実装されたrun()メソッドを別のスレッドで実行します。
- Threadはクラスであり、( runメソッドをオーバーライドしながら) 以下のものを継承します。
public class CustomThread extends Thread {
@Override
public void run() {
// некоторая логика
}
}
そして、このクラスのオブジェクトを作成し、start()メソッドを使用して起動することで、新しいスレッドを起動します。
new CustomThread().start();
- Concurrencyは、マルチスレッド環境で作業するためのツールを備えたパッケージです。
- 同時コレクション- マルチスレッド環境での作業に特化したコレクションのセット。
- キュー- マルチスレッド環境に特化したキュー (ブロッキングおよびノンブロッキング)。
- シンクロナイザーは、マルチスレッド環境で作業するための特殊なユーティリティです。
- エグゼキュータは、スレッド プールを作成するためのメカニズムです。
- ロック- スレッド同期メカニズム (標準のものより柔軟です - synchronized、wait、notify、notifyAll)。
- アトミックはマルチスレッド実行用に最適化されたクラスであり、各操作はアトミックです。
109. スレッド間の同期について話します。wait()、notify()、notifyAll()、join() メソッドは何に使用されますか?
私が質問を理解している限り、スレッド間の同期はキー修飾子 - synchronizedに関するものです。このモディファイアは、ブロックのすぐ隣に配置できます。synchronized (Main.class) {
// некоторая логика
}
または、メソッド シグネチャ内で直接次のように指定します。
public synchronized void move() {
// некоторая логика}
前に述べたように、同期は、1 つのスレッドがすでにブロック/メソッドに入っているときに、他のスレッドからブロック/メソッドを閉じることができるメカニズムです。ブロック/メソッドを部屋として考えてください。あるストリームは部屋に来て部屋に入り鍵を閉めますが、他のストリームは部屋に来て部屋が閉まっているのを見て、部屋が空くまでその近くで待ちます。用事を済ませた最初のスレッドはルームを出てキーを解放します。そして、私が鍵について常に話してきたのは無駄ではありませんでした。なぜなら、それは実際に存在するからです。これはビジー/フリー状態を持つ特別なオブジェクトです。このオブジェクトはすべての Java オブジェクトにアタッチされるため、同期ブロックを使用する場合は、ドアを閉じるミューテックスを持つオブジェクトを括弧内に示す必要があります。
Cat cat = new Cat();
synchronized (cat) {
// некоторая логика
}
最初の例 ( Main.class ) で行ったように、クラス ミューテックスを使用することもできます。メソッドでsynchronized を使用するとき、閉じたいオブジェクトを指定しませんよね? この場合、非静的メソッドの場合、メソッドはthis object 、つまりこのクラスの現在のオブジェクトのミューテックスで閉じます。静的なものは、現在のクラスのミューテックスで閉じます ( this.getClass(); )。ミューテックスについて詳しくは、こちらをご覧ください。同期については、こちらをお読みください。 Wait()は、現在のモニター (アンカーのようなもの) に接続されているかのように、ミューテックスを解放し、現在のスレッドをスタンバイ モードにするメソッドです。このため、このメソッドは同期されたブロックまたはメソッドからのみ呼び出すことができます (それ以外の場合、何を解放し、何を期待する必要があります)。これはObjectクラスのメソッドであることにも注意してください。より正確には、1 つではなく 3 つでも構いません。
-
Wait() - 別のスレッドがこのオブジェクトのNotice()メソッドまたはNotifyAll()メソッドを呼び出すまで、現在のスレッドを待機モードにします(これらのメソッドについては後で説明します)。
-
待機 (長いタイムアウト) - 別のスレッドがこのオブジェクトのNotice()メソッドまたはNotifyAll()メソッドを呼び出すか、指定されたタイムアウトが期限切れになるまで、現在のスレッドを待機モードにします。
-
待機 (長いタイムアウト、int ナノ) - 前のものと同様に、ナノ秒のみを指定できます (より正確な時間設定)。
-
Notify()は、現在の同期ブロックの 1 つのランダムなスレッドを起動できるようにするメソッドです。繰り返しますが、これは同期されたブロックまたはメソッド内でのみ呼び出すことができます(結局のところ、他の場所ではフリーズを解除する人がいません)。
-
NotifyAll() は、現在のモニター上で待機しているすべてのスレッドを起動するメソッドです (同期されたブロックまたはメソッドでのみ使用されます)。
110. 流れを止めるにはどうすればよいですか?
まず最初に言っておきたいのは、run()メソッドが完全に実行されると、スレッドは自動的に破棄されるということです。ただし、この方法が完了する前に、予定より早く彼を殺す必要がある場合があります。それでは何をすべきでしょうか?おそらく、 Threadオブジェクトにはstop()メソッドが必要なのでしょうか。たとえそれがどんなものであっても!この方法は時代遅れであると考えられており、システムクラッシュを引き起こす可能性があります。 さて、それではどうでしょうか?これを行うには 2 つの方法があります。 1 つ目は、内部ブール フラグを使用する方法です。例を見てみましょう。完全に停止するまで画面上に特定の語句を表示するスレッドを独自に実装しました。public class CustomThread extends Thread {
private boolean isActive;
public CustomThread() {
this.isActive = true;
}
@Override
public void run() {
{
while (isActive) {
System.out.println("Поток выполняет некую логику...");
}
System.out.println("Поток остановлен!");
}
}
public void stopRunningThread() {
isActive = false;
}
}
stopRunning()メソッド を使用すると、内部フラグが false になり、runメソッドの実行が停止します。mainで実行しましょう:
System.out.println("Начало выполнения программы");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// пока наш основной поток спит, вспомогательный CustomThread работает и выводит в коноль своё сообщение
thread.stopRunningThread();
System.out.println("Конец выполнения программы");
その結果、コンソールに次のような内容が表示されます。
プログラム実行の開始 スレッドはいくつかのロジックを実行しています... スレッドはいくつかのロジックを実行しています... スレッドはいくつかのロジックを実行しています... スレッドはいくつかのロジックを実行しています... スレッドはいくつかのロジックを実行しています...スレッドは何らかのロジックを実行しています... プログラムの実行の終了 スレッドは停止しました。
これは、スレッドが機能し、一定数のメッセージをコンソールに出力し、正常に停止されたことを意味します。出力されるメッセージの数は実行ごとに異なり、場合によっては追加のスレッドが何も出力しないこともあります。私が気づいたように、これはメインスレッドのスリープ時間に依存し、時間が長いほど、追加のスレッドが何も出力しない可能性が低くなります。スリープ時間を 1ms にするとメッセージはほとんど出力されなくなりますが、20ms に設定するとほぼ動作します。おそらく、時間が短い場合、スレッドは単に起動して作業を開始する時間がなく、すぐに停止されます。 2 番目の方法は、 ThreadオブジェクトでInterrupted()メソッドを使用することです。このメソッドは、内部割り込みフラグ (このフラグはデフォルトではfalse です) の値を返し、もう 1 つのInterrupt()メソッドは、このフラグを true に設定します (これが発生した場合)。フラグがtrueの場合、スレッドは作業を停止する必要があります)。例を見てみましょう:
public class CustomThread extends Thread {
@Override
public void run() {
{
while (!Thread.interrupted()) {
System.out.println("Поток выполняет некую логику...");
}
System.out.println("Поток остановлен!");
}
}
}
main で実行します。
System.out.println("Начало выполнения программы");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Конец выполнения программы");
実行結果は最初のケースと同じになりますが、私はこのアプローチの方が気に入っています。記述するコードを減らし、既製の標準機能をより多く使用します。 今日はここまでです。
GO TO FULL VERSION