1. ホーム

java ファンデーション 002

2022-02-28 19:57:48

<スパン テスト用紙1

2013年末、ネット上で"Java面接問題完全攻略"というものが出回り、よく読んでみると、そこに書かれている問題の多くが繰り返しで価値がなく、参考回答も間違っているものが多いことがわかりました。 ブログで紹介します。改訂作業では、当時の最新版JDK(Java 7)を参考に問題の解答と関連コードを与え、EJB 2.xやJSFなどの無駄な内容や古い内容を削除し、データ構造とアルゴリズム、大規模Webサイトの技術アーキテクチャ、デザインパターン、UML、Spring MVCなどを追加、hashCodeメソッドの設計、ガベージコレクション、並行プログラミング、データベーストランザクションなど、多くの知識について深く分析して提供することにしました。当時は、OSやデータベース、ソフトウェアテストなど、面接によく出る内容も加えたいとさえ思っていましたが、諸般の事情で最終的に150問しか整理されなかったのです。ほっとしたのは、この150問がやはり多くの人の役に立ち、私のCSDNブログの総アクセス数は5万を超え、最終的には多くのサイトや個人の方にオリジナルで転載していただけたことです。昨年、Baiduの検索で"Java interview"私はこれらの事を書いた基本的にトップ5の検索結果にランクされている、私は"Alexander"を感じるようになり、私は不正確な一度これらの事を書いたので、多くの人々を誤解させるかもしれません。2014年私は別の30問を整理したとき、以前に逃した面接の質問と知識のポイントを追加することを望んでいるが、私はまだ多くのことを欠いていると感じて、多くの新しいものは、Java 8の導入後に要約して整理する必要があります。2014年以降、私の教え子の多くがJavaプログラマやJavaエンジニアとして就職し、その面接経験を皆さんにお伝えする時間がありませんでした。Java面接質問全集"ということで、この記事が生まれました。もう一度登場した内容を書いても責めないでください。なぜなら、繰り返しであっても何かを書くたびに、プログラミング言語や関連技術について考え直す必要があり、一字一句だけでなく、完璧を目指すため、私が共有するものはより新しく、より良く、より有益でなければならないと信じてください。この内容もプロのプログラマーとトレーナーの思考、精神、感情を語っているのです。

1. オブジェクト指向の特徴とは?



A:オブジェクト指向の主な機能は以下の通りです。



- 抽象化すること。抽象化とは、あるクラスのオブジェクトに共通する特徴をまとめたクラスを構築することであり、データの抽象化と動作の抽象化の両方を含む。抽象化とは、オブジェクトがどのような特性や振る舞いを持つかだけを考え、その振る舞いの詳細については考えないことである。



- インヘリタンス(Inheritance)。既存のクラスから継承情報を取得し、新しいクラスを作成することを継承という。継承情報を提供するクラスを親クラス(スーパークラス、ベースクラス)、継承情報を取得するクラスを子クラス(派生クラス)と呼びます。継承は変化するソフトウェアシステムにある程度の連続性を与え、プログラム中の変数をカプセル化する重要な手段でもあります(理解できない方は、燕紅博士のJavaとパターン、または「デザインパターン早わかり」のブリッジパターンの項を読んでみてください)。



- カプセル化。カプセル化とは、データを操作するメソッドとデータを結びつけることであり、データへのアクセスは定義されたインターフェースを通じてのみ可能である、とよく考えられています。オブジェクト指向の本質は、現実の世界を完全に自律した閉じたオブジェクトの連続として描くことである。クラスに書くメソッドは実装の詳細をカプセル化したものであり、クラスはデータとデータ操作のカプセル化として書くのです。カプセル化とは、隠せるものはすべて隠し、外界には最も単純なプログラミングインターフェースのみを提供することだとも言える(普通の洗濯機と全自動洗濯機の違いを考えてみよう。明らかに全自動洗濯機の方がカプセル化されているので、操作はより単純だ。)



- ポリモーフィズム。ポリモーフィズムとは、異なるサブタイプのオブジェクトが同じメッセージに対して異なる反応をすることを可能にすることを意味します。簡単に言うと、同じオブジェクトリファレンスで同じメソッドを呼び出しても、異なる処理をすることを意味します。ポリモーフィズムは,コンパイル時ポリモーフィズムとランタイムポリモーフィズムに分けられます.オブジェクトのメソッドをオブジェクトが外部に提供するサービスと考えると、ランタイムポリモーフィズムは次のように解釈できます。システムAがシステムBの提供するサービスにアクセスするとき、システムBはサービスの提供方法を複数持っていますが、システムAにはすべてが透過的です(電気かみそりがシステムA、その電源がシステムBのようなものです。システムBは電池を使うことも、交流を使うことも、場合によっては AシステムはBのオブジェクトを通して電源のメソッドを呼び出すだけで、電源システムの根本的な実装が何であるか、どのように電源を供給しているのかは知らない)。メソッドのオーバーロード(overload)はコンパイル時多相性(前結合ともいう)を実装し、メソッドのオーバーライド(override)は実行時多相性(後結合ともいう)を実装しています。ランタイムポリモーフィズムは、オブジェクト指向の物事の本質であり、ポリモーフィズムを達成するために、2つのことを行う必要があります。1). メソッドのオーバーライド(サブクラスは親クラスを継承し、親クラスの既存または抽象メソッドをオーバーライドする)、2)。オブジェクトモデリング(親オブジェクトの参照で子オブジェクトを参照し、同じ参照で同じメソッドを呼び出しても子オブジェクトによって異なる挙動をするようにする)。

2. アクセス修飾子 public, private, protected, unwritten (default)の違いは何ですか?



回答

<テーブル

モディファイア

現在のクラス

パッケージと同じ

サブクラス

その他のパッケージ

公開

プロテクト

×

デフォルト

×

×

プライベート

×

×

×

defaultは、同じパッケージの他のクラスに対してはpublic、同じパッケージでない他のクラスに対してはprivateに相当し、protectedは、サブクラスに対してはpublic、同じパッケージでないクラスに対してはprivateに相当します。Javaでは、外部クラス修飾子はpublicかdefaultのみで、クラスメンバ(内部クラスも含む)はこれら4つの修飾子全てに対応できます。

3. Stringは最も基本的なデータ型か?



A: いいえ。Javaには、byte、short、int、long、float、double、char、booleanの8つの基本データ型しかなく、基本型(プリミティブ型)以外は、参照型(リファレンス型)になっています。Java5以降に導入された列挙型も、特殊な参照型である。

4. float f=3.4;は正しいですか?



Answer:いいえ。3.4は倍精度の数値で、倍精度の型(double)を浮動小数点型(float)に代入するとダウンキャストとなり精度が落ちるので、強制的に型変換する必要があります float f=(float)3.4; または float f =3.4F; と記述してください。

5. short s1 = 1; s1 = s1 + 1; is that wrong? short s1 = 1; s1 += 1; is that wrong?



A: short s1 = 1; s1 = s1 + 1; の場合、1がint型なので、s1 + 1の演算結果もint型となり、short型に代入するために強制型変換が必要です。また、short s1 = 1; s1 += 1; は s1 = (short)(s1 + 1); と等価であり、暗黙の強制型変換があるため正しくコンパイルされます。

6. Javaにはgotoがありますか?



A:gotoはJavaの予約語であり、現在のバージョンでは使用されていません。(Javaの生みの親であるJames Gosling氏の著書 "The Java Programming Language" の付録によると、Javaのキーワードのリストがあり、その中に goto と const がありますが、この2つは現在では使えないキーワードなので、予約語と呼ぶところもあるようです。(C言語に慣れたプログラマなら、システム・クラス・ライブラリで使われてきた特別な意味を持つ単語やその組み合わせが予約語とみなされることを知っているので、より広い意味を持つはずです)

7. intとIntegerの違いは何ですか?



A:Javaはほぼ純粋なオブジェクト指向のプログラミング言語ですが、プログラミングの利便性や基本データ型の導入のため、しかしこれらの基本データ型をオブジェクトとして操作できるように、Javaでは基本データ型ごとに対応するラッパ型(ラッパクラス)を導入しており、Java5からはintラッパクラスはInteger、Java5からは自動ボクシング/アンボクシング機構が導入されて両者が相互に変換できるようになっています。



Javaでは、プリミティブ型ごとにラッパー型が用意されています。



- プリミティブ型:boolean、char、byte、short、int、long、float、double



- Wrapperタイプ。ブール値、文字、バイト、ショート、整数、ロング、フロート、ダブル

class AutoUnboxingTest { <未定義

    public staticvoid main(String[] args) {... <未定義

        整数a =new 整数(3);

        Integer b =3; // 3をInteger型に自動変換する

        int c = 3;

       System.out.println(a == b); //false 2つの参照は同じオブジェクトを参照していません。

       System.out.println(a == c); //true aは自動的にintにアンボックスされ、cと比較されます。

    }

}

- 1

- 2

- 3

- 4

- 5

- 6

- 7

- 8

- 9

- 10

また、最近、オートボックスとアンボックスにも多少関係する面接の質問に遭遇しました。そのコードは以下の通りです。

public class Test03 { <未定義

    public staticvoid main(String[] args) {... <未定義

        整数f1= 100, f2= 100, f3= 150, f4= 150。

       System.out.println(f1 == f2);

       System.out.println(f3 == f4)。

    }

}

- 1

- 2

- 3

- 4

- 5

- 6

- 7

- 8

- 9

何のことかわからないと、どちらの出力も真か偽かと思いがちです。まず注意すべきは、4つの変数f1, f2, f3, f4はIntegerオブジェクトの参照なので、次の==演算は値ではなく参照を比較することになることです。箱詰めの性質はどうなっているのでしょうか。Integerオブジェクトにint値を代入すると、IntegerクラスのスタティックメソッドvalueOfが呼び出されます。valueOfのソースコードを見れば、何が起こるかわかると思います。

    <未定義

        if (i >=IntegerCache.low && i <=IntegerCache.high)

            returnIntegerCache.cache[i + (-IntegerCache.low)] を返します。

        newInteger(i) を返します。

    }

- 1

- 2

- 3

- 4

- 5

IntegerCacheは、Integerの内部クラスで、コードは以下の通りです。

/**

     * の間の値に対する autoboxing のオブジェクト ID セマンティクスをサポートするためのキャッシュです。

     * JLS が要求する -128 から 127 (含む) の範囲。

    

     * キャッシュは初回使用時に初期化されます。

     * は {@code-XX:AutoBoxCacheMax=<size>} オプションで制御することができます。

     * VM初期化時に、java.lang.Integer.IntegerCache.high プロパティが設定されます。

ハイプロパティ

     * のプライベートシステムプロパティに設定・保存することができます。

<ハイ

     */

    private staticclass IntegerCache { <未定義

        staticfinal int low = -128;

        staticfinal int high;

        staticfinal Integer cache[];

        static { <未定義

            // highvalue はプロパティで設定することができます。

            int h =127。

            文字列 integerCacheHighPropValue =.

               sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high") を使用します。

            if(integerCacheHighPropValue ! = null) {... <未定義

                try{ <未定義

                   int i = parseInt(integerCacheHighPropValue);

                   i = Math.max(i, 127);

                   // 配列の最大サイズは Integer.MAX_VALUE です.

                   h = Math.min(i, Integer.MAX_VALUE - (-low) - 1)となります。

                }catch( NumberFormatException nfe) { <未定義

                   // プロパティが int にパースできない場合は、無視する。

                }

            }

            high =h;

            cache =new Integer[(high - low) + 1];

            int j =low。

            for(intk = 0; k < cache.length; k++)

               cache[k] = new Integer(j++);

            //range [-128, 127] はインターンでなければならない (JLS7 5.1.7)

            assertIntegerCache.high >= 127;

        }

        privateIntegerCache() {} です。

    }

- 1

- 2

- 3

- 4

- 5

- 6

- 7

- 8

- 9

- 10

- 11

- 12

- 13

- 14

- 15

- 16

- 17

- 18

- 19

- 20

- 21

- 22

- 23

- 24

- 25

- 26

- 27

- 28

- 29

- 30

- 31

- 32

- 33

- 34

- 35

- 36

- 37

- 38

- 39

- 40

- 41

- 42

- 43

- 44

簡単に言うと、整数リテラルの値が-128から127の間であれば、新しい整数オブジェクトは生成されず、代わりに定数プールにある整数オブジェクトが直接参照されるので、上記の面接問題のf1==f2の結果は真、f3==f4は偽となります。

注意喚起 面接の質問は一見シンプルであればあるほど不思議で、面接官にはかなりの熟練度が要求されます。

8. &と&の違いは何ですか?



A:&演算子には2つの使い方があります。(1)ビット単位でのwith、(2)論理的なwithです。&&演算子は、短絡的なwithの操作です。論理和と短絡和の違いは大きいですが、どちらも式全体が真になるためには、演算子の左端と右端のブール値が真であることが必要です。&&の左側の式の値が偽であれば、右側の式は直接短絡されて何も演算されないので短絡和と呼ばれているのです。例えば、ユーザーログインがNULLでなく、ユーザー名が空文字列でないことを確認する場合、次のように記述します。 username ! = null&&!username. equals("")の場合、両者の順序を入れ替えることはできませんし、&演算子は言うまでもなく、最初の条件が成立しない場合、単に文字列equalsと比較することができないため、さもなければNullPointerExceptionが生成されます。注:論理和演算子(|)と短絡和演算子(||)の違いも同じです。

追加事項 JavaScriptに慣れている人なら、ショートカットの威力はよく分かっているはずです。JavaScriptの達人になりたいなら、まずは短絡的な遊びから始めてみてください。

9. メモリ内のスタック、ヒープ、メソッド領域の使い方を説明しなさい。



A:通常、基本データ型の変数、オブジェクトへの参照を定義し、関数呼び出しのシーンはJVMのスタック空間を使って保存され、newキーワードとコンストラクタで生成されたオブジェクトはヒープ空間に置かれ、ヒープはガベージコレクタが管理する主要領域で、ガベージコレクタは現在世代収集アルゴリズムを使用しているので、ヒープ空間は新世代と旧世代に細分化することが可能です。世代、具体的にはEden、Survivor(FromSurvivorとTo Survivorに分けられる)、Tenuredに分けられる。メソッド領域とヒープは様々なスレッドが共有するメモリ領域で、クラス情報、定数、静的変数、JITコンパイラのコンパイルコードなどJVMがロードしたデータを格納するために使われる。直書き100、"Hello"などのプログラムのリテラル ( literal )、定数はメソッド領域の一部である定数プールに置かれる。スタックスペースは最も速く動作しますが、スタックは小さく、通常、多数のオブジェクトはヒープスペースに配置され、スタックとヒープの両方のサイズは、JVM起動パラメータによって調整することができ、スタックスペースが枯渇するとStackOverflowErrorが発生し、ヒープと定数プールスペースが不足しているとOutOfMemoryErrorに発生することになります。

String str = new String("hello");

- 1

上記の文では、スタックに変数str、ヒープにnewで作成した文字列オブジェクト、メソッド領域にリテラル"hello"を配置しています。

補遺1. Java の新しいバージョン(Java 6 の一部のアップデートから)では、JIT コンパイラの進化と "escape analysis" 技術の段階的な成熟により、オンスタック割り当てやスカラー置換などの最適化により、オブジェクトが必ずヒープ上に割り当てられるという事柄は絶対ではなくなってきています。

補足2 : ランタイム定数プールは、その性質上、動的であるという点でクラスファイルの定数プールと同等である。Java言語では、定数はコンパイル時にのみ生成される必要はなく、Stringクラスのintern()メソッドのように、実行時に新しい定数をプールに入れることができる。

次のコードが何をするのか、Java 7 の前と後で結果を比較してみてください。

String s1 = 新しいStringBuilder("go")

    .append("od").toString();

System.out.println(s1.intern() == s1);

String s2 = new StringBuilder("ja")

   .append("va").toString();

System.out.println(s2.internal() == s2);

- 1

- 2

- 3

- 4

- 5

- 6

10. Math.round(11.5) は何に等しく、Math.round(-11.5) は何に等しいか?



A: Math.round(11.5) は 12 を返し、Math.round(-11.5) は -11 を返します。四捨五入は、引数に0.5を加えて切り捨てることで動作します。

11. switchはbyte, long, Stringのどれで動作するのでしょうか?



A: Java5以前では、switch(expr)において、exprはbyte、short、char、intしか使えません。Java 5 からは enum 型が導入され、expr も enum 型になります。Java 7 からは、expr は String にもなりますが、long integer (long) は現在のすべてのバージョンで使用できません。

12. 2×8の計算を最も効率的に行うには?



答え:2 << 3(左に3つずらすと2の3乗に相当し、右に3つずらすと2の3乗に相当します。)

追加してください。 書かれたクラスのhashCodeメソッドをオーバーライドすると、以下のようなコードが表示されることがあります。実は、なぜこのような乗算演算でハッシュコード(ハッシュ符号)を生成するのか、なぜ素数なのか、なぜ通常31という数字が選ばれるのか、よく理解できていないのではないでしょうか?最初の2つの質問に対する答えは、あなた自身のBaiduで読むことができます。31が選ばれるのは、シフトと減算の操作に置き換えることで、より良いパフォーマンスを得ることができるからです。この時点で、すでに思い当たる節があるかもしれませんね。31 * num は (num << 5) - num と等価であり、5ビットを左にシフトすることは2の5乗に相当し、その後自分自身を減算することは31の乗に相当し、最近のVMはこの最適化を自動的に行っています。

public class PhoneNumber { <未定義

    private intareaCode;

    private Stringprefix;

    private StringlineNumber;

    オーバーライド

    public inthashCode() { <未定義

        final intprime = 31;

        int result= 1;

        result =prime * result + areaCode;

        結果 = 主 * 結果

                +((lineNumber == null) ? 0 : lineNumber.hashCode())。

        result =prime * result + ((prefix == null) ? 0 : prefix.hashCode())。

        を返します。

    }

    オーバーライド

    public booleanequals(Object obj) {... <未定義

        if (this == obj)

            が真を返します。

        if (obj ==null)

            はfalseを返します。

        if(getClass() ! = obj.getClass())

            はfalseを返します。

        PhoneNumberother = (PhoneNumber) obj;

        if(areaCode ! = other.areaCode)

            は偽を返します。

        if(lineNumber == null) { <未定義

            if(other.lineNumber ! = null)

               は false を返します。

        } else if(!lineNumber.equals(他の.lineNumber))

            はfalseを返します。

        if (prefix== null) { <未定義

            if(other.prefix ! = null)

               は false を返します。

        } else if(!prefix.equals(other.prefix))

            はfalseを返します。

        は真を返します。

    }

}

- 1

- 2

- 3

- 4

- 5

- 6

- 7

- 8

- 9

- 10

- 11

- 12

- 13

- 14

- 15

- 16

- 17

- 18

- 19

- 20

- 21

- 22

- 23

- 24

- 25

- 26

- 27

- 28

- 29

- 30

- 31

- 32

- 33

- 34

- 35

- 36

- 37

- 38

- 39

- 40

- 41

13.配列のlength()メソッドと文字列のlength()メソッドはあるのか?



A: 配列にはlength()メソッドはなく、lengthプロパティがあり、文字列にはlength()メソッドがあり、JavaScriptではlengthプロパティから文字列の長さを取得しますが、これはJavaと混同していますね。

14. Javaで、現在の複数のネストされたループから飛び出すには?



A: 一番外側のループの前にAのようなタグを追加し、break A;で多重ループからジャンプアウトします。(Javaはタグ付きのbreakやcontinue文をサポートしており、CやC++のgoto文と多少似た働きをしますが、gotoの使用を避けるのと同じように、タグ付きのbreakやcontinueを使うのは避けるべきです。プログラムをよりエレガントにはできず、多くの場合は逆の効果さえあるので、この構文は実際には(知っていた方がよいでしょう)

15. コンストラクタ(構成子)はオーバーライドできる?



A: コンストラクタは継承できないので、オーバーライドできませんが、オーバーロードは可能です。

16. 2つのオブジェクトは同じ値(x.equals(y) == true)を持っていますが、異なるハッシュコードを持つことができますが、それは正しいですか?



A: いいえ、2つのオブジェクト x と y が x.equals(y) == true を満たす場合、それらのハッシュコードは同じでなければなりません。 は同じでなければなりません。(2)2つのオブジェクトが同じハッシュコードを持つ場合、それらは必ずしも同じものではありません。もちろん、この要件に従う必要はありませんが、上記の原則に違反すると、コンテナを使用した場合、同じオブジェクトがSetコレクションに出現することがある一方で、新しい要素を追加する際の効率が大幅に低下します(ハッシュストレージを使用するシステムでは、ハッシュコードの衝突が頻繁に起こると、アクセス性能が急激に低下することになります)。

追加されました。 equalsとhashCodeメソッドについては、多くのJavaプログラムは知っているが、多くの人は知っているだけで、Joshua Blochの名著"Effective Java"(多くのソフトウェア会社、"Effective Java"、"Java Programming Ideas"、"Refactoring.で、そのことが紹介されています)。Javaプログラマ必読の書です。まだお読みでない方は、ぜひお急ぎください。 アマゾン 購入はこちらから) では、equalsメソッドについて次のように紹介しています。まず、equalsメソッドは自己再帰性(x.equals(x)がtrueを返すこと)、対称性(x.equals(y)がtrueを返すとき、y.equals(x)もtrueを返す)、移植性(x.equals(y), y.equals( z) がともにtrueを返すときx. equals(z)もtrueを返すこと)、一貫性(xとyが参照するオブジェクトの情報が変更されていない場合、x.equals(y)を複数回呼び出すと同じ戻り値が得られること)、xを参照している非NULL値に対してx.equals(null)はfalseを返さなければなりません。高品質のequalsメソッドの実現には、以下のコツが必要です。1.演算子==で引数がこのオブジェクトへの参照かどうかをチェックする 2.演算子instanceofで引数が正しい型かどうかをチェックする 3.クラスの主要属性について、引数が渡されるオブジェクトの属性と一致するかどうかをチェックする 4.引数が渡されるオブジェクトの属性について、引数が渡されるオブジェクトの属性と一致するかどうかをチェックする 5.引数が渡されるオブジェクトの属性について、引数が渡されるクラスの主要属性と一致するかどうかをチェックする などです。equalsメソッドを書いたら、対称性、受け渡し、一貫性を満たしているかどうかを自問する、 5. equalsを書き換えるときは必ずhashCodeをオーバーライドする、 6. equalsメソッドの引数のObjectを他の型に置き換えない、書き換えるときは@Overrideアノテーションを忘れない、などです。

17. String クラスを継承することは可能ですか?



A: Stringクラスはfinalクラスであり、継承することはできません。

追加してください。 Stringを継承すること自体が間違いです。String型を再利用するには、継承(Is-A)ではなく、関連付け(Has-A)と依存(Use-A)が最適です。

18. オブジェクトをメソッドにパラメータとして渡すと、メソッドはオブジェクトのプロパティを変更でき、変更した結果を返すことができますが、これは値渡しなのでしょうか、それとも参照渡しなのでしょうか?



A: 値渡しです。Java言語のメソッドコールは、パラメータの値渡しにのみ対応しています。オブジェクトのインスタンスがメソッドのパラメータとして渡されるとき、パラメータの値はそのオブジェクトへの参照となります。オブジェクトのプロパティは呼び出し中に変更できますが、オブジェクトへの参照を変更しても呼び出し元には影響しません。C++とC#では、参照を渡すかパラメータを転送することで、入力されたパラメータの値を変更することができます。以下に示すコードは、C#では書けますが、Javaではできません。

システムを使っています。

名前空間 CS01 { <未定義

    class プログラム { <未定義

        publicstatic void swap(ref int x, ref int y) {. <未定義

            inttemp = x;

            x = y となる。

            y =temp;

        }

        publicstatic void Main (string[] args) { { { <未定義

            int a = 5, b = 10;

            swap(ref a, ref b)です。

            // a = 10, b = 5;

           Console.WriteLine ("a = {0}, b = {1}", a, b)を実行します。

        }

    }

}

- 1

- 2

- 3

- 4

- 5

- 6

- 7

- 8

- 9

- 10

- 11

- 12

- 13

- 14

- 15

- 16

- 17

- 18

- 19

注:Javaで参照を渡せないのは本当に不便で、これはJava 8でもまだ改善されていません。それこそが、Javaで書かれたコードにWrapperクラスが多く存在する理由です(メソッド呼び出しで変更する必要がある参照をWrapperクラスに置き、Wrapperオブジェクトをメソッドに渡す)、これはコードを肥大化するだけで、特にCやC++からJavaプログラマに移行する開発者には耐え難いものです。

19. StringとStringBuilder、StringBufferの違いは何ですか?



A: Javaプラットフォームは2種類の文字列を提供します。StringとStringBuffer/StringBuilderの2種類があり、文字列を保存したり操作したりすることができます。このうち、Stringは読み取り専用の文字列で、Stringが参照する文字列の内容を変更することはできません。StringBuffer/StringBuilderクラスは、直接変更可能な文字列オブジェクトを表します。Java 5で登場したStringBuilderは、StringBufferと全く同じメソッドを持っていますが、すべての面で同期がとられていないため、シングルスレッド環境で使用される点が異なり、StringBufferよりも効率的でもあります。

インタビュー質問1 - StringBuffer/StringBuilderオブジェクトのappendメソッドを呼び出して文字列を連結するよりも、+演算子で文字列を連結した方が良い場合はどのような場合でしょうか?

インタビュー質問2 - 次のプログラムの出力結果を挙げよ。

class StringEqualTest { (ストリングイコールテスト) <未定義

    public staticvoid main(String[] args) {... <未定義

        文字列 s1 = "プログラミング"。

        String s2 =new String("Programming");

        文字列 s3 ="Programming";

        文字列 s4 ="ming";

        文字列 s5 = "プログラム" + "ミン";

        文字列 s6 =s3 + s4;

       System.out.println(s1 == s2)。

       System.out.println(s1 == s5)。

        System.out.println(s1 == s6)。

       System.out.println(s1 == s6.internal());

       System.out.println(s2 == s2.intern());

    }

}

- 1

- 2

- 3

- 4

- 5

- 6

- 7

- 8

- 9

- 10

- 11

- 12

- 13

- 14

- 15

- 16

補足 上記の面接の質問に答えるには、2つのポイントをクリアする必要があります。1. 文字列オブジェクトの内部メソッドは、定数プールにある対応するバージョンの文字列オブジェクトの参照を取得し(定数プールにStringオブジェクトのequalsの結果が真である文字列がある場合)、定数プールに対応する文字列がない場合は定数プールに追加し、定数プールの文字列への参照を返す;2. 文字列の+操作は、基本的に、追加操作のためにStringBuilderオブジェクトを作成し、スプライスされたStringBuilderオブジェクトをtoStringメソッドでStringオブジェクトに処理します。javap -c StringEqualTest. classコマンドで、そのクラスファイルに対応するJVMバイトコード命令を取得することが可能です。

20. オーバーロード(Overload)とオーバーライド(Override)の違い。オーバーロードされたメソッドは、戻り値の型によって区別できますか?



A: オーバーロードとオーバーライドは、どちらもポリモーフィズムを実現する方法です。前者はコンパイル時のポリモーフィズムを実現し、後者は実行時のポリモーフィズムを実現するという違いがあります。オーバーロードはクラス内で発生し、同じ名前のメソッドでもパラメータリストが異なる(パラメータの種類が異なる、パラメータの数が異なる、またはその両方)場合にオーバーロードとみなされます。オーバーライドはサブクラスとその親クラス間で発生し、オーバーライドにはサブクラスのオーバーライドメソッドが親クラスのオーバーライドメソッドと同じ戻り値を持ち、親クラスのオーバーライドメソッドよりアクセス性が高く、親クラスのオーバーライドメソッド以上の例外を宣言できないこと(リクター置換原則)、が要求されます。オーバーロードには戻り値の型に関する特別な要件はありません。

インタビューの質問 以前、ファーウェイの面接でこんな質問がありました - "なぜ戻り値の型によってオーバーロードを区別できないのですか"、答えを考えてみてください

21. JVMがクラスファイルを読み込む仕組みについて説明してください。



A: JVMにおけるクラスローディングは、ClassLoaderとそのサブクラスによって実現されます。Javaにおけるクラスローダーは、Javaランタイムシステムの重要なコンポーネントであり、実行時にクラスファイル内のクラスを見つけてロードする役割を担っています。



Javaはクロスプラットフォームであるため、コンパイルされたJavaのソースプログラムは実行プログラムではなく、1つまたは複数のクラスファイルです。Javaプログラムがクラスを使用する必要があるとき、JVMはクラスがロードされ、リンク(検証、準備、解析)され、初期化されていることを確認します。クラスのロードは、クラスの.classファイルのデータをメモリに読み込むプロセスで、通常は.classファイルに読み込むためのバイト配列を作成し、ロードされたクラスに対応するクラス・オブジェクトを生成します。ロードが完了した後、Classオブジェクトはまだ完成していませんので、この時点ではまだクラスは利用できません。クラスが読み込まれると、接続フェーズに入ります。このフェーズは、検証、準備(静的変数のメモリ確保とデフォルト初期値の設定)、解析(シンボリック参照を直接参照に置き換える)の3つのステップで構成されています。最後にJVMは、1)クラスに直接の親があり、このクラスがまだ初期化されていない場合、最初に親クラスを初期化し、2)クラス内に初期化文が存在する場合、順次実行することを含めてクラスを初期化します。



クラスの読み込みはクラスローダーによって行われ、ルートローダー(BootStrap)、エクステンションローダー(Extension)、システムローダー(System)、ユーザー定義クラスローダー( java.lang.ClassLoader のサブクラス)などがある。Java 2 (JDK 1.2)から、クラス・ローディング・プロセスはPDM (Parent Delegation Mechanism)を採用した。pdmはJavaプラットフォームのセキュリティをより確実にし、JVMはルート・ローダーとしてBootstrapを備え、他のすべてのローダーは1つだけの親クラスローダーを持っている。JVMは、JavaプログラムにBootstrapへの参照を提供しません。以下は、いくつかのクラス・ローダーの説明です。

- Bootstrap: 一般にネイティブコードで実装され、JVMベースコア・クラス・ライブラリ(rt.jar)のロードを担当します。

- Extension: java.ext.dirs システム・プロパティで指定されたディレクトリからライブラリをロードし、その親ローダーはBootstrapです。

- システムです。アプリケーション・クラス・ローダーとも呼ばれ、その親はエクステンションです。環境変数 classpath またはシステムプロパティ java.class.path で指定されたディレクトリからクラスを文書化し、ユーザー定義のローダーのデフォルトの親ローダーとなります。

22. char型変数に漢字を格納できるのか、その理由は?



A: Javaで使われているエンコーディングはUnicode(特定のエンコーディングを選ばず、文字セット内の文字の番号をそのまま使うので統一されている)であり、char型は2バイト(16ビット)占有するので、漢字を入れることは問題ないでしょう。

追加です。 Unicodeを使用するということは、JVMの内部と外部で文字が異なる表現を持つということです。JVM内部ではすべてUnicodeで、この文字がJVM内部から外部(例えばファイルシステムに預けられる)に転送されるとき、エンコーディング変換が必要になります。そこで、Javaには、バイトストリームと文字ストリームがあり、文字ストリームとバイトストリームを変換する変換ストリーム、例えば、バイトストリームと文字ストリーム間のアダプタクラスであるInputStreamReaderやOutputStreamReaderがエンコーディング変換を担っています。Cプログラマにとって、このようなエンコーディング変換を実現するには Cプログラマにとって、このようなエンコーディング変換を行うには、共用メモリ機能であるユニオンに依存することが怖いのです。

23. 抽象クラスとインターフェースの類似点と相違点を教えてください。



A: 抽象クラスとインタフェースはインスタンス化できませんが、抽象クラスとインタフェースの参照型を定義することができます。抽象クラスを継承したクラスやインタフェースを実装したクラスは、その中のすべての抽象メソッドを実装する必要があり、そうでない場合はやはり抽象クラスとして宣言する必要があります。抽象クラスはコンストラクタを定義でき、抽象メソッドと具象メソッドを持つことができますが、インターフェースはコンストラクタを定義できず、すべてのメソッドが抽象メソッドであるため、インターフェースは抽象クラスよりも抽象度が高くなります。抽象クラスのメンバは private, default, protected, public のいずれかになりますが、インターフェースのメンバはすべて public です。抽象クラスではメンバ変数を定義できますが、インターフェースで定義されるメンバ変数は実際には定数です。抽象メソッドを持つクラスは抽象クラスとして宣言されなければなりませんが、抽象クラスは必ずしも抽象メソッドを持つ必要はありません。

24. Static Nested ClassとInner Classの違いは何ですか?



A: Static Nested Class は static と宣言された内部クラスで、外部のクラスインスタンスに依存せずにインスタンス化することができます。通常の内部クラスは、外部クラスをインスタンス化した後にインスタンス化する必要があり、以下のようにかなり奇妙な構文になります。

/**

 * ポーカークラス(トランプ1個分)

 * 著者 骆昊

 *

 */

public class Poker { <未定義

    private staticString[] suites = {"スペード", "ハート", "クラブ", "ダイヤ"};

    private staticint[] faces = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};

    private Card[]cards;

    /**

     * コンストラクタ

    

     */

    public Poker(){ <未定義

        cards = newCard[52] です。

        for(int i =0; i < suites.length; i++) { { { (int i =0; i < suites.long; i++) <未定義

            <未定義

               cards[i * 13 + j] = new Card(suites[i], faces[j]);

            }

        }

    }

    /**

     * シャッフル(乱雑な順番)

     *

     */

    public void shuffle(){。 <未定義

        for(int i =0, len = cards.length;iの<len;i++){。 <未定義

            intindex = (int) (Math.random() * len);

            Cardtemp = cards[index];

           cards[index] = cards[i]です。

           cards[i] = temp;

        }

    }

    /**

     * ディール

     * @param index 配られたカードの位置

    

     */

    public Carddeal(int index) { <未定義

        returncards[index]です。

    }

    /**

     * カードクラス(ワンポーカー)

     * [内部クラス]です。

     * 著者 骆昊

     *

     */

    public classCard { <未定義

        privateString suite; // ファンシーカラー

        private int face; // ポイントの数

        publicCard(String suite, int face) {. <未定義

           this.suite = suite;

           this.face = face;

        }

        オーバーライド

        publicString toString() { <未定義

            StringfaceStr = ""です。

           switch(face) { <未定義

            case 1:faceStr = "A"ブレーク。

            case11: faceStr = "J"; break;

            case12: faceStr = "Q"; break;

            case13: faceStr = "K"; break;

           デフォルト:faceStr = String.valueOf(face)。

            }

            returnsuite + faceStr;

        }

    }

}

- 1

- 2

- 3

- 4

- 5

- 6

- 7

- 8

- 9

- 10

- 11

- 12

- 13

- 14

- 15

- 16

- 17

- 18

- 19

- 20

- 21

- 22

- 23

- 24

- 25

- 26

- 27

- 28

- 29

- 30

- 31

- 32

- 33

- 34

- 35

- 36

- 37

- 38

- 39

- 40

- 41

- 42

- 43

- 44

- 45

- 46

- 47

- 48

- 49

- 50

- 51

- 52

- 53

- 54

- 55

- 56

- 57

- 58

- 59

- 60

- 61

- 62

- 63

- 64

- 65

- 66

- 67

- 68

- 69

- 70

- 71

- 72

- 73

- 74

- 75

テストコードです。

class PokerTest { <未定義

    public staticvoid main(String[] args) {... <未定義

        ポーカー poker= new Poker()。

       poker.shuffle(); //シャッフル

        Poker.cardc1 = poker.deal(0); // 1枚目のカードを配ります。

        // 非静的な内部クラスCardの場合

        // Card オブジェクトは、外側のクラス Poker オブジェクトを通してのみ作成することができます。

        Poker.Cardc2 = poker.new Card("Hearts",1); // 自分でカードを作る。

       System.out.println(c1); // シャッフル後の1枚目のカード

       System.out.println(c2); // 印刷します。ハートのエース

    }

}

- 1

- 2

- 3

- 4

- 5

- 6

- 7

- 8

- 9

- 10

- 11

- 12

- 13

- 14

Interview Question - 次のコードのうち、コンパイルエラーが発生するのはどの部分ですか?

class Outer { <未定義

    class Inner {} です。

    public staticvoid foo() { new Inner(); }.

    public void bar() { new Inner(); }.

    public staticvoid main(String[] args) { { <未定義

        newInner()です。

    }

}

- 1

- 2

- 3

- 4

- 5

- 6

- 7

- 8