Java クラスの属性とメソッド
オブジェクト指向プログラミング(OOP)は「オブジェクト」という概念を中心に展開されます。オブジェクトは、データと振る舞いをカプセル化した独立したエンティティです。オブジェクトが保持するデータ(属性やフィールド)と、それが実行できる操作(メソッド)をどのように定義するかを理解することは、Java のオブジェクト指向プログラミングをマスターするための基礎となります。
本章では、属性とメソッドについて全面的かつ深く掘り下げていきます。前章で紹介したクラスとオブジェクトの概念に基づき、これらのオブジェクトの特徴と振る舞いをどのように定義するかをさらに詳しく学習します。
1. 属性(フィールド)の定義
属性(Attributes)は、フィールド(fields)やインスタンス変数(instance variables)とも呼ばれ、オブジェクトに関連付けられたデータを表します。これらはオブジェクトの特徴や性質を定義します。例えば、Car(自動車)オブジェクトであれば、color(色)、model(モデル)、year(年式)、currentSpeed(現在の速度)などの属性を持つことができます。
1.1 フィールドの宣言
Java でフィールドを宣言するには、クラスの定義内でデータタイプと名称を指定する必要があります。通常、フィールドはクラスの冒頭部分、クラス宣言の直後かつメソッドの前に宣言されます。
public class Car {
String color; // 車の色を保持するフィールド
String model; // 車のモデルを保持するフィールド
int year; // 車の製造年を保持するフィールド
int currentSpeed; // 車の現在の速度を保持するフィールド
}この例では:
String color;はcolorという名前のString型のフィールドを宣言しています。String model;はmodelという名前のString型のフィールドを宣言しています。int year;はyearという名前のint(整数)型のフィールドを宣言しています。int currentSpeed;はcurrentSpeedという名前のint型のフィールドを宣言しています。
1.2 アクセス修飾子
アクセス修飾子(Access Modifiers)は、フィールド(およびメソッド)の可視性とアクセス権限をコントロールします。主なアクセス修飾子は以下の通りです:
- public(パブリック): どのクラスからでもアクセス可能です。
- private(プライベート): 同じクラス内からのみアクセス可能です。
- protected(プロテクテッド): 同じクラス、サブクラス、および同じパッケージ内のクラスからアクセス可能です。
- (デフォルト): 修飾子がない場合、同じパッケージ内からのみアクセス可能です。
カプセル化(Encapsulation): 一般的に、フィールドを private として宣言することは優れたプログラミングプラクティスとされており、これによりカプセル化を強制できます。つまり、オブジェクトの内部状態は外部から隠蔽され、データが直接変更されるのを防ぎます。データのアクセスや変更は、メソッド(後述する Getter と Setter)を通じてコントロールします。
public class Car {
private String color;
private String model;
private int year;
private int currentSpeed;
}これで、color、model、year、currentSpeed は Car クラスの内部からのみ直接アクセスできるようになります。
1.3 データタイプ
フィールドは、プリミティブ型(int、double、boolean、char など)や参照型(String、配列、その他のクラス)など、あらゆる有効な Java のデータタイプを使用できます。データタイプの選択は、そのフィールドに格納するデータの種類によって決まります。
異なるデータタイプを使用した例:
public class Product {
private String name; // String:製品名を保持
private double price; // double:製品価格を保持
private int quantity; // int:在庫数量を保持
private boolean inStock; // boolean:在庫があるかどうかを表示
}1.4 フィールドの初期化
フィールドは宣言時に初期化することも、クラスのコンストラクタ(次章で解説)内で初期化することも、あるいは Setter メソッドを使用して初期化することもできます。フィールドが明示的に初期化されない場合、Java は以下のデフォルト値を割り当てます:
- 数値型(
int、doubleなど):0 - ブーリアン型(
boolean):false - 文字型(
char):\u0000(空文字) - 参照型(
String、オブジェクトなど):null
宣言時にフィールドを初期化する例:
public class Car {
private String color = "赤"; // color を "赤" で初期化
private String model = "未知"; // model を "未知" で初期化
private int year = 2023; // year を 2023 で初期化
private int currentSpeed = 0; // currentSpeed を 0 で初期化
}この例では、後から変更されない限り、作成されたすべての Car オブジェクトはこれらのデフォルト値を持ちます。
2. メソッドの定義
メソッド(Methods)はオブジェクトの振る舞い、つまりオブジェクトが実行できる操作を定義します。これらは特定のタスクを実行するコードブロックです。例えば、Car オブジェクトであれば、accelerate()(加速)、brake()(ブレーキ)、honk()(クラクション)などのメソッドを持つことができます。
2.1 メソッドの宣言
メソッドの宣言には、以下の要素が含まれます:
- アクセス修飾子: (例:
public、private、protected)メソッドの可視性を決定します。 - 戻り値の型 (Return Type): メソッドが返す値のデータタイプ。値を返さない場合は
voidを指定します。 - メソッド名: メソッドの内容を表す名称(キャメルケースに従うべきです)。
- パラメーターリスト: (任意)メソッドが入力として受け取るパラメーター(データタイプと名称)。
- メソッドボディ: 波括弧
{}で囲まれたコードブロックで、実行する命令が含まれます。
メソッドの基本構文:
アクセス修飾子 戻り値の型 メソッド名(パラメーターリスト) {
// メソッドボディ - 実行するコード
return 戻り値; // 戻り値の型が void でない場合
}Car クラスのメソッド例:
public class Car {
private String color;
private String model;
private int year;
private int currentSpeed;
// 加速メソッド
public void accelerate(int increment) {
currentSpeed += increment;
System.out.println("車が加速しました。現在の速度: " + currentSpeed);
}
// ブレーキメソッド
public void brake(int decrement) {
currentSpeed -= decrement;
if (currentSpeed < 0) {
currentSpeed = 0; // 速度がマイナスにならないようにする
}
System.out.println("ブレーキをかけました。現在の速度: " + currentSpeed);
}
// 現在の速度を取得するメソッド
public int getCurrentSpeed() {
return currentSpeed;
}
}この例では:
accelerate(int increment)はpublicメソッドで、incrementという名前のint型パラメーターを受け取り、currentSpeedフィールドの値を増加させます。値を返さないためvoid型です。brake(int decrement)はpublicメソッドで、decrementという名前のint型パラメーターを受け取り、currentSpeedの値を減少させます。これもvoid型です。getCurrentSpeed()はpublicメソッドで、パラメーターは受け取らず、int型でcurrentSpeedの現在の値を返します。
3. メソッド内でのフィールドへのアクセス
メソッド内では、フィールド名を直接使用してオブジェクトのプロパティにアクセスできます。フィールドが private である場合、読み取りと変更にはそれぞれ Getter と Setter メソッドを使用する必要があります。
3.1 Getter と Setter メソッド
Getter と Setter メソッド(アクセッサーおよびミューテーターメソッドとも呼ばれます)は、private フィールドの値にアクセスし、変更するために使用されます。これらはオブジェクト内部の状態に対して制御されたアクセスを提供し、カプセル化の原則に合致しています。
- Getter(アクセッサー)メソッド: フィールドの値を返します。命名規則は通常
get変数名()です。 - Setter(ミューテーター)メソッド: フィールドの値を設定(変更)します。命名規則は通常
set変数名(データタイプ 変数名)です。
Car クラスの color フィールドに対する Getter と Setter の例:
public class Car {
private String color;
private String model;
private int year;
private int currentSpeed;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color; // 'this' を使って引数とフィールドを区別する
}
// 他のメソッド(accelerate, brake, getCurrentSpeed)はそのまま
}この例では:
getColor()はcolorフィールドの Getter です。colorの値を返します。setColor(String color)はcolorフィールドの Setter です。colorという名前のString型パラメーターを受け取り、フィールドのcolorにその値を代入します。thisキーワードはインスタンス変数のcolorを指し、ローカル変数(引数)のcolorと区別するために使用されます。
3.2 this キーワード
this キーワードは現在のオブジェクトへの参照です。主に以下の用途で使用されます:
- インスタンス変数とローカル変数の区別: 上記の
setColorメソッドのように、メソッドの引数とインスタンス変数が同名の場合、thisを使用してインスタンス変数を特定します。 - 同じクラス内での別のコンストラクタの呼び出し(次章のコンストラクタで詳解します)。
- メソッドから現在のオブジェクトを返す。
this キーワードの用法を示す例:
public class Car {
private String color;
public Car(String color) {
this.color = color; // 'this.color' はインスタンス変数を指し、'color' はパラメーターを指す
}
public Car changeColor(String color) {
this.color = color;
return this; // 色を変更した後、現在の Car オブジェクトを返す
}
}この例では:
- コンストラクタ
Car(String color)内で、this.colorはCarオブジェクトのcolorフィールドを指し、colorはコンストラクタに渡された引数を指します。 changeColorメソッドは車の色を変更し、return this;によってCarオブジェクト自体を返します。この書き方により、メソッドチェーン(Method Chaining)が可能になります。
4. メソッドパラメーターとオーバーロード
4.1 メソッドパラメーター
メソッドはパラメーターを受け取ることができ、これらはメソッド呼び出し時に渡される値です。パラメーターを使用することで、メソッドにデータを渡し、その振る舞いをカスタマイズできます。
複数パラメーターの例:
public class Calculator {
public int add(int num1, int num2) {
return num1 + num2;
}
public double divide(double dividend, double divisor) {
if (divisor == 0) {
System.out.println("除数はゼロにできません。");
return 0; // ゼロ除算のケースを処理
}
return dividend / divisor;
}
}この例では:
addメソッドは 2 つのint型パラメーターnum1とnum2を受け取り、その和を返します。divideメソッドは 2 つのdouble型パラメーターdividend(被除数)とdivisor(除数)を受け取り、その商を返します。また、ゼロ除算を防ぐためのエラー処理も含まれています。
4.2 メソッドオーバーロード
メソッドオーバーロード(Method Overloading)は、同じクラス内で名前が同じでもパラメーターリストが異なる(パラメーターの数、データタイプ、または順序が異なる)複数のメソッドを定義することを可能にします。コンパイラは、メソッド呼び出し時に渡された引数に基づいて、実行すべきメソッドを決定します。これは非常に便利な機能であり、詳細は後続の章で扱います。
5. メソッドの呼び出し
オブジェクトのメソッドを呼び出すには、ドット演算子(.)を使用し、その後にメソッド名と括弧 () を記述します。メソッドにパラメーターが必要な場合は、括弧の中に引数を渡します。
例:
public class Main {
public static void main(String[] args) {
Car myCar = new Car("白"); // Car に適切なコンストラクタがあると仮定
myCar.setColor("青");
myCar.accelerate(50);
myCar.brake(20);
int currentSpeed = myCar.getCurrentSpeed();
System.out.println("現在の速度: " + currentSpeed);
}
}この例では:
myCar.setColor("青")はmyCarオブジェクトのsetColorメソッドを呼び出し、文字列 "青" を引数として渡しています。myCar.accelerate(50)はmyCarオブジェクトのaccelerateメソッドを呼び出し、整数 50 を引数として渡しています。myCar.brake(20)はmyCarオブジェクトのbrakeメソッドを呼び出し、整数 20 を引数として渡しています。int currentSpeed = myCar.getCurrentSpeed();はmyCarオブジェクトのgetCurrentSpeedメソッドを呼び出し、返された値を currentSpeed 変数に代入しています。
6. 総合実戦デモンストレーション
少し複雑な BankAccount(銀行口座)クラスの例を見てみましょう:
public class BankAccount {
private String accountNumber;
private String accountHolderName;
private double balance;
public BankAccount(String accountNumber, String accountHolderName) {
this.accountNumber = accountNumber;
this.accountHolderName = accountHolderName;
this.balance = 0.0; // 初期残高は 0
}
public String getAccountNumber() {
return accountNumber;
}
public String getAccountHolderName() {
return accountHolderName;
}
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println(amount + " 円を入金しました。最新残高: " + balance);
} else {
System.out.println("無効な入金額です。");
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println(amount + " 円を出金しました。最新残高: " + balance);
} else {
System.out.println("残高不足、または無効な出金額です。");
}
}
}
public class Main {
public static void main(String[] args) {
BankAccount myAccount = new BankAccount("1234567890", "田中太郎");
System.out.println("口座番号: " + myAccount.getAccountNumber());
System.out.println("口座名義: " + myAccount.getAccountHolderName());
System.out.println("初期残高: " + myAccount.getBalance());
myAccount.deposit(1000.0);
myAccount.withdraw(500.0);
System.out.println("最終残高: " + myAccount.getBalance());
}
}この BankAccount クラスは、以下のポイントを示しています:
- 属性:
accountNumber、accountHolderName、およびbalance(すべてprivate設定)。 - コンストラクタ:
accountNumberとaccountHolderNameを初期化し、初期balanceを 0 に設定します。 - Getter メソッド:
getAccountNumber()、getAccountHolderName()、およびgetBalance()が属性への読み取り専用アクセスを提供します。 - 振る舞いメソッド:
deposit(double amount)とwithdraw(double amount)が口座に対する操作を実行し、balance(残高)を変更します。