タイトル: クラスとメソッド
SEOタイトル: Java クラスとメソッド完全ガイド — フィールド・修飾子・継承
| この記事の要点 |
|
クラスの基本構造
public class User {
// フィールド (インスタンス変数)
private String name;
private int age;
// クラス変数 (static)
private static int totalCount = 0;
// 定数
public static final int MAX_AGE = 150;
// コンストラクタ
public User(String name, int age) {
this.name = name;
this.age = age;
totalCount++;
}
// インスタンスメソッド
public String greet() {
return "Hello, I'm " + this.name;
}
// static メソッド (インスタンス不要)
public static int getTotalCount() {
return totalCount;
}
// getter / setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
// 使用
User u = new User("Taro", 25);
System.out.println(u.greet()); // インスタンスメソッド
System.out.println(User.getTotalCount()); // static メソッド
System.out.println(User.MAX_AGE); // 定数
アクセス修飾子
| 修飾子 | 同一クラス | 同一パッケージ | 子クラス | 他パッケージ |
|---|---|---|---|---|
public | ✓ | ✓ | ✓ | ✓ |
protected | ✓ | ✓ | ✓ | ✗ |
| (なし) package-private | ✓ | ✓ | ✗ | ✗ |
private | ✓ | ✗ | ✗ | ✗ |
原則:
- フィールドは private (カプセル化) → getter/setter で公開
- メソッドは最小限の公開 (内部実装は private)
- クラスは public または package-private (1 ファイル 1 public クラス)
static (クラス変数 / クラスメソッド)
public class Counter {
private static int count = 0; // クラス全体で 1 つ
public static void increment() { // インスタンス不要
count++;
}
public static int get() {
return count;
}
}
Counter.increment();
Counter.increment();
System.out.println(Counter.get()); // 2
// static メソッドからインスタンス変数 / メソッドにアクセスは ★ 不可
public class Bad {
private int x; // インスタンス変数
public static void f() {
// System.out.println(x); // ★ コンパイルエラー
}
}
final (変更禁止 / 継承禁止)
// final 変数: 再代入不可
public final int MAX = 100;
// final メソッド: オーバーライド不可
public final void critical() { ... }
// final クラス: 継承不可
public final class String { ... } // String, Integer, LocalDate 等
// 引数 final
public void process(final List list) {
// list = new ArrayList<>(); // ★ NG
list.add("a"); // OK (参照先の中身は変えられる)
}
abstract クラス / インターフェース
// abstract クラス: インスタンス化不可、子で実装させる
public abstract class Shape {
public abstract double area(); // 実装なし
public void describe() { // 実装あり
System.out.println("Area = " + area());
}
}
class Circle extends Shape {
private double r;
public Circle(double r) { this.r = r; }
@Override
public double area() { return Math.PI * r * r; }
}
// interface (Java 8+ default メソッドあり)
public interface Greetable {
void greet(); // 抽象メソッド
default void hello() { System.out.println("Hi"); } // default 実装
static void info() { System.out.println("v1"); } // static
}
class Hello implements Greetable {
@Override
public void greet() { System.out.println("Hello!"); }
}
インナークラス (内部クラス)
public class Outer {
private int x = 10;
// 1. インスタンス内部クラス
public class Inner {
public int sum() { return x + 1; } // Outer の x にアクセス可
}
// 2. static ネストクラス
public static class StaticNested {
public int val = 5;
}
// 3. ローカルクラス (メソッド内)
public void method() {
class Local {
public void hi() { System.out.println(x); }
}
new Local().hi();
}
// 4. 匿名クラス
public Runnable task = new Runnable() {
@Override
public void run() { System.out.println("run"); }
};
}
// 利用
Outer o = new Outer();
Outer.Inner i = o.new Inner();
Outer.StaticNested s = new Outer.StaticNested();
record (Java 14+) — データクラスを 1 行で
// 旧来 (50 行ぐらいの boilerplate が必要)
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) { this.x = x; this.y = y; }
public int x() { return x; }
public int y() { return y; }
@Override public boolean equals(Object o) { ... }
@Override public int hashCode() { ... }
@Override public String toString() { ... }
}
// ✅ record で 1 行
public record Point(int x, int y) {}
// 自動生成されるもの:
// - private final フィールド x, y
// - public Point(int x, int y) コンストラクタ
// - x(), y() アクセサ
// - equals / hashCode / toString
Point p = new Point(1, 2);
System.out.println(p.x()); // 1
System.out.println(p); // Point[x=1, y=2]
// メソッド追加も可
public record Money(long amount, String currency) {
public Money plus(Money other) {
return new Money(amount + other.amount, currency);
}
}
sealed クラス (Java 17+)
// 「これらの子のみ許可」と明示
public sealed interface Shape permits Circle, Square, Triangle {}
public final class Circle implements Shape { ... }
public final class Square implements Shape { ... }
public final class Triangle implements Shape { ... }
// public class Pentagon implements Shape {} // ★ コンパイルエラー (permits に無い)
// switch でも網羅性チェック可
double area(Shape s) {
return switch (s) {
case Circle c -> Math.PI * c.r() * c.r();
case Square sq -> sq.a() * sq.a();
case Triangle t -> 0.5 * t.base() * t.height();
// default 不要 (Java が網羅性を保証)
};
}
メソッドの細部
| 要素 | 説明 |
|---|---|
| 戻り値の型 | void なら値を返さない |
| メソッド名 | lowerCamelCase 動詞で始める (calculateTotal) |
| 引数 | 0 個以上。final 可、varargs 可 |
| throws 句 | 検査例外を呼び出し側に通知 |
| 本体 | 波括弧 + 文の並び |
| 戻り値 | return 文 (void 以外は必須) |
public int calculateTotal(int price, int quantity, double discount) throws IllegalArgumentException {
if (quantity < 0) throw new IllegalArgumentException("quantity must be >= 0");
double total = price * quantity * (1 - discount);
return (int) total;
}
FAQ
Q: 1 つの .java ファイルに複数クラスを書ける?
A: 書けるが、public クラスは 1 つだけ でファイル名と一致が必須。残りは package-private。
Q: getter/setter は必須?
A: 慣習的に必須だが、record や DTO では不要 (自動生成 or public final で十分)。
Q: class と interface どちらを使う?
A: 「実装の共有」=>abstract class、「契約の定義」=>interface。Java 8+ では interface も default 実装を持てるので、迷ったら interface 優先。