序文
「作者のホームページ」:Sprite Youbai Bubbles
「個人サイト」:スプライトの個人サイト
「おすすめコラム」:
★ Java ワンストップ サービス ★
★ 入門から習熟まで対応★
★クールなフロントエンド コード共有 ★
★ 0 からヒーロー、Vue が神になるまでの道★
★ uniapp-構築からプロモーションまで★
★ 0 からヒーロー、 Vueが神になる道★
★ アルゴリズムは1カラムで解ける★
★ 0からアーキテクチャを語ろう★
★データの循環の絶妙なやり方★
★先進的なバックエンドへの道★
前回の記事Java - 基本文法 (1)の続きです。
記事ディレクトリ
5. 継承とポリモーフィズム:
Java は継承とポリモーフィズムをサポートしています。継承はオブジェクト指向プログラミングにおける重要なテクニックであり、新しいクラスが既存のクラスのプロパティとメソッドを取得できるようにします。ポリモーフィズムとは、同じメソッドが状況によって異なる動作をすることを意味します。
ここではJavaにおける継承とポリモーフィズムについて詳しく紹介していきます。
継承の基本概念
Java における継承は、クラスが別のクラスからプロパティと動作を継承できるようにするオブジェクト指向プログラミング メカニズムです。継承されたクラスは親クラスまたは基本クラスと呼ばれ、継承されたクラスはサブクラスまたは派生クラスと呼ばれます。継承によりコードの再利用が容易になると同時に、コードの可読性と保守性も向上します。
Java では、キーワード extends を使用して継承関係を実装します。サンプルコードは次のとおりです。
public class Animal {
public void eat() {
System.out.println("Animal is eating.");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("Dog is barking.");
}
}
上記のコードでは、Dog クラスは Animal クラスを継承しているため、Dog クラスには親クラス Animal にメンバー メソッド Eat() があります。
継承された機能
- サブクラスは、パブリック、プロテクト、およびデフォルトのアクセス レベルのメンバーを含む、親クラスのメンバー変数とメンバー メソッドを継承できます。
- サブクラスは、特定のニーズを満たすために親クラスのメンバー メソッドをオーバーライドできます。
- サブクラスは、特定のニーズを満たすために新しいメンバー変数とメンバー メソッドを追加できます。
- サブクラスは、親クラスのプライベート メンバー変数およびプライベート メンバー メソッドに直接アクセスできませんが、親クラスのパブリック メンバーまたは保護されたメンバー メソッドを通じてアクセスできます。
ポリモーフィズムの基本概念
ポリモーフィズムは、異なるオブジェクトが同じメッセージに対して異なる応答をできるようにするオブジェクト指向プログラミングの機能です。Java では、メソッドのオーバーロードとメソッドのオーバーライドを通じてポリモーフィズムを実現できます。
- メソッドのオーバーロード: メソッドのオーバーロードとは、メソッド名は同じだがパラメーター リストが異なる複数のメソッドをクラス内に定義することを指します。Java は、メソッドのパラメータ リストに基づいて、どのメソッドを呼び出すかを決定します。
- メソッドの書き換え: メソッドの書き換えとは、親クラスのメソッドをサブクラスで再定義することを指します。サブクラスによってオーバーライドされるメソッドは、親クラスのメソッドと同じ名前、パラメーター リスト、戻り値の型を持つ必要があり、アクセス修飾子をこれ以上制限することはできません。
サンプルコード:
public class Animal {
public void eat() {
System.out.println("Animal is eating.");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("Dog is eating bones.");
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("Cat is eating fish.");
}
}
上記のコードでは、Dog クラスと Cat クラスの両方が、親クラス Animal の Eat() メソッドを書き換えます。Eat() メソッドが呼び出されるとき、Java 仮想マシンは呼び出されるオブジェクトのタイプに基づいてどのメソッドを呼び出すかを決定します。
ポリモーフィックな実装
Java では、ポリモーフィズムを実現する方法が 2 つあります。継承によるポリモーフィズムとインターフェイスです。
-
継承によるポリモーフィズム:
継承システムでは、親クラス ポインタはサブクラス オブジェクトを指すことができます。親クラスの参照変数を使用してオーバーライドされたメソッドを呼び出す場合、Java 仮想マシンは呼び出されるオブジェクトのタイプに基づいてどのメソッドを呼び出すかを決定します。
サンプルコード:
Animal ani1 = new Dog(); Animal ani2 = new Cat(); ani1.eat(); // 输出:Dog is eating bones. ani2.eat(); // 输出:Cat is eating fish.
-
インターフェイスを介したポリモーフィズム:
インターフェイスは、メソッドの宣言のみを定義し、メソッドの実装は提供しない特別な種類の抽象クラスです。クラスは複数のインターフェイスを実装できるため、異なる動作特性を持つことができます。Java では、オブジェクト参照をインターフェイス型に変換することでポリモーフィズムが実現されます。インタフェースの参照変数を利用して実装クラス内のメソッドを呼び出す場合、Java仮想マシンは呼び出すオブジェクトの型に応じて呼び出すメソッドを決定します。
サンプルコード:
interface Shape {
void draw();
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Draw a circle.");
}
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Draw a rectangle.");
}
}
public class Main {
public static void main(String[] args) {
Shape s1 = new Circle();
Shape s2 = new Rectangle();
s1.draw(); // 输出:Draw a circle.
s2.draw(); // 输出:Draw a rectangle.
}
}
上記のコードでは、Circle クラスと Rectangle クラスの両方が Shape インターフェイスを実装し、インターフェイス内のdraw() メソッドを書き換えます。インターフェースの参照変数を使用して実装クラスのメソッドを呼び出す場合、Java 仮想マシンは呼び出すオブジェクトのタイプに基づいて呼び出すメソッドを決定します。
キャスト
Java では、必須の型変換を使用して親クラス参照変数をサブクラス参照変数に変換し、サブクラス固有のメンバーへのアクセスを容易にすることができます。
サンプルコード:
Animal ani = new Dog();
if (ani instanceof Dog) {
Dog d = (Dog)ani;
d.bark();
}
上記のコードでは、ani は Animal クラスの参照変数ですが、Dog クラスのインスタンスを指します。instanceof 演算子を使用すると、ani が Dog クラスのインスタンスを指しているかどうかを判断できます。その場合、キャストを使用して ani を Dog 型に変換し、Dog クラスに固有のメソッド bark() にアクセスできます。
キャスト中に実際のオブジェクトが必要な型のサブクラスではない場合、ClassCastException がスローされることに注意してください。したがって、キャスト前の型チェックには、instanceof 演算子を使用することをお勧めします。
6. 親クラスのコンストラクターを呼び出す
Java では、サブクラスは親クラスのすべてのプロパティとメソッドを継承しますが、親クラスのコンストラクターは継承しません。したがって、親クラスのメンバー変数が正しく初期化されていることを確認するために、サブクラスのコンストラクター内で親クラスのコンストラクターを呼び出すことが非常に必要です。
サブクラスのコンストラクターで super キーワードを使用して、親クラスのコンストラクターを呼び出します。親クラスに複数のコンストラクターがある場合、 super キーワードを使用して、呼び出す必要があるコンストラクターを指定できます。
サンプルコード:
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
}
public class Dog extends Animal {
private int age;
public Dog(String name, int age) {
super(name); // 调用父类的构造方法
this.age = age;
}
}
上記のコードでは、Dog クラスは Animal クラスを継承し、そのコンストラクターで Animal クラスのコンストラクターを呼び出します。
抽象クラスと抽象メソッド
抽象クラスは、インスタンス化できず、他のクラスの親クラスとしてのみ使用できる特別なクラスです。抽象クラスには、具体的な実装を持たず、メソッド宣言のみを含む抽象メソッドを含めることができます。
Java では、abstract キーワードを使用して抽象クラスまたは抽象メソッドを定義します。クラスに抽象メソッドが含まれる場合、クラスは抽象クラスである必要があります。
サンプルコード:
abstract class Shape {
abstract void draw();
}
class Circle extends Shape {
@Override
void draw() {
System.out.println("Draw a circle.");
}
}
class Rectangle extends Shape {
@Override
void draw() {
System.out.println("Draw a rectangle.");
}
}
上記のコードでは、Shape クラスは抽象クラスであり、抽象メソッドdraw() が含まれています。Circle クラスと Rectangle クラスはどちらも Shape クラスを継承し、draw() メソッドを実装します。
クラスが抽象クラスを継承する場合、抽象クラス内のすべての抽象メソッドを実装する必要があり、それ以外の場合はクラスも抽象クラスとして宣言する必要があることに注意してください。
インターフェース
インターフェイスは、メソッドの宣言のみを定義し、メソッドの実装は提供しない特別な種類の抽象クラスです。クラスは複数のインターフェイスを実装できるため、異なる動作特性を持つことができます。
Java では、interface キーワードを使用してインターフェイスを定義します。インターフェイス内のメソッドはデフォルトでパブリック抽象メソッドですが、定数、デフォルト メソッド、静的メソッドも定義できます。
サンプルコード:
interface Shape {
double PI = 3.14; // 定义常量
void draw(); // 定义抽象方法
default void show() {
// 定义默认方法
System.out.println("This is a shape.");
}
static void info() {
// 定义静态方法
System.out.println("This is a shape interface.");
}
}
class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Draw a circle with radius " + radius);
}
}
上記のコードでは、Shape インターフェイスは定数 PI、抽象メソッドdraw()、デフォルト メソッド show()、および静的メソッド info() を定義します。Circle クラスは Shape インターフェイスを実装し、draw() メソッドをオーバーライドします。
クラスがインターフェイスを実装する場合、インターフェイス内のすべてのメソッドを実装する必要があり、それ以外の場合はクラスを抽象クラスとして宣言する必要があることに注意してください。
要約する
継承とポリモーフィズムは、オブジェクト指向プログラミングにおいて非常に重要な概念です。継承によりコードの再利用が容易になると同時に、コードの可読性と保守性も向上します。ポリモーフィズムは、オブジェクト指向プログラミングにおける非常に強力な機能であり、異なるオブジェクトが同じメッセージに対して異なる応答を行うことができます。
Java では、継承関係を実装するために extends キーワードが使用され、親クラスのコンストラクターを呼び出すために super キーワードが使用されます。ポリモーフィズムは、メソッドのオーバーロードとメソッドのオーバーライド、およびインターフェイスを通じて実現できます。必須の型変換を実行するときは、ClassCastException 例外を回避するために型チェックに注意する必要があります。さらに、抽象クラスと抽象インターフェイスもオブジェクト指向プログラミングにおいて非常に重要な概念であり、コードをより適切に整理し、データをカプセル化し、複雑な機能を実現するのに役立ちます。
6.インターフェース:
Java のインターフェイスは、抽象メソッドのコレクションです。インターフェイスはクラスによって実装でき、クラスは複数のインターフェイスを実装することもできます。インターフェイスは、interface キーワードを使用して定義されます。
ここでは、Javaにおけるインターフェースの概念、特徴、利用方法、応用シナリオなどを詳しく紹介します。
インターフェースの概念
Java では、インターフェイスはメソッド定義と定数宣言のみを含む特別な抽象クラスであり、具体的なメソッド実装は含まれません。インターフェイスを使用すると、複数の異なるクラスで同じメソッドを実装できるため、コードの再利用という目的を達成できます。同時に、このインターフェイスを使用してコールバック メカニズム (コールバック) を実装することもできます。つまり、オブジェクトは特定の状況下で別のオブジェクトのメソッドを呼び出します。
インターフェースの機能
- インターフェイス内のすべてのメソッドはパブリック抽象メソッドであり、特定のメソッド実装は含まれません。
- 定数はインターフェイスで定義できますが、変数は定義できません。
- インターフェイスはインスタンス化できず、実装されるだけです。
- クラスは複数のインターフェイスを実装できます。
- インターフェイスは複数のインターフェイスから継承できます。
インターフェースの使用方法
Java では、インターフェースはキーワードインターフェースを使用して定義されます。インターフェイス内のメソッドは、デフォルトではパブリック抽象メソッドです。メソッド名の前に abstract キーワードを追加できますが、必須ではありません。
サンプルコード:
public interface Shape {
double getArea();
double getPerimeter();
}
上記のコードでは、Shape インターフェイスが定義されています。これには 2 つのメソッド getArea() と getPerimeter() が含まれており、どちらもパブリック抽象メソッドです。このインターフェイスは他のクラスによって実装され、さまざまな形状の面積と周囲長を計算する関数を提供できます。
インターフェースの実装
Java では、インターフェースはキーワード installs を使用して実装されます。クラスは複数のインターフェイスを実装できますが、インターフェイスを実装するクラスは、インターフェイスで宣言されたすべてのメソッドを実装する必要があります。
サンプルコード:
public class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public double getPerimeter() {
return 2 * Math.PI * radius;
}
}
上記のコードでは、Circle クラスが Shape インターフェイスを実装し、getArea() メソッドと getPerimeter() メソッドを書き換えます。
インターフェースの継承
Java では、インターフェイスは別のインターフェイスを継承することもでき、サブインターフェイスが親インターフェイスのメソッド定義を継承できるようになります。
サンプルコード:
public interface Drawable {
void draw();
}
public interface Shape extends Drawable {
double getArea();
double getPerimeter();
}
上記のコードでは、Shape インターフェイスは Drawable インターフェイスを継承し、2 つの新しいメソッド getArea() と getPerimeter() を拡張しています。
インターフェースの応用シナリオ
- ポリモーフィズムの実装: インターフェイスを使用すると、複数の異なるクラスで同じメソッドを実装できるため、コードの再利用という目的を達成できます。
- コールバック メカニズムの実装: インターフェイスを使用してコールバック メカニズムを実装できます。つまり、オブジェクトは特定の状況下で別のオブジェクトのメソッドを呼び出します。
- クラスの継承の制限: インターフェイスは、特定のクラスの継承関係を制限する制約として使用できます。クラスがインターフェイスを実装する場合、そのインターフェイスで宣言されたすべてのメソッドを実装する必要があります。
- 定数の定義: インターフェイスは、他のクラスで使用する定数を定義できます。
つまり、インターフェイスは Java の非常に重要な概念の 1 つであり、これによりコードをより適切に編成し、データをカプセル化し、複雑な機能を実現できるようになります。API を設計する場合、インターフェイスは非常に一般的な設計パターンでもあり、API のスケーラビリティと保守性を向上させることができます。
7. ジェネリック:
ジェネリックは、コードをより柔軟かつ安全にすることができる Java 言語の強力な機能です。ジェネリックスを使用すると、型をパラメータ化できるため、コードがさまざまなデータ型に適応しやすくなります。
それでは、Java におけるジェネリックスの概念、特徴、使用方法、適用シナリオについて詳しく紹介します。
一般的な概念
Java におけるジェネリックは、さまざまなデータ型をサポートするクラスまたはメソッドを定義できるようにするパラメーター化された型メカニズムです。わかりやすく言うと、ジェネリックとは、コードの再利用と拡張を実現するために、データ型をパラメータとしてクラスまたはメソッドに渡すことです。
一般的な機能
- ジェネリックスはコンパイル時の型チェックをサポートしており、コンパイル時に型エラーを検出できます。
- ジェネリックによりコードの重複が減り、コードの可読性と保守性が向上します。
- ジェネリックにより、プログラムの柔軟性と拡張性が向上します。
ジェネリックの使い方
Java では、山かっこ <> を使用してジェネリック型を指定します。次に例を示します。
List<String> list = new ArrayList<>();
上記のコードでは、List はリストを操作するための複数のメソッドを含む汎用インターフェイスであり、String は要素の型を表し、ArrayList は配列によって実装された List インターフェイスに基づく可変長配列シーケンスです。
ジェネリッククラス
Java では、さまざまな種類のオブジェクトをサポートできるジェネリック クラスを定義できます。ジェネリック クラスを定義する場合は、次のようにクラス名の後に型パラメーターを追加します。
public class Box<T> {
private T data;
public Box(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
上記のコードでは、Box クラスはジェネリック クラスであり、型パラメーター T を定義し、Box があらゆる種類のデータを格納できることを示しています。Box オブジェクトを作成するときは、特定のタイプの T を指定する必要があります。
一般的なメソッド
Java では、多くの異なるタイプのパラメータをサポートできるようにジェネリック メソッドを定義することもできます。ジェネリック メソッドは、次のように定義時にメソッド名の前に型パラメーターを追加する必要があります。
public class ArrayUtil {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.printf("%s ", element);
}
System.out.println();
}
}
上記のコードでは、 printArray() はジェネリック メソッドであり、型パラメーター T を定義し、メソッドが任意の型の配列を処理できることを示します。printArray() メソッドを呼び出すときは、特定のタイプの T を指定する必要があります。
ワイルドカード
Java では、ワイルドカード (ワイルドカード) を使用して、特定のタイプのサブクラスまたは親クラスを表すことができます。
- ? extends T は型のサブクラスを表します。
- ? super T は、特定のタイプのスーパークラスを表します。
サンプルコード:
public class Animal {
}
public class Dog extends Animal {
}
List<? extends Animal> list1 = new ArrayList<Dog>(); // 子类向父类转换
List<? super Dog> list2 = new ArrayList<Animal>(); // 父类向子类转换
上記のコードでは、list1 は Animal のすべてのサブクラスを含むリストを表し、Dog タイプのリストを受け取ることができ、list2 は Dog のすべての親クラスを含むリストを表し、Animal タイプのリストを受け取ることができます。このようにして、サブクラスから親クラスへ、親クラスからサブクラスへの変換が実現できる。
一般的なアプリケーション シナリオ
- コレクション クラス: Java のコレクション クラス (List、Set、Map など) は、ジェネリックを使用して実装されます。
- インターフェイスと抽象クラス: ジェネリックスをインターフェイスと抽象クラスで使用すると、さまざまな種類のオブジェクトをサポートできます。
- タイプ セーフ: ジェネリックスは、タイプ セーフなコードの作成を保証し、型変換中の実行時エラーを回避します。
- リフレクション メカニズム: ジェネリックをリフレクション メカニズムと組み合わせることで、実行時にジェネリック情報を取得できます。
つまり、ジェネリックスは Java の非常に重要な概念の 1 つであり、ジェネリックスを使用するとコンパイル時に型エラーを検出できるため、コードの堅牢性と可読性が向上します。また、コードの重複が減り、コードの保守性とスケーラビリティが向上します。
2 つ目は、ジェネリックはクラスだけでなくメソッドにも適用されるということです。ジェネリック メソッドを定義する場合は、メソッド名の前に型パラメーターを追加する必要があります。
3 番目に、ワイルドカードはジェネリックスにおいて非常に重要な概念であり、特定のタイプのサブクラスまたは親クラスを表すために使用できます。たとえば、List<? extends Number> はすべての Number サブクラスを含むリストを表し、List<? super Integer> はすべての Integer 親クラスを含むリストを表します。
第 4 に、ジェネリックの適用シナリオは非常に広範囲にわたり、一般的なものとしては、コレクション クラス、インターフェイスと抽象クラス、タイプ セーフティとリフレクション メカニズムなどが挙げられます。
ジェネリックを使用したサンプル コードを次に示します。
ジェネリッククラス
public class Box<T> {
private T data;
public Box(T data) {
this.data = data;
}
public T getData() {
return data;
}
}
上記のコードでは、Box はジェネリック クラスであり、型パラメーター T を定義し、Box が任意の型のデータを格納できることを示します。
一般的なメソッド
public class ArrayUtil {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.printf("%s ", element);
}
System.out.println();
}
}
上記のコードでは、 printArray() はジェネリック メソッドであり、型パラメーター T を定義し、メソッドが任意の型の配列を処理できることを示します。
ワイルドカード
public class Animal {
}
public class Dog extends Animal {
}
List<? extends Animal> list1 = new ArrayList<Dog>(); // 子类向父类转换
List<? super Dog> list2 = new ArrayList<Animal>(); // 父类向子类转换
上記のコードでは、list1 は Animal のすべてのサブクラスを含むリストを表し、Dog タイプのリストを受け取ることができ、list2 は Dog のすべての親クラスを含むリストを表し、Animal タイプのリストを受け取ることができます。このようにして、サブクラスから親クラスへ、親クラスからサブクラスへの変換が実現できる。
汎用インターフェース
public interface Comparable<T> {
int compareTo(T o);
}
上記のコードでは、Comparable はジェネリック インターフェイスであり、型パラメーター T を定義し、Comparable が任意の型のオブジェクトを比較できることを示します。
一般的な列挙型
public enum Color {
RED, GREEN, BLUE}
public enum Size {
SMALL, MEDIUM, LARGE}
public class Shirt<T extends Enum<T>> {
private T color;
private T size;
public Shirt(T color, T size) {
this.color = color;
this.size = size;
}
public T getColor() {
return color;
}
public T getSize() {
return size;
}
}
上記のコードでは、 Shirt はジェネリック クラスであり、2 つの型パラメーター T と E を定義します。T は列挙型 (Color や Size など) である必要があり、E は Comparable インターフェイスを実装する型である必要があります。これにより、シャツの色とサイズを表す汎用の列挙クラスを作成できるようになります。
要約すると、ジェネリックは Java の非常に重要な概念の 1 つであり、これにより、より堅牢で柔軟で拡張可能なコードを作成できるようになります。実際の開発では、作業をより適切に完了するために、ジェネリックスの構文と使用法に習熟する必要があります。