
オブジェクト Java オブジェクトと現実世界のオブジェクトには、状態と動作という 2 つの特性があります。 たとえば、Human オブジェクトには状態 (名前、性別、寝ているかどうかなど) と動作 (Java を勉強する、歩く、話すなど) があります。Java オブジェクトはすべてその状態をフィールドに保存し、メソッドを通じてその動作を公開します。 |
カプセル化
データのカプセル化とは、内部データを外部から隠し、公開された方法を通じてのみアクセスできるようにすることです。どういう意味ですか?どのようなデータですか?誰から隠しているの?非表示とは、クラスのデータ メンバー (フィールド) への直接アクセスを制限することを意味します。Java での動作:
- フィールドは非公開になります
- クラス内の各フィールドは、ゲッターとセッターという 2 つの特別なメソッドを取得します。Getter メソッドはフィールドの値を返します。Setter メソッドを使用すると、間接的ではあるが許容可能な方法でフィールドの値を変更できます。
Java コードでのカプセル化の例:
public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test{
public static void main(String[] args) {
Student firstStudent = new Student();
firstStudent.setName("John");
// The name field is private, so you can no longer do this: firstStudent.name = "John";
}
}
なぜカプセル化を使用する必要があるのでしょうか?
主な理由は、コードの変更を容易にするためです。ホッケー スクールへの申し込みがあり、生徒の名前と学校に入学したときの年齢を保存する 2 つのフィールドを持つHockeyStudentクラスがあると想像してください。このようなもの:
public class HockeyStudent {
public String name;
public int ageOfEnrollment;
}
ageOfEnrollmentフィールドはパブリックであり、ゲッターやセッターはありません。このクラスは他の多くのクラスで使用されており、開発者が 1 つの int フィールドでは十分ではないと判断するまではすべて問題ありませんでした。コホート内の一部のホッケー選手は、他の選手よりも 1 歳近く年上なので、生まれた月に応じて 2 つのグループに分ける方が便利です。そのため、ageOfEnrollmentフィールドをint 配列 (int[][])に変更する必要があります。最初の数値は丸年を表し、2 番目の数値は月を表します。次に、 Studentクラスを使用するすべてのコードをリファクタリングする必要があります。ただし、あなたの登録年齢であれば、フィールドがプライベートで、ゲッターとセッターがある場合、すべてが簡単になります。学生の年齢設定の要件が変更された場合は、setAgeOfEnrollment()セッター メソッドのロジックを更新するだけで、クラスは問題なくStudent を引き続き使用できます。この例は多少不自然ですが、カプセル化を使用することがなぜ素晴らしいアイデアであるかを説明できれば幸いです。
継承
この原則は、実際の経験がなくても理解するのが簡単です。Don'trepeat Your Yourself (DRY) は、継承の概念のモットーになる可能性があります。継承を使用すると、親クラスのフィールドとメソッドを再定義せずに継承する子クラスを作成できます。確かに、子クラスで親クラスのフィールドとメソッドをオーバーライドすることはできますが、それは必須ではありません。さらに、子クラスに新しい状態や動作を追加できます。親クラスはスーパークラスまたは基本クラスと呼ばれることがあり、子クラスはサブクラスとして知られています。Java のextendsキーワードは、コード内で継承の原則を実装するために使用されます。Java での動作:
- 親クラスを作成します。
- extendsキーワードを使用して子クラスを作成します。
- Child クラスのコンストラクターで、super(parentField1,parentField2, ...)メソッドを使用して親のフィールドを設定します。
コンストラクターは、新しく作成されたオブジェクトを初期化するために使用される特別なメソッドです。コンストラクターの名前はクラス名と同じです。コンストラクターには、デフォルト (引数なしのコンストラクター) とパラメーター化されたコンストラクターの 2 種類があります。クラスには少なくとも 1 つのコンストラクターが必要です (他のコンストラクターが定義されていない場合は、デフォルトのコンストラクターがあります)。また、多数のコンストラクターを持つことができます。 新しいオブジェクトを作成するたびに、そのコンストラクターを呼び出します。上の例では、次の行でこれを実行します。
newキーワードを使用して、Studentクラスのデフォルトのコンストラクターtudent()を呼び出します。 |
いくつかのルール:
- 1 つのクラスは親を 1 つだけ持つことができます。
- 1 つの親クラスが多数の子クラスを持つことができます。
- 子クラスは独自の子クラスを持つことができます。
Java コードでの継承の例
Phoneクラスを作成しましょう。
public class Phone {
int price;
double weight;
// Constructor
public Phone(int price, double weight) {
this.price = price;
this.weight = weight;
}
void orderPhone(){
System.out.println("Ordering phone...");
}
}
もちろん、電話機にはさまざまなタイプがあるため、2 つの子クラスを作成しましょう。1 つは Android フォン用、もう 1 つは iPhone 用です。次に、親にはないフィールドとメソッドをいくつか追加します。そして、super()を使用してコンストラクターを呼び出し、親クラスが持つフィールドを初期化します。
Javaでの継承の例
public class Android extends Phone {
// Some new fields
String androidVersion;
int screenSize;
String secretDeviceCode;
// Constructor
public Android(int price, double weight, String androidVersion, int screenSize, String secretDeviceCode) {
super(price, weight); // Android inherits Phone’s fields
//this - reference to the current object
//super - reference to the parent object
this.androidVersion = androidVersion;
this.screenSize = screenSize;
this.secretDeviceCode = secretDeviceCode;
}
// New Android-specific method, does not exist in the Phone class
void installNewAndroidVersion() {
System.out.println("installNewAndroidVersion invoked...");
}
}
public class IPhone extends Phone {
boolean fingerPrint;
public IPhone(int price, double weight, boolean fingerPrint) {
super(price, weight);
System.out.println("IPhone constructor was invoked...");
this.fingerPrint = fingerPrint;
}
void deleteIPhoneFromDb() {
System.out.println("deleteIPhoneFromDb invoked...");
}
@Override // This is about polymorphism, see below
void orderPhone(){
System.out.println("Ordering my new iPhone and deleting the old one...");
}
}
繰り返しになりますが、Java では、継承により、親クラスのフィールドとメソッドを継承する子クラスでクラスを拡張できます。これはコードの再利用性を実現する優れた方法です。
ポリモーフィズム
ポリモーフィズムとは、オブジェクトが変形して、さまざまな形をとったり、さまざまな方法で動作したりする能力です。Java では、通常、親クラス参照を使用して子クラス オブジェクトを参照するときにポリモーフィズムが発生します。それが何を意味し、Java でどのように機能するか:
Javaのポリモーフィズムとは何ですか? 一般に、これは、同じメソッド名を異なる目的に使用できることを意味します。Java には、メソッド オーバーライド (動的ポリモーフィズム) とメソッド オーバーロード (静的ポリモーフィズム) の 2 種類のポリモーフィズムがあります。メソッドのオーバーライド
子クラスで親クラスのメソッドをオーバーライドして、強制的に別の方法で動作させることができます。play()メソッドを使用してMusician親クラスを作成しましょう。Java コードにおけるポリモーフィズムの例
public class Musician {
String name;
int age;
// Default constructor
public Musician() {
}
// Parameterized constructor
public Musician(String name, int age) {
this.name = name;
this.age = age;
}
void play() {
System.out.println("I am playing my instrument...");
}
}
さまざまなミュージシャンがさまざまな楽器を使用します。PianistとViolinistという 2 つの子クラスを作成しましょう。ポリモーフィズムのおかげで、それぞれが独自のバージョンのplay()メソッドを実行します。オーバーライドする場合は@Overrideアノテーションを使用できますが、必須ではありません。
public class Pianist extends Musician {
String favoritePianoType;
public Pianist(String name, int age, String favoritePianoType) {
super(name, age);
this.favoritePianoType = favoritePianoType;
}
@Override
void play(){
System.out.println("I am playing the piano...");
}
}
ヴァイオリン奏者はソリストまたはオーケストラのメンバーである可能性があります。play()メソッドをオーバーライドするときは、このことを考慮してみましょう。
public class Violinist extends Musician {
boolean isSoloist;
public Violinist(String name, int age, boolean isSoloist) {
super(name, age);
this.isSoloist = isSoloist;
}
@Override
void play(){
if (isSoloist)
System.out.println("I am playing the violin solo...");
else
System.out.println("I am playing the violin in an orchestra...");
}
}
Demoクラス を作成しましょう。このクラスでは、以前に作成した各クラスのインスタンスを 1 つずつ含む 3 つのオブジェクトを作成します。どのような結果が得られるか見てみましょう。
public class Demo {
public static void main(String[] args) {
Musician musician = new Musician();
Violinist violinist = new Violinist("John", 32, true);
Pianist pianist = new Pianist("Glen", 30, "Acoustic");
System.out.println("Musician said:");
musician.play();
System.out.println("Violinist said:");
violinist.play();
System.out.println("Pianist said:");
pianist.play();
}
}
得られるものは次のとおりです。
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo…
Pianist said:
I am playing the piano...
すべてのヴァイオリニストやピアニストは音楽家ですが、すべての音楽家がヴィオリストやピアニストであるわけではありません。つまり、新しい演奏メソッドを作成する必要がない場合は、ミュージシャンの演奏メソッドを使用できるということです。または、 superキーワードを使用して、子から親のメソッドを呼び出すこともできます。Pianist のコードでそれをやってみましょう:
public class Pianist extends Musician {
String favoritePianoType;
@Override
void play(){
super.play();
System.out.println("I am playing the piano...");
}
}
次に、 Demoクラスでmain()メソッド を呼び出してみましょう。結果は次のとおりです。
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...
メソッドのオーバーロード
メソッドのオーバーロードとは、同じクラス内で同じ名前のさまざまなメソッドを使用することを意味します。それらは、パラメータの数、順序、またはタイプの点で異なっていなければなりません。ピアニストはアコースティック ピアノとエレクトリック ピアノを演奏できるとします。エレキを演奏するには、音楽家が電気を必要とします。2 つの異なるplay()メソッドを作成してみましょう。1 つ目はパラメーターなしでアコースティック ピアノ用で、2 つ目は電気が利用可能かどうかを示すパラメーターが含まれています。
public class Pianist extends Musician {
String name;
int age;
String favoritePianoType;
@Override
void play(){
super.play();
System.out.println("I am playing the piano...");
}
void play(boolean isElectricity){
if (isElectricity) {
System.out.println("The electricity is on.");
System.out.println("I am playing the piano...");
}
else System.out.println("I can't play this without electricity.");
}
}
ちなみに、最初のplay()メソッドを 2 番目のplay(boolean)メソッド内で次のように使用できます。
void play(boolean isElectricity){
if (isElectricity) {
System.out.println("The electricity is on.");
play();
}
else System.out.println("I can't play this without electricity.");
}
オーバーロードを示すために Demoクラス にいくつかの行を追加してみましょう。
public class Demo {
public static void main(String[] args) {
Musician musician = new Musician();
Violinist violinist = new Violinist("John", 23, true);
Pianist pianist = new Pianist("Glen", 30, "Acoustic");
System.out.println("Musician said:");
musician.play();
System.out.println("Violinist said:");
violinist.play();
System.out.println("Pianist said:");
pianist.play();
System.out.println("The pianist will now try the electric piano:");
pianist.play(true);
System.out.println("The electricity has been shut off. Now when trying the electric piano, the pianist says:");
pianist.play(false);
}
}
結果は次のとおりです。
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...
The pianist will now try the electric piano:
The electricity is on.
I am playing my instrument...
I am playing the piano...
The electricity has been shut off. Now when trying the electric piano, the pianist says:
I can't play this without electricity.
Java は、パラメータとオブジェクト タイプに基づいて、どのメソッドを使用する必要があるかを認識します。それがポリモーフィズムです。
抽象化
クラスを定義するとき、私たちは何かのモデルを構築しようとしています。たとえば、さまざまなレースカーを使用した MyRacer というビデオ ゲームを作成しているとします。プレイヤーはそのうちの 1 つを選択し、後で更新するか、別のものを購入することができます。それで…車とは何ですか?車は非常に複雑なものですが、レース ビデオ ゲーム (ドライビング シミュレーターとは対照的に) を作成しようとしている場合、車に含まれる何千ものギアやガスケットをすべて説明する必要はありません。必要なのはモデル、最高速度、操縦性特性、価格、色…そしておそらくそれだけで十分でしょう。それが私たちのゲームの車のモデルです。MyRacer 2 の後半で、道路上のハンドリングに影響を与えるタイヤを追加することにしたとします。ここでは、詳細を追加したため、モデルが異なります。させて' ■ データ抽象化を、オブジェクトの重要な (または必要な) 特性のみを識別し、無関係な詳細を無視するプロセスとして定義します。抽象化にはさまざまなレベルがあります。たとえば、あなたがバスの乗客の場合、バスがどのようなもので、どこへ行くのかを知る必要がありますが、運転方法を知る必要はありません。あなたがバスの運転手であれば、新しいバスの作成方法を知る必要はありません。知っていればよいのは、バスの運転方法だけです。ただし、バス メーカーの場合は、バス設計の詳細が非常に重要であるため、より低い抽象レベルに進む必要があります。私の言いたいことを理解していただければ幸いです。バスがどのようなもので、どこへ行くのかを知る必要がありますが、運転方法を知る必要はありません。あなたがバスの運転手であれば、新しいバスの作成方法を知る必要はありません。知っていればよいのは、バスの運転方法だけです。ただし、バス メーカーの場合は、バス設計の詳細が非常に重要であるため、より低い抽象レベルに進む必要があります。私の言いたいことを理解していただければ幸いです。バスがどのようなもので、どこへ行くのかを知る必要がありますが、運転方法を知る必要はありません。あなたがバスの運転手であれば、新しいバスの作成方法を知る必要はありません。知っていればよいのは、バスの運転方法だけです。ただし、バス メーカーの場合は、バス設計の詳細が非常に重要であるため、より低い抽象レベルに進む必要があります。私の言いたいことを理解していただければ幸いです。Java での動作:
Java または OOP で、最低 (最も具体的な) から最高 (最も抽象的な) まで 4 つの抽象レベルを構築してみましょう。-
最低レベルの抽象化は特定のオブジェクトです。これは、特定のクラスに属する一連の特性を持つエンティティです。特定のフィールド値があります
-
オブジェクトを作成するためのテンプレートがクラスです。これは、同様のプロパティと内部構造を持つオブジェクトのセットの説明です。
-
抽象クラスは、クラスのセットの特性を抽象的に記述したものです (他のクラスによる継承のテンプレートとして機能します)。高度な抽象化を備えているため、抽象クラスから直接オブジェクトを作成することはできません。オブジェクトの作成に使用できるのは、抽象クラスの子クラスのみです。抽象クラスには実装を伴うメソッドが含まれる場合がありますが、これは必須ではありません。
-
インターフェイスは、抽象パブリック メソッドと静的定数フィールド (final static) のみを含む Java プログラミング言語構造の構造です。つまり、抽象クラスもインターフェイスもオブジェクトの生成には使用できません。
Java コードのインターフェイスの例
interface Human {
public void struggle();
public void protect();
}
interface Vulcan {
int angleOfPointyEars;
public void turnOffEmotions(boolean isOn);
public void telepathy();
}
複数のインターフェースを実装できます
The Spock class implements Human and Vulcan {
public void struggle() {
System.out.println("I am struggling...");
}
public void protect() {
System.out.println("You are under my protection!”);
}
public void turnOffEmotions(boolean isOn){
If (isOn) {
System.out.println("I am turning off my emotions.");
isOn= !isOn;
}
}
public void telepathy() {
System.out.println("Connecting to your brain...");
}
}
初心者向けには、Java のオブジェクト指向プログラミングの主要な概念がすべて網羅されています。4 つの主要な OOP 原則に加えて、Java には関連付け、集約、および構成もあります。これらは「追加の OOP 原則」と呼ぶことができます。それらは個別の記事に値します。
GO TO FULL VERSION