継承(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基礎は完了です。次は実践編でファイル操作やエラー処理を学びましょう。