🍣

Javaの基礎知識まとめ

に公開

基礎概念

Javaとは?

Javaは、世界中で幅広く利用されているプログラミング言語です。
1995年にSun Microsystems(現在はOracleが管理)から公開され、現在も進化を続けています。
また、Javaは「安定して長く使える」「どこでも動く」「大規模開発に強い」という点から、
今でも現役で使われ続けている言語です。
以下がJavaの特徴です。

特徴

  • プラットフォームに依存しない
    「一度書けば、どこでも動く(Write Once, Run Anywhere)」を掲げ、Windows・macOS・Linuxなど様々な環境で実行可能です。

  • オブジェクト指向言語
    クラスやオブジェクトを中心にプログラムを構築でき、拡張性や再利用性が高いです。

  • 用途が幅広い
    Webアプリケーション、業務システム、モバイルアプリ(特にAndroid)、IoT機器など、多くの分野で利用されています。

変数/型

Javaでは、データを扱うために変数を使います。変数には必ず型(データ型)を指定する必要があり、どのようなデータを扱うかを明確にします。

主な型

  • プリミティブ型(基本型)
    数値や真偽値などを直接扱う型
    • 整数: int, long
    • 小数: float, double
    • 文字: char
    • 真偽値: boolean
// プリミティブ型(基本型)
// 整数型
byte smallNumber = 10;      // 8ビット整数
short mediumNumber = 1000;  // 16ビット整数
int age = 25;               // 32ビット整数
long bigNumber = 100000L;   // 64ビット整数

// 小数型
float taxRate = 8.5f;       // 単精度浮動小数点
double price = 99.9;        // 倍精度浮動小数点

// 文字型
char grade = 'A';            // 単一文字

// 真偽値
boolean isActive = true;     // true or false
  • 参照型
    オブジェクトを参照する型
    • 例: String, 配列、クラス
// 参照型
String name = "Java";        // 文字列
Integer numberObject = 25;   // プリミティブ型をラップするオブジェクト型
Double priceObject = 99.9;   // 同上
Boolean activeObject = true; // 同上

演算子

Javaの演算子は、値や変数に対して計算や比較を行うための記号です。
大きく分けて「算術演算子(計算)」「比較演算子(条件判定)」「論理演算子(真偽の組み合わせ)」「代入演算子(値を代入・更新)」「その他(便利な特殊演算子)」があります。

1. 算術演算子(数値の計算)

演算子 説明
+ 足し算 5 + 3 → 8
- 引き算 5 - 3 → 2
* 掛け算 5 * 3 → 15
/ 割り算 6 / 3 → 2
% 余り 7 % 3 → 1
++ インクリメント(1増える) i++
-- デクリメント(1減る) i--

2. 比較演算子(値の比較)

演算子 説明
== 等しい a == b
!= 等しくない a != b
> より大きい a > b
< より小さい a < b
>= 以上 a >= b
<= 以下 a <= b

3. 論理演算子(真偽値の組み合わせ)

演算子 説明
&& AND(両方 true なら true) a && b
|| OR(どちらか true なら true) a || b
! NOT(反転) !a

4. 代入演算子

演算子 説明
= 代入 x = 5
+= 足して代入 x += 3 → x = x + 3
-= 引いて代入 x -= 2 → x = x - 2
*= 掛けて代入 x *= 4 → x = x * 4
/= 割って代入 x /= 2 → x = x / 2
%= 余りを代入 x %= 3 → x = x % 3

5. その他の便利演算子

演算子 説明
?: 三項演算子 result = (a > b) ? a : b
instanceof 型チェック obj instanceof String

if

if条件に応じて処理を分岐させるための構文 です。
条件が true の場合だけ、特定の処理を実行できます。
elseelse if と組み合わせることで、複数の条件分岐も可能です。

int score = 75;

if (score >= 90) {
    System.out.println("評価: A"); // 実行されない
} else if (score >= 70) {
    System.out.println("評価: B"); // ← ここが実行される
} else if (score >= 50) {
    System.out.println("評価: C"); // 実行されない
} else {
    System.out.println("評価: D"); // 実行されない
}

switch

switch変数の値に応じて処理を分岐させる構文 です。
if の複数条件分岐をスッキリ書きたいときに便利です。
case ごとに処理を分け、break で分岐を終了します。
default はどの case にも該当しない場合に実行されます。

int day = 3;
String dayName;

switch (day) {
    case 1:
        dayName = "月曜日";
        break;
    case 2:
        dayName = "火曜日";
        break;
    case 3:
        dayName = "水曜日";
        break;
    case 4:
        dayName = "木曜日";
        break;
    case 5:
        dayName = "金曜日";
        break;
    default:
        dayName = "休日";
        break;
}

System.out.println(dayName); // 実行結果: 水曜日

for

for文繰り返し処理を行うための構文 です。
回数が決まっている繰り返しに向いており、初期化・条件判定・増減を1行でまとめて書けます。

// i を 1 で初期化。i <= 5 の間ループ。i++ はループごとに i を1増やす
for (int i = 1; i <= 5; i++) { 
    System.out.println("i = " + i); // i の値を出力
    // 実行結果:
    // 1回目: i = 1
    // 2回目: i = 2
    // 3回目: i = 3
    // 4回目: i = 4
    // 5回目: i = 5
}
// ループ終了後、i = 6 で条件 i <= 5 が false になりループを抜ける

while

while文条件が true の間、処理を繰り返す構文 です。
回数が決まっていない場合や、条件次第で繰り返しを止めたい場合に使います。

int i = 1;               // 初期化
while (i <= 5) {          // 条件判定: i が 5 以下ならループ
    System.out.println("i = " + i); // i の値を出力
    i++;                  // i を 1 増やす
    // 実行結果:
    // 1回目: i = 1
    // 2回目: i = 2
    // 3回目: i = 3
    // 4回目: i = 4
    // 5回目: i = 5
}
// i = 6 で条件 i <= 5 が false になりループ終了

コレクション

コレクションは 複数のデータをまとめて扱うためのオブジェクト です。
Javaでは配列だけでなく、ListSetMap などのデータ構造が用意されており、データの追加・削除・検索などが簡単に行えます。

配列

配列は 同じ型の複数のデータをまとめて管理するためのデータ構造 です。

  • 要素数は固定で、作成時にサイズを決める必要があります
  • インデックス(0から始まる番号)で各要素にアクセス可能

宣言と初期化は用途に応じて以下のようにいくつかの方法があります。

// 方法1
int[] numbers = {10, 20, 30, 40, 50};

// 方法2
int[] numbers = new int[5];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
numbers[3] = 40;
numbers[4] = 50;

// 方法3
int[] numbers;
numbers = new int[]{10, 20, 30, 40, 50};

以下のように宣言した配列にアクセスできます。

// 配列の宣言と初期化
int[] numbers = {10, 20, 30, 40, 50};

// 要素にアクセス
System.out.println(numbers[0]); // 10
System.out.println(numbers[3]); // 40

// 要素の変更
numbers[2] = 35; 
System.out.println(numbers[2]); // 35

List

List同じ型の複数の要素を順序付きで管理できるコレクション です。

  • 配列と違い、サイズが可変 で要素の追加・削除が簡単にできる
  • 要素は インデックス(0から始まる番号)でアクセス 可能
  • 重複する値を持つこともできる

通常は ArrayListLinkedList などの具象クラスをインスタンス化して使用します。

import java.util.ArrayList;
import java.util.List;

// Listの宣言と初期化(ArrayListを使用)
List<String> fruits = new ArrayList<>();

// 要素の追加
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
fruits.add("Apple"); // 重複も可能

// 要素へのアクセス
System.out.println(fruits.get(1)); // "Banana"

// 要素の削除
fruits.remove(0); // "Apple"を削除

// Listのサイズを取得
System.out.println(fruits.size()); // 3

// 拡張for文で全要素にアクセス
for (String fruit : fruits) {
    System.out.println(fruit); // "Banana", "Orange", "Apple" の順で表示
}

Set

Set重複する値を持たない要素の集まりを管理するコレクション です。

  • 要素の重複を許さない
  • 順序が保証されないHashSet の場合)
  • 特定の要素が含まれているかを高速に確認できる

数学の集合(セット)に似た性質を持ちます。
HashSetLinkedHashSet などの具象クラスを使って実装します。

import java.util.HashSet;
import java.util.Set;

// Setの宣言と初期化(HashSetを使用)
Set<String> colors = new HashSet<>();

// 要素の追加
colors.add("Red");
colors.add("Blue");
colors.add("Green");

// 重複した要素を追加しようとしても無視される
colors.add("Red");

// 要素が含まれているか確認
System.out.println(colors.contains("Blue")); // true

// Setのサイズを取得
System.out.println(colors.size()); // 3

// 拡張for文で全要素にアクセス(順序は保証されない)
for (String color : colors) {
    System.out.println(color); // "Red", "Green", "Blue" など(順不同)
}

Map

Mapキー(Key)と値(Value)のペアでデータを管理するコレクション です。

  • キーは重複を許さない(一意である必要がある)
  • キーを使って、対応する値に高速にアクセスできる
  • 順序が保証されないHashMap の場合)

辞書のように、単語(キー)を引くと意味(値)が出てくるイメージです。
HashMapLinkedHashMap などの具象クラスを使って実装します。

import java.util.HashMap;
import java.util.Map;

// Mapの宣言と初期化(HashMapを使用)
Map<String, Integer> scoreMap = new HashMap<>();

// 要素の追加 (キー, 値)
scoreMap.put("Alice", 90);
scoreMap.put("Bob", 75);
scoreMap.put("Charlie", 88);

// 同じキーで追加すると値が上書きされる
scoreMap.put("Alice", 95);

// キーを使って値を取得
System.out.println(scoreMap.get("Bob")); // 75

// キーを指定して要素を削除
scoreMap.remove("Charlie");

// キーの一覧を取得して、すべてのキーと値にアクセス
for (String name : scoreMap.keySet()) {
    System.out.println(name + ": " + scoreMap.get(name));
    // "Alice: 95", "Bob: 75" など(順不同)
}

オブジェクト指向

オブジェクト指向は、現代のソフトウェア開発において広く採用されている考え方(プログラミングパラダイム)の一つです。現実世界の「モノ」が持つ属性(データ)と振る舞い(機能)をひとまとめにした「オブジェクト」として捉え、オブジェクト同士の相互作用としてシステムを設計します。

この考え方を用いることで、プログラムを部品のように組み立てることができ、再利用性が高く、メンテナンスしやすいソフトウェアを効率的に開発できます。

クラスとオブジェクト

オブジェクト指向の最も基本的な概念が「クラス」と「オブジェクト」です。

  • クラス (Class)
    オブジェクトの設計図に例えられます。クラスには、オブジェクトが持つべきデータ(フィールド)と、そのデータを操作するための機能(メソッド)が定義されています。
  • オブジェクト (Object / Instance)
    クラスという設計図をもとに作られた実体です。
    一つのクラスから、異なるデータを持つ複数のオブジェクトを生成できます。

// 車の「設計図」であるクラス
class Car {
    // フィールド(データ)
    String color;
    int speed;

    // メソッド(機能)
    void accelerate() {
        speed += 10;
        System.out.println("スピードが10km/h上がりました。現在の速度: " + speed + "km/h");
    }
}

// クラスからオブジェクトを生成する
public class Main {
    public static void main(String[] args) {
        // Carクラスから「myCar」というオブジェクトを生成
        Car myCar = new Car();
        myCar.color = "赤";
        myCar.speed = 0;
        
        System.out.println("私の車の色は" + myCar.color + "です。"); // 私の車の色は赤です。
        myCar.accelerate(); // スピードが10km/h上がりました。現在の速度: 10km/h
    }
}

コンストラクタ

コンストラクタは、オブジェクトが生成されるときに自動的に呼び出される特別なメソッドです。
主な役割は、オブジェクトのフィールドを初期化することです。

  • クラス名と同じ名前を持つ
  • 戻り値を指定しない

class Car {
    String color;

    // コンストラクタ
    public Car(String c) {
        System.out.println("コンストラクタが呼び出されました。");
        color = c; // 引数で受け取った値でフィールドを初期化
    }
}

public class Main {
    public static void main(String[] args) {
        // new Car("青")のタイミングでコンストラクタが実行される
        Car myCar = new Car("青"); 
        System.out.println("車の色は" + myCar.color + "です。"); // 車の色は青です。
    }
}

カプセル化

カプセル化は、オブジェクト指向の三大要素の一つで、データ(フィールド)とそれを操作するメソッドを一つにまとめ、オブジェクトの内部構造を外部から隠すことを指します。

これにより、外部からデータが不正に書き換えられることを防ぎ、オブジェクトの独立性と安全性を高めます。これを実現するための具体的な仕組みが、次の「アクセス指定子」です。

アクセス指定子

アクセス指定子は、フィールドやメソッドに外部からどれだけアクセスできるかを制限するキーワードです。

指定子 説明
public どこからでもアクセス可能。
protected 同じパッケージと、別のパッケージのサブクラスからアクセス可能。
(指定なし) 同じパッケージ内からのみアクセス可能。
private 同じクラス内からのみアクセス可能。外部からは完全に隠蔽される。

カプセル化を実現するため、通常フィールドは private にして、
そのフィールドを操作するための public なメソッド(ゲッター/セッター)を公開します。

class Student {
    // フィールドをprivateで隠蔽
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    // scoreを取得するための公開メソッド(ゲッター)
    public int getScore() {
        return this.score;
    }

    // scoreを設定するための公開メソッド(セッター)
    public void setScore(int score) {
        if (score >= 0 && score <= 100) {
            this.score = score; // 0〜100点の場合のみ値を設定
        } else {
            System.out.println("不正な点数です。");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Student s = new Student("Taro", 80);
        // s.score = -10; // コンパイルエラー! privateなので直接アクセスできない
        
        s.setScore(-10); // 不正な点数です。
        System.out.println("点数: " + s.getScore()); // 点数: 80
    }
}

継承 (Inheritance)

継承は、既存のクラス(親クラス/スーパークラス)の性質を引き継いだ新しいクラス(子クラス/サブクラス)を作ることができる仕組みです。

  • コードの再利用: 親クラスのコードを再利用できるため、開発効率が向上します。
  • 階層構造: 「スポーツカーは、車の一種である」といった現実世界の階層関係を表現できます。

// 親クラス
class Animal {
    void eat() {
        System.out.println("食事をします。");
    }
}

// Animalクラスを継承した子クラス
class Dog extends Animal {
    void bark() {
        System.out.println("ワン!と吠えます。");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.eat(); // 親クラスのメソッドを呼び出せる
        myDog.bark(); // 自分のクラスのメソッドを呼び出せる
    }
}

ポリモーフィズム(多様性 / 多態性)

ポリモーフィズムは、同じ型の変数や同じ名前のメソッドが、状況に応じて異なる振る舞いをすることを指します。継承関係において、親クラスの型の変数に子クラスのオブジェクトを代入することで実現されます。

これにより、オブジェクトの種類をいちいち判別しなくても、共通のインターフェースでそれらを操作できるようになり、柔軟で拡張性の高いコードを書くことができます。

class Animal {
    void cry() {
        System.out.println("動物が鳴きます。");
    }
}
class Dog extends Animal {
    void cry() { // 親クラスのメソッドを上書き(オーバーライド)
        System.out.println("ワン!");
    }
}
class Cat extends Animal {
    void cry() { // 親クラスのメソッドを上書き(オーバーライド)
        System.out.println("ニャー!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal a1 = new Dog(); // 親クラスの変数に子クラスのオブジェクトを代入
        Animal a2 = new Cat();

        a1.cry(); // "ワン!" と表示される
        a2.cry(); // "ニャー!" と表示される
        // 同じ cry() メソッドの呼び出しでも、実際のオブジェクトの種類によって結果が変わる
    }
}

オーバーライドとオーバーロード

オーバーライド (Override) オーバーロード (Overload)
場所 親クラスと子クラスの間 同じクラス内
目的 親クラスのメソッドの振る舞いを、子クラスで**再定義(上書き)する。 同じ名前で引数が異なる**メソッドを複数定義し、利便性を高める。
条件 メソッド名、引数の型と数、戻り値の型がすべて同じ。 メソッド名は同じだが、引数の型、数、順番のいずれかが異なる。
  • オーバーライドの例: 上記ポリモーフィズムの例で、DogクラスとCatクラスがAnimalクラスのcry()メソッドを再定義しているのがオーバーライドです。
  • オーバーロードの例:
    class Calculator {
        int add(int a, int b) {
            return a + b;
        }
        double add(double a, double b) { // 引数の型が違う
            return a + b;
        }
        int add(int a, int b, int c) { // 引数の数が違う
            return a + b + c;
        }
    }
    

抽象クラス (Abstract Class)

抽象クラスは、インスタンス化できない、不完全なクラスです。継承されることを前提としており、子クラスに共通の機能や骨格を定義するために使います。

  • abstract キーワードを付けて定義する。
  • 具体的な処理内容を持たない抽象メソッドabstractメソッド)を持つことができる。
  • 抽象クラスを継承した子クラスは、必ずすべての抽象メソッドをオーバーライドしなければならない。

// 抽象クラス
abstract class Figure {
    // 抽象メソッド(処理内容は子クラスで定義する)
    abstract double getArea();

    // 通常のメソッドも持てる
    void display() {
        System.out.println("これは図形です。");
    }
}

// 抽象クラスを継承
class Circle extends Figure {
    double radius;
    
    // 抽象メソッドの実装を強制される
    @Override
    double getArea() {
        return radius * radius * 3.14;
    }
}

インタフェース (Interface)

インタフェースは、メソッドのシグネチャ(名前、引数、戻り値の型)だけを定義した、完全な抽象です。クラスが持つべき機能の「契約」や「仕様」を定める役割を果たします。

  • interface キーワードを使って定義する。
  • クラスは複数のインタフェースを実装(implements)できる(クラスの継承は一つのみ)。
  • 「〜できる」といった能力(振る舞い)をクラスに追加したい場合によく使われる。

// インタフェースの定義
interface Swimmable {
    void swim(); // public abstract が自動で付与される
}

// PersonクラスはSwimmableインタフェースを実装
class Person implements Swimmable {
    @Override
    public void swim() {
        System.out.println("クロールで泳ぎます。");
    }
}

class Fish implements Swimmable {
    @Override
    public void swim() {
        System.out.println("ヒレを使ってスイスイ泳ぎます。");
    }
}

静的メンバ (Static Members)

フィールドやメソッドに static キーワードを付けると、それらはインスタンスではなくクラスに属するものとして扱われます。

インスタンスメンバ(staticなし) 静的メンバ(staticあり)
所属 各オブジェクト(インスタンス)に所属 クラスに所属
メモリ オブジェクトごとにメモリが確保される クラスに一つだけ。全オブジェクトで共有
アクセス オブジェクト変数.メンバ クラス名.メンバ

アプリケーション全体で共有したい定数や、特定のオブジェクトの状態に依存しないユーティリティメソッドなどに使われます。

class Circle {
    // 静的フィールド(定数)
    public static final double PI = 3.14159;
    
    // 静的カウンタ
    private static int circleCount = 0;
    
    public Circle() {
        circleCount++; // インスタンスが作られるたびにカウントアップ
    }
    
    // 静的メソッド
    public static int getCircleCount() {
        return circleCount;
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("円周率: " + Circle.PI); // クラス名でアクセス
        
        System.out.println("作成された円の数: " + Circle.getCircleCount()); // 0
        
        Circle c1 = new Circle();
        Circle c2 = new Circle();
        
        System.out.println("作成された円の数: " + Circle.getCircleCount()); // 2
    }
}

Discussion