Java の設計思想とエディション
Java 言語は、「一度記述すればどこでも実行可能(Write Once, Run Anywhere)」を理念として設計されています。主な特徴として、オブジェクト指向に基づく構造、高い可移植性、ガベージコレクションによるメモリ管理、そして堅牢なセキュリティ機構が挙げられます。また、マルチスレッド処理をネイティブにサポートしており、分散システム構築にも適しています。
開発プラットフォームは用途に応じて以下の 3 つに分類されます。
- Java SE (Standard Edition): デスクトップアプリや基礎的なコンソール開発向けの標準版。
- Java EE (Enterprise Edition): 大規模な Web アプリケーションやサーバーサイド開発向けの企業版。
- Java ME (Micro Edition): 組み込み機器やモバイル端末向けの限定版。
実行環境を整えるためには、JDK(Java Development Kit)のインストールが必要です。JDK には、開発ツールだけでなく、JRE(Java Runtime Environment)および JVM(Java Virtual Machine)が含まれています。インストール後は、JAVA_HOME や PATH などの環境変数を設定し、コマンドプロンプトで java -version を実行してバージョン情報を確認することで、設定の完了を検証できます。
基本構文とデータ表現
データ型と変数
Java は厳密な型付け言語であり、変数を使用する際には必ず型を宣言する必要があります。プリミティブ型(int, double, boolean など)と参照型(クラス、配列など)に大別されます。金融計算など精度が重要な場面では、浮動小数点型(float, double)ではなく BigDecimal クラスの利用が推奨されます。
型変換には、自動的な広げ変換(例:int → long)と、開発者が明示する狭め変換(キャスト)があります。狭め変換を行う際は、データ溢出に注意する必要があります。また、boolean 型へのキャストは許可されていません。
変数のスコープは以下の通りです。
- クラス変数:
staticキーワードで修飾され、クラス全体で共有されます。 - インスタンス変数: クラス内に定義され、オブジェクトごとに状態を持ちます。
- ローカル変数: メソッド内に定義され、使用前に初期化する必要があります。
命名規則では、クラス名は PascalCase、メソッドと変数は camelCase、定数は UPPER_CASE を採用するのが一般的です。
演算子とパッケージ
算術演算子(+, -, *, /, %)、代入演算子、関係演算子、論理演算子などが利用可能です。また、ビット演算や三項演算子もサポートされています。コードの整理のため、パッケージ機構が用意されており、通常はドメイン名を逆順にした文字列(例:com.example.project)をパッケージ名として使用します。ドキュメント生成には javadoc コマンドを用い、@author や @param などのタグでメタデータを記述します。
制御フローと入出力
Scanner による入力処理
標準入力からデータを読み取るには java.util.Scanner クラスを使用します。next() は空白で区切られた単語を読み取り、nextLine() は行全体を読み取ります。
import java.util.Scanner;
public class InputHandler {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("数値を連続して入力してください(終了は非数値):");
double value;
int entries = 0;
double aggregate = 0.0;
while (input.hasNextDouble()) {
value = input.nextDouble();
entries++;
aggregate += value;
}
if (entries > 0) {
System.out.println("合計値:" + aggregate);
System.out.println("入力回数:" + entries);
System.out.println("平均値:" + (aggregate / entries));
}
input.close();
}
}
条件分岐とループ
条件分岐には if 文と switch 文があります。switch 文では、byte、short、int、char のほか、Java 7 以降では String 型も利用可能です。ループ構造には while、do-while、for、および拡張 for 文(foreach)があります。循环制御には、ループを完全に抜ける break と、今回の iteration をスキップする continue が利用できます。
メソッドと処理の構造化
メソッドは特定の処理をカプセル化した単位です。修飾子、戻り値の型、メソッド名、パラメータリスト、本体で構成されます。
オーバーロードと可変長引数
同一クラス内でメソッド名が同じでも、パラメータの型や数が異なれば複数の定義が可能です(オーバーロード)。戻り値の型だけでは区別できません。また、... を使用して可変長引数を受け取ることもできます。
再帰処理
メソッドが自身を呼び出す再帰構造も可能です。ただし、終了条件(再帰頭)を明確に定義しないとスタックオーバーフローが発生します。
配列とデータ構造
配列は同じ型のデータを連続したメモリ領域に格納するコンテナです。生成時にサイズが確定し、後から変更することはできません。配列変数自体はヒープ領域に確保される参照型です。
配列操作とアルゴリズム
配列のソートや操作には java.util.Arrays クラスが役立ちます。ここでは、バブルソートと疎配列の変換例を示します。
public class ArrayUtils {
// バブルソートによる昇順整列
public static int[] sortAscending(int[] dataSet) {
int buffer;
for (int outer = 0; outer < dataSet.length - 1; outer++) {
for (int inner = 0; inner < dataSet.length - 1 - outer; inner++) {
if (dataSet[inner] > dataSet[inner + 1]) {
buffer = dataSet[inner];
dataSet[inner] = dataSet[inner + 1];
dataSet[inner + 1] = buffer;
}
}
}
return dataSet;
}
// 疎配列への変換処理
public static void compressMatrix() {
int[][] grid = new int[6][7];
grid[0][3] = 22;
grid[1][1] = 11;
grid[2][3] = -6;
// ... 他の有効値を設定 ...
int nonZeroCount = 0;
for (int[] row : grid) {
for (int val : row) {
if (val != 0) nonZeroCount++;
}
}
int[][] sparseGrid = new int[nonZeroCount + 1][3];
sparseGrid[0][0] = grid.length;
sparseGrid[0][1] = grid[0].length;
sparseGrid[0][2] = nonZeroCount;
int count = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] != 0) {
count++;
sparseGrid[count][0] = i;
sparseGrid[count][1] = j;
sparseGrid[count][2] = grid[i][j];
}
}
}
// 変換結果の出力処理は省略
}
}
オブジェクト指向プログラミング(OOP)
Java の核心はオブジェクト指向にあります。クラスを設計図とし、オブジェクトとしてデータをカプセル化します。
- カプセル化: データを隠蔽し、公開されたメソッドを通じてのみアクセスを許可することで、安全性と保守性を高めます。
- 継承:
extendsキーワードを用いて既存クラスの機能を引き継ぎます。Java は単一継承のみをサポートし、すべてのクラスの根幹にはObjectクラスが存在します。子类はsuperを通じて親クラスのコンストラクタやメソッドにアクセスできます。 - 多態性: 親クラス型の参照変数で子类オブジェクトを参照でき、実行時にオーバーライドされたメソッドが呼び出されます。
抽象クラスとインターフェース
abstract クラスは実装の一部を子类に委ねるためのテンプレートです。一方、interface は実装詳細を完全に隠蔽した契約定義であり、多重継承的な構造を実現します。
内部クラス
クラス内に別のクラスを定義する内部クラスには、メンバー内部クラス、静的内部クラス、ローカル内部クラス、匿名内部クラスなどの形式があります。
class HostClass {
private int id = 100;
public void execute() {
// ローカル内部クラス
class LocalTask {
void run() { System.out.println("ローカルタスク実行"); }
}
// 匿名内部クラス
Command action = new Command() {
public void hello() {
System.out.println("匿名インスタンスからの挨拶");
}
};
action.hello();
}
// メンバー内部クラス
public class MemberClass {
void show() {
System.out.println("外部クラス ID: " + id);
}
}
}
interface Command {
void hello();
}
例外処理機構
実行時エラーは Throwable クラスを継承するオブジェクトとして扱われます。主に、回復可能な Exception と、回復が困難な Error に分類されます。例外処理には、試行ブロック try、catch ブロック catch、最終処理 finally、および例外送出 throw、宣言 throws のキーワードが使用されます。これにより、プログラムの異常終了を防ぎ、適切なエラー処理を行うことが可能になります。