JVMの実行方式
JVMはインタープリター方式でバイトコードを実行し、プログラムを迅速に開始し、JITコンパイラを通じて性能を最適化します。
インタープリター方式
- バイトコードを1行ずつ機械語に変換して実行します。デバッグが速いですが、実行速度はコンパイル方式より遅いです。
コンパイラ方式
- 実行速度が速いですが、コンパイル過程で時間がかかります。
文字列処理
- String: 不変オブジェクトで、文字列を操作するたびに新しいStringオブジェクトが生成されます。スレッドセーフです。
- StringBuffer: 可変オブジェクトで、文字列操作時に既存のオブジェクトの値を変更します。スレッドセーフですが、同期化による性能低下がある場合があります。
- StringBuilder: 可変オブジェクトで、文字列操作時に既存のオブジェクトの値を変更しますが、スレッドセーフではありません。
スレッドセーフ
- マルチスレッド環境でスレッドが同時にそのコードやデータにアクセスしても、実行結果が同じになります。ミューテックス/セマフォなどの同期化方法で共有リソースへの同時アクセスを制御します。
オーバーヘッド
- 作業を遂行するために必要な追加の資源や時間を意味します。同期化時のオーバーヘッドは待機時間が発生し、同期化されたブロックまたはメソッドに一度に一つのスレッドのみアクセスできるため、他のスレッドは実行が遅延することがあります。
アクセス制御修飾子
- public: すべてのクラスからアクセス可能です。
- protected: 同じパッケージ内の他のクラスとそのクラスを継承する子クラスでアクセス可能です。
- default: アクセス制御修飾子を明示しない場合で、クラス、メンバー変数、メソッドは同じパッケージ内のクラスでのみアクセスできます。
- private: 宣言されたクラス内部でのみアクセスできます。カプセル化して外部から保護する際に使用します。
クラスとオブジェクト
- クラス: 特定のオブジェクトの属性と行動を定義する設計図です。
- オブジェクト: クラスによって定義された設計図に従って作られた実体です。メモリに割り当てられ、各オブジェクトは固有の状態を持ち、クラスに定義されたメソッドを実行できます。
- インスタンス: クラスのオブジェクトで、各インスタンスは固有の状態を持ちます。
Call by ReferenceとCall by Value
- Call by Reference: 引数のメモリアドレスを渡します。
- Call by Value: 引数の値をコピーして渡します。Javaは基本的にCall by Valueで動作します。Javaの参照変数は元のオブジェクトへの参照を値としてコピーします。
Javaのデータタイプ
- 基本データ型: 整数型、浮動小数点型、論理型、文字型などがあり、スタック領域に保存されます。
- 参照データ型: オブジェクトを生成して生成されたオブジェクトのアドレスを参照するタイプで、クラス、インターフェース、配列、列挙型などがあります。ヒープメモリに保存され、参照する変数がなければGCにより破壊されます。
OOPの4つの特徴
- 抽象化: 特定の観点で重要な部分だけを抽出する作業
- カプセル化: データとプロセスを一つのオブジェクトにまとめる
- 継承: 親オブジェクトの特徴をそのまま受け継ぐ
- 多態性: 応答がオブジェクトのタイプ
に応じて異なる
SOLIDの原則
- 単一責任の原則(SRP): 一つのクラスは一つの責任だけを持つべきです。
- 開放閉鎖の原則(OCP): 自身の拡張には開かれており、周辺の変化には閉じているべきです。
- リスコフ置換の原則(LSP): 子クラスは親クラスの役割をすべて果たせるべきです。
- インターフェース分離の原則(ISP): 複数の具体的なインターフェースを使用します。
- 依存性逆転の原則(DIP): 実装クラスに依存せず、インターフェースに依存すべきです。
Non-StaticメンバーとStaticメンバーの違い
- Non-Staticメンバー: インスタンスメンバーと呼ばれ、ヒープ領域に生成され、各オブジェクトごとに別々に存在します。
- Staticメンバー: クラスメンバーと呼ばれ、コンパイル時にスタティック領域に生成されます。オブジェクト生成なしで使用できます。
ローカル変数
- メソッド内で生成される変数で、メソッドが実行されると生成され、メソッドが終了すると消えます。
Javaのmainメソッドがstaticである理由
- JREはプログラム内にmainメソッドがあるか確認して実行します。mainメソッドが終了するとJREはJVMを終了し、JRE自体もメモリから消えます。
- public: どこからでもアクセス可能であるべきです。
- static: プログラム実行時にメモリに割り当てられるべきです。
- void: mainメソッドが終了するとプログラムも終了するため、戻り値を必要としません。
- main: 慣例的な開始点です。
- String[] args: プログラム実行時に最初のスレッドであるmainにデータを渡したい場合に使用します。
finalキーワード
- 変数やメソッド、クラスが変更不可能であることを示す予約語です。
finallyキーワード
- try/catchブロックが終了する際に常に実行されるコードを定義します。
finalizeキーワード
- ガベージコレクタがもはや参照が存在しないオブジェクトをメモリから削除しようと決定した瞬間に呼び出されます。
Java GenericとC++テンプレートの違い
- Genericはコンパイル時に型を検査し、実際には存在しません。テンプレートはコンパイル時にインスタンス化されます。
JavaのGC
- Young Generation: 新しく生成されたオブジェクトが保存される領域で、ここでのGCをMinor GCと呼びます。
- Old Generation: Young Generationで生き残ったオブジェクトが移動される領域で、ここでのGCをMajor GCと呼びます。
GCアルゴリズム
- Mark and Sweep: ルートオブジェクトから開始してアクセス可能なすべてのオブジェクトを識別しマークします。マークされていないオブジェクトは削除されます。
- Copying: 主にYoung Generationで使用され、ヒープを2つの半空間に分け、1つの空間から生き残ったオブジェクトを他の空間にコピーして圧縮します。
- Generational GC: オブジェクトの生存期間に応じて異なる方法でメモリを管理します。
GCの種類
- Serial GC: Young GenerationではCopying、Old GenerationではMark and Sweepを使用します。
- Parallel GC: 複数のスレッドを使用してGCを実行します。
- CMS GC: 並行してマークとスウィープを使用し、メモリの断片化が発生することがあります。
-
G1 GC:
- 領域ベース: ヒープを小さなリージョン単位に分割します。
- 予測可能性: 予測可能な一時停止時間を目指します。
- 混合収集: Young GenerationおよびOld Generationの両方について並行および混合収集を行います。
-
ZGC:
- 低遅延: 非常に短いSTW時間(10ms)
- 大容量ヒープ: 非常に大きなヒープで効率的に動作します。
Javaの直列化(Serialization)と逆直列化(Deserialization)
- 直列化はオブジェクトの状態をバイトストリームに変換するプロセスです。
- 逆直列化はバイトストリームを再びオブジェクトに変換するプロセスです。
オーバーロードとオーバーライド
- オーバーロード: 同じメソッド名ですが、パラメータの型や数によって異なる仕様を持つメソッドをクラス内に作ることです。
- オーバーライド: サブクラスが継承するメソッドをクラスに合わせて再実装することです。
アップキャストとダウンキャスト
- アップキャスト: スーパークラスの変数にサブクラスのオブジェクトを代入することです。
- ダウンキャスト: アップキャストされた変数の型をサブクラスに変更することです。
インターフェースと抽象クラスの違い
- 抽象クラス: abstractキーワードで宣言されているか、クラスに1つ以上の抽象メソッドが含まれているクラスです。機能拡張のために使用されます。
- インターフェース: 実装を強制するために使用され、標準化および多態性をサポートします。
JVM構造
- クラスローダー: クラスファイルをメモリにロードして初期化します。
-
ランタイムデータエリア:
- メソッドエリア: クラス構造に関する情報、定数プール、メソッドデータ、メソッドコードを保存します。
- ヒープ: GCの主要対象です。
- Javaスタック: スレッドごとに生成され、ローカル変数、オペレーションスタック、メソッドの実行状態を示すデータを含みます。
- PCレジスタ: 現在実行中のJVM命令のアドレスを保存します。
- ネイティブメソッドスタック: ネイティブメソッドを呼び出す際に使用されます。
-
実行エンジン:
- インタープリター: バイトコードを1行ずつ実行します。
- JITコンパイラ: よく実行されるバイトコードをネイティブ機械語に変換します。
- GC: ガベージコレクションを実行します。
- ネイティブメソッドインターフェース(JNI): C/C++で書かれたネイティブライブラリを使用します。
- ネイティブメソッドライブラリ: JVMが使用するネイティブライブラリで、オペレーティングシステムとの相互作用を担当します。
Compare And Swap
- V: 値を更新するメモリ位置
- A: メモリ位置Vに現在保存されていると予想する値
- B: メモリ位置Vに保存しようとする新しい値
ロックフリー同期化
-
利点:
- ロックを使用しないため、デッドロックやコンテキストスイッチングオーバーヘッドが発生しません。
- 性能向上: ロックフリーメカニズムを使用して性能ボトルネックを減らします。
-
欠点:
- ABA問題: 値が中間で変更された後、元の値に戻る場合を検出できません。
- ビジーウェイティング: CAS演算が繰り返し失敗するとCPUリソースを浪費することがあります。
###同期化 (Synchronous) と非同期化 (Asynchronous)
-
同期化:
- 作業が順次実行され、各作業が完了するまで次の作業が開始されません。
- 単純なフロー制御: 論理フローが単純で理解しやすくデバッグしやすいです。
- ブロッキング: 一つの作業が完了するまで他の作業がブロッキングされます。
-
非同期化:
- 作業が並行して実行され、一つの作業が完了するまで他の作業が実行されることができます。
- 複雑なフロー制御: 同時性問題や複雑なフロー制御が含まれることがあります。
- 非ブロッキング: 作業が非同期に実行されるため、応答性が低下しません。
==演算子とequals()メソッド
- ==演算子: 二つのオペランドが同じオブジェクトを参照しているかを比較します。基本データ型では値自体を比較します。
- equals()メソッド: オブジェクトの内容が同じかを比較します。ほとんどのJavaクラスではequals()メソッドをオーバーライドしてオブジェクトの内容比較を行います。
リフレクションの長所と短所
-
長所:
- 動的動作: ランタイムに動的にクラスをロードし、オブジェクトを生成し、メソッドを呼び出すことができ、柔軟性が高いです。
- フレームワーク開発: 多くのフレームワークがリフレクションを使用して依存性注入、オブジェクトマッピングなどの機能を実現しています。
- ツール開発: IDE、デバッガ、テストツールなどでもリフレクションを使用してコードを検査および操作できます。
-
短所:
- 性能オーバーヘッド: リフレクションは直接呼び出しよりも遅いことがあります。
- 安全性: コンパイルタイムの型チェックが不可能なためランタイムエラーが発生する可能性が高いです。
- セキュリティ制限: リフレクションを通じて機密データにアクセスできるためセキュリティ問題が発生することがあります。
セマフォとミューテックス
-
セマフォ (Semaphore):
- カウンターベース: カウンターを通じて複数のスレッドが共有リソースに同時にアクセスできるようにします。
- 非所有的: リソースを獲得したスレッドがリソースを必ず解放する必要はありません。
-
ミューテックス (Mutex):
- 二値ロック: 一度に一つのスレッドだけがリソースを占有できます。
- 所有的: リソースを獲得したスレッドがリソースを必ず解放する必要があります。
表でのまとめ
以下の表に重要な概念をまとめました:
概念 | 説明 |
---|---|
JVMの実行方式 | インタープリター方式でバイトコードを実行し、JITコンパイルで最適化 |
インタープリター方式 | バイトコードを1行ずつ実行、デバッグが速いが遅い |
コンパイラ方式 | 実行速度が速いが、コンパイルに時間がかかる |
String | 不変オブジェクト、スレッドセーフ |
StringBuffer | 可変オブジェクト、スレッドセーフ、性能低下の可能性 |
StringBuilder | 可変オブジェクト、スレッドセーフでない |
スレッドセーフ | マルチスレッド環境で実行結果が同じ |
オーバーヘッド | 追加資源や時間、同期化で待機時間が発生 |
アクセス制御修飾子 | public, protected, default, private |
クラスとオブジェクト | クラスは設計図、オブジェクトは実体 |
Call by Reference | 引数のメモリアドレスを渡す |
Call by Value | 引数の値をコピーして渡す |
OOPの特徴 | 抽象化、カプセル化、継承、多態性 |
SOLIDの原則 | 単一責任、開放閉鎖、リスコフ置換、インターフェース分離、依存性逆転 |
Non-StaticとStatic | Non-Staticはインスタンスメンバー、Staticはクラスメンバー |
ローカル変数 | メソッド内で生成、終了時に消える |
mainメソッド | public, static, void, main, String[] args |
finalキーワード | 変更不可能 |
finallyキーワード | 常に実行されるコード |
finalizeキーワード | ガベージコレクタが削除決定時に呼び出し |
Genericとテンプレート | Genericは型検査、テンプレートはインスタンス化 |
GCの種類 | Serial, Parallel, CMS, G1, ZGC |
GCアルゴリズム | Mark and Sweep, Copying, Generational |
直列化と逆直列化 | オブジェクトをバイトストリームに変換、逆変換 |
オーバーロードとオーバーライド | 同じメソッド名、異なる仕様、再実装 |
アップキャストとダウンキャスト | スーパークラスからサブクラスに変更 |
インターフェースと抽象クラス | 実装強制、標準化、多態性 |
JVM構造 | クラスローダー、ランタイムデータエリア、実行エンジン |
Compare And Swap | メモリ位置、予想値、新しい値 |
ロックフリー同期化 | デッドロックなし、性能向上、ABA問題 |
同期化と非同期化 | 順次実行、並行実行 |
==演算子とequals()メソッド | オブジェクト参照、内容比較 |
リフレクション | 動的動作、性能オーバーヘッド、セキュリティ制限 |
セマフォとミューテックス | カウンター、非所有的、二値ロック、所有的 |