チュートリアル

Java基礎:継承とインターフェース

Java入門オブジェクト指向継承
広告エリア

継承(extends)

// 親クラス(スーパークラス)
public class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void speak() {
        System.out.println(name + "が鳴いています");
    }

    public void move() {
        System.out.println(name + "が移動しています");
    }
}

// 子クラス(サブクラス)
public class Dog extends Animal {
    private String breed;

    public Dog(String name, String breed) {
        super(name);  // 親のコンストラクタを呼び出し
        this.breed = breed;
    }

    // メソッドのオーバーライド
    @Override
    public void speak() {
        System.out.println(name + "がワンワン鳴いています");
    }

    // 新しいメソッド
    public void fetch() {
        System.out.println(name + "がボールを取ってきます");
    }

    public String getBreed() {
        return breed;
    }
}

// 使用
Dog dog = new Dog("ポチ", "柴犬");
dog.speak();   // "ポチがワンワン鳴いています"
dog.move();    // "ポチが移動しています"(継承)
dog.fetch();   // "ポチがボールを取ってきます"

super キーワード

public class Vehicle {
    protected int speed;

    public Vehicle(int speed) {
        this.speed = speed;
    }

    public String getInfo() {
        return "速度: " + speed + "km/h";
    }
}

public class Car extends Vehicle {
    private String brand;

    public Car(String brand, int speed) {
        super(speed);  // 親のコンストラクタ
        this.brand = brand;
    }

    @Override
    public String getInfo() {
        // 親のメソッドを呼び出して拡張
        return brand + " - " + super.getInfo();
    }
}

Car car = new Car("トヨタ", 120);
System.out.println(car.getInfo());  // "トヨタ - 速度: 120km/h"

抽象クラス

インスタンス化できない、継承専用のクラスです。

public abstract class Shape {
    protected String color;

    public Shape(String color) {
        this.color = color;
    }

    // 抽象メソッド(サブクラスで実装必須)
    public abstract double area();
    public abstract double perimeter();

    // 通常のメソッド
    public void printInfo() {
        System.out.println("色: " + color);
        System.out.println("面積: " + area());
        System.out.println("周囲: " + perimeter());
    }
}

public class Rectangle extends Shape {
    private double width;
    private double height;

    public Rectangle(String color, double width, double height) {
        super(color);
        this.width = width;
        this.height = height;
    }

    @Override
    public double area() {
        return width * height;
    }

    @Override
    public double perimeter() {
        return 2 * (width + height);
    }
}

public class Circle extends Shape {
    private double radius;

    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }

    @Override
    public double perimeter() {
        return 2 * Math.PI * radius;
    }
}

インターフェース

public interface Printable {
    void print();
}

public interface Saveable {
    void save(String filename);
    default void autoSave() {  // デフォルトメソッド
        save("autosave.dat");
    }
}

// 複数のインターフェースを実装
public class Document implements Printable, Saveable {
    private String content;

    public Document(String content) {
        this.content = content;
    }

    @Override
    public void print() {
        System.out.println(content);
    }

    @Override
    public void save(String filename) {
        System.out.println(filename + "に保存しました");
    }
}

Document doc = new Document("Hello, World!");
doc.print();
doc.save("document.txt");
doc.autoSave();

関数型インターフェース

@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);
}

// ラムダ式で実装
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;

System.out.println(add.calculate(3, 5));       // 8
System.out.println(multiply.calculate(3, 5));  // 15

ポリモーフィズム

public abstract class Employee {
    protected String name;
    protected double baseSalary;

    public Employee(String name, double baseSalary) {
        this.name = name;
        this.baseSalary = baseSalary;
    }

    public abstract double calculateSalary();

    public void printSalary() {
        System.out.println(name + ": " + calculateSalary() + "円");
    }
}

public class FullTimeEmployee extends Employee {
    private double bonus;

    public FullTimeEmployee(String name, double baseSalary, double bonus) {
        super(name, baseSalary);
        this.bonus = bonus;
    }

    @Override
    public double calculateSalary() {
        return baseSalary + bonus;
    }
}

public class PartTimeEmployee extends Employee {
    private int hoursWorked;
    private double hourlyRate;

    public PartTimeEmployee(String name, int hoursWorked, double hourlyRate) {
        super(name, 0);
        this.hoursWorked = hoursWorked;
        this.hourlyRate = hourlyRate;
    }

    @Override
    public double calculateSalary() {
        return hoursWorked * hourlyRate;
    }
}

// ポリモーフィズムで処理
List<Employee> employees = List.of(
    new FullTimeEmployee("太郎", 300000, 50000),
    new PartTimeEmployee("花子", 80, 1200),
    new FullTimeEmployee("次郎", 280000, 40000)
);

for (Employee emp : employees) {
    emp.printSalary();  // 各サブクラスのcalculateSalary()が呼ばれる
}

instanceofとパターンマッチング

public void processShape(Shape shape) {
    // 従来の方法
    if (shape instanceof Circle) {
        Circle circle = (Circle) shape;
        System.out.println("円: 半径 " + circle.getRadius());
    }

    // パターンマッチング(Java 16以降)
    if (shape instanceof Circle c) {
        System.out.println("円: 半径 " + c.getRadius());
    }

    // switchでのパターンマッチング(Java 21以降)
    switch (shape) {
        case Circle c -> System.out.println("円: " + c.area());
        case Rectangle r -> System.out.println("長方形: " + r.area());
        default -> System.out.println("その他");
    }
}

sealed クラス(Java 17以降)

継承できるクラスを制限します。

public sealed class Result permits Success, Failure {
    // 共通のメソッド
}

public final class Success extends Result {
    private Object value;
    // ...
}

public final class Failure extends Result {
    private String error;
    // ...
}

実践例:通知システム

public interface Notification {
    void send(String message);
    default void sendWithPrefix(String prefix, String message) {
        send("[" + prefix + "] " + message);
    }
}

public abstract class BaseNotification implements Notification {
    protected String recipient;

    public BaseNotification(String recipient) {
        this.recipient = recipient;
    }

    protected void log(String message) {
        System.out.println("送信: " + recipient + " - " + message);
    }
}

public class EmailNotification extends BaseNotification {
    public EmailNotification(String email) {
        super(email);
    }

    @Override
    public void send(String message) {
        log("メール: " + message);
        // メール送信処理
    }
}

public class SMSNotification extends BaseNotification {
    public SMSNotification(String phoneNumber) {
        super(phoneNumber);
    }

    @Override
    public void send(String message) {
        String shortMessage = message.length() > 160
            ? message.substring(0, 160)
            : message;
        log("SMS: " + shortMessage);
        // SMS送信処理
    }
}

public class PushNotification extends BaseNotification {
    public PushNotification(String deviceToken) {
        super(deviceToken);
    }

    @Override
    public void send(String message) {
        log("プッシュ: " + message);
        // プッシュ通知処理
    }
}

// 使用
List<Notification> notifications = List.of(
    new EmailNotification("user@example.com"),
    new SMSNotification("090-1234-5678"),
    new PushNotification("device-token-xyz")
);

for (Notification n : notifications) {
    n.send("お知らせがあります");
}

まとめ

  • extendsでクラスを継承(単一継承のみ)
  • superで親クラスにアクセス
  • abstractで抽象クラス・抽象メソッド
  • interfaceで契約を定義(多重実装可能)
  • @Overrideでオーバーライドを明示
  • instanceofとパターンマッチングで型判定
  • sealedで継承を制限

これでJava基礎は完了です。次は実践編でファイル操作やエラー処理を学びましょう。

広告エリア