JavaRush /Java Blog /Random-JA /あるインタビューの話: 興味深い質問
GuitarFactor
レベル 30
Санкт-Петербург

あるインタビューの話: 興味深い質問

Random-JA グループに公開済み
最近、大手IT企業のインターンの面接に参加する機会がありました。 あるインタビューの話: 興味深い質問 - 1これは私にとって初めての IT 面接でしたが、興味深いものであったと思います。合計で、私は3時間以上「尋問」を受けました(その前に、オフィスでコンピューターを使用した宿題とテストが行​​われました)。私が質問に間違って答えても諦めず、誘導的な質問の助けを借りて私が考え、正しい答えにたどり着く面接官に敬意を表したいと思います。以下にいくつかの「スケッチ」を紹介します。私の意見では、非常に興味深い質問であり、そのいくつかは Java の特定の側面をより深く理解するのに役立ちました。おそらくこれらのことは一部の人にとっては明白なことかもしれませんが、これが役立つ人もいると思います。以下のフレーズは次のフォントで強調表示されています: インタビュアー - 太字 ナレーションによる説明と私の考え - 斜体 私の回答 - 通常のフォント 背景は終わりました。本題に入りましょう)

スケッチ 1. 「一見簡単な方法」

数値 a を数値 b で割った結果を返すメソッドをどのように実装するかを書きます。 面接官は紙に書きます。
int divide(int a, int b) {
}
*私は信じられない思いでメソッドの署名が書かれた紙を見つめました。何が問題ですか?* 私はこう書きます:
int divide(int a, int b) {
    return a/b;
}
この方法に問題はありますか? *私は本当に愚かな愚か者を捕まえています* どうやらそうではありません.. 次に正当な質問が来ます: b=0 の場合はどうなりますか? *おっと、このままではこのオフィスから追い出されてしまいます!* ああ、もちろんです。ここでは int 型の引数があるため、算術例外がスローされます。引数の型が float または double の場合、結果は Infinity になります。 これについてはどうするのでしょうか? try/catch を書き始めています
int divide(int a, int b) {
    try {
        return a/b;
    } catch (Exception e) {
        e.printStackTrace();
        return ... // ??? what the hack?
    }
}
*戻ってフリーズすることがあります。エラーの場合は何かを返す必要があります。しかし、この「何か」は計算結果からどのように区別できるのでしょうか?* 何を返すのでしょうか? うーん...戻り変数の型を整数に変更し、例外の場合は null を返すことになります。 型を変更できないと仮定してみましょう。なんとか抜け出すことができるでしょうか?例外を除いて何か別のことができるでしょうか? *これが登場* 呼び出しメソッドに転送することもできます。 右。それはどのように見えるでしょうか?
int divide(int a, int b) throws ArithmeticException{
    return a/b;
}

void callDivide(int a, int b) {
    try {
        divide(a, b);
    } catch (ArithmeticException e) {
        e.printStackTrace();
    }
}
例外を処理する必要はありますか? はい、分割メソッドから明示的に転送するためです。(*ここで私は間違っていました! 以下は、正しい答えに到達するための面接官からの誘導的な質問です*) そして、算術例外 - それはどのような種類の例外ですか - チェックされているのか、チェックされていないのか? これは実行時例外であり、チェックされていないことを意味します。 *ここで決定的な質問が来ます* つまり、あなたの言葉を借りれば、メソッド シグネチャで算術例外のスローを指定すると、それはチェック例外になるということでしょうか? *うーん!* たぶん...いいえ。 はい、なくなってしまいました。シグネチャで throws /uncheckedException/ を指定した場合、メソッドが例外をスローする可能性があることのみを警告しますが、呼び出し側メソッドで例外を処理する必要はありません。それは解決しました。間違いを避けるために他にできることはありますか? *少し考えた結果* はい、(b==0) かどうかも確認できます。そして、いくつかのロジックを実行します。 右。したがって、次の 3 つの方法で行くことができます。
  • トライ/キャッチ
  • throws – 呼び出し側メソッドへの転送
  • 引数のチェック
この場合、divideどちらの方法が望ましいと思いますか?
私なら例外を呼び出し元のメソッドに転送することを選択します。なぜなら... Division メソッドでは、この例外をどのように処理するか、intエラーが発生した場合にどのような種類の結果を返すかが明確ではありません。そして、呼び出しメソッドでは、引数 b を使用して、それがゼロに等しいかどうかを確認します。 この答えはインタビュー対象者を満足させたようですが、正直に言うと、この答えが明確であるかどうかはわかりません))

スケッチ 2. 「誰が速いですか?」

ArrayList と LinkedList はどう違うのか、という標準的な質問の後に、次のような質問が来ました。 要素を中央に挿入するかArrayList、中間に挿入するか、どちらが速くなりますLinkedListか? *ここでジャンプしましたが、どこにでも「リストの途中で要素を挿入または削除するために使用する」というような記述があったことを思い出しました。LinkedList家でも JavaRush の講義を再確認しましたが、次のようなフレーズがありました。「コレクションの途中に多くの要素を挿入 (または削除) する場合は、LinkedList. それ以外の場合はすべて - ArrayList」自動応答※ を 使うと早くなりますLinkedList明確にしてください
  1. 要素を中央に挿入するにはArrayList、リスト内の要素を定数時間で検索し、挿入された要素の右側にある要素のインデックスを線形時間で再計算します。
  2. ..の場合、LinkedListまず線形時間で中央に到達し、次に一定時間で要素を挿入し、隣接する要素のリンクを変更します。
結局のところ、どちらが速いのでしょうか? うーん...結果的には同じですね。 しかし、いつがLinkedList速いのでしょうか? それをリストの前半に挿入すると、それがわかります。たとえば、先頭に挿入した場合、ArrayList末尾まですべてのインデックスを再計算する必要がありますが、LinkedList最初の要素の参照を変更するだけで済みます。 教訓: JavaRush であっても、書かれていることすべてを文字通り信じてはいけません!)

スケッチ 3. 「イコールとハッシュコードがなかったらどうなるでしょうか!」

等号とハッシュコードに関する会話は非常に長くなりました - どのようにオーバーライドするか、 の実装Object、内部で何が起こるか、要素が に挿入されるときなどHashMap。私の意見として興味深い点をいくつか引用します* クラスを作成したと想像してください。
public class A {
    int id;

    public A(int id) {
        this.id = id;
    }
}
そして、それらはequalsと をオーバーライドしませんでしたhashcode。コードを実行すると何が起こるかを説明する
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*インタビューの前に基本的なアルゴリズム、その複雑さ、データ構造を理解するために特に数日を費やしたのは良かったです。とても役に立ちました。CS50 に感謝します!*
  1. クラス A の 2 つのインスタンスを作成します

  2. 空のマップを作成します。デフォルトでは 16 個のバスケットがあります。キーはクラス A のオブジェクトであり、その中でequalsおよびメソッドはオーバーライドされませんhashcode

  3. a1地図に入れてみましょう。これを行うには、まずハッシュを計算しますa1

    ハッシュは何と等価になりますか?

    メモリ内のセルのアドレスは、クラスのメソッドの実装です。Object

  4. ハッシュに基づいて、バスケット インデックスを計算します。

    どうやって計算すればいいのでしょうか?

    ※残念ながら、ここでは明確な回答はできませんでした。長い数値 (ハッシュ) があり、バケットが 16 個ある場合、異なるハッシュを持つオブジェクトがバケット全体に均等に分散されるようにインデックスを定義するにはどうすればよいでしょうか? インデックスは次のように計算されると想像できます。

    int index = hash % buckets.length

    すでに家にいて、ソースコードの元の実装が少し異なることがわかりました。

    static int indexFor(int h, int length)
    {
        return h & (length - 1);
    }
  5. 衝突がないことを確認してa1を挿入します。

  6. メソッドに進みましょうget。インスタンス a1 と a2 は異なるhash(メモリ内の異なるアドレス) を持つことが保証されているため、このキーには何も見つかりません。

    クラス Aのみで再定義しhashcode、最初にキー a1 を持つペアをハッシュマップに挿入し、次にキー a2 を持つペアをハッシュマップに挿入しようとするとどうなるでしょうか?

    次に、最初に目的のバスケットを見つけますhashcode。この操作は正しく実行されます。Entry次に、カートにアタッチされている LinkedList 内のオブジェクトを調べて、 によってキーを比較してみましょうequals。なぜなら equalsがオーバーライドされない場合、基本実装はクラスから取得されますObject(参照による比較)。a1 と a2 には異なるリンクがあることが保証されているため、挿入された要素 a1 は「見逃され」、a2 は新しいノードとして LinkedList に配置されます。

    結論は何ですか? HashMapオーバーライドされていないオブジェクトのキーとして使用することはできますかequalshashcode?

    いいえ、あなたがすることはできません。

スケッチ4.「わざと壊してみよう!」

エラーと例外に関する質問の後に、次の質問が続きました。 関数が StackOverflow をスローする簡単な例を書いてください。 *その後、再帰関数を書こうとしたときにこのエラーに悩まされたことを思い出しました* これはおそらく、再帰呼び出しの場合、再帰を終了するための条件が正しく指定されていない場合に発生します。 *その後、私は何か賢いことを試し始めましたが、最終的には面接官が助けてくれたので、すべてが簡単であることが判明しました*
void sof() {
    sof();
}
このエラーは ? とどう違うのですかOutOfMemory? *ここでは答えませんでしたが、後でこれが Java メモリ (オブジェクトへの呼び出しと参照はスタックに格納され、オブジェクト自体はヒープ メモリに格納されます) の知識に関する質問であることに気づきStackましHeapた。したがって、StackOverflow は、次のメソッド呼び出しのためのメモリ領域がなくなりStack、メモリOutOfMemory内のオブジェクト用の領域がなくなったときにスローされますHeap*
これらは私が覚えているインタビューの瞬間です。最終的にはインターンシップに受け入れられたので、2 か月半の研修があり、すべてがうまくいけば、その会社で働くことができます。) 興味があれば、今度は小さい記事を別の記事に書くこともできます。これは、私が別の会社で面接を受けたときに受けた、単純だがわかりやすい問題の分析です。私にとっては以上です。この記事が誰かの知識を深めたり、整理したりするのに役立つことを願っています。皆さんも楽しく学んでください!
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION