Javaの継承について詳しく解説
Java の継承と合成の基本概念
継承: 既存のクラスに基づいて新しいクラスを構築できます。 。既存のクラスを継承すると、これらのクラスのメソッドとフィールドを再利用できます。これに基づいて、新しいメソッドとフィールドを追加することで、クラスの機能を拡張できます。
合成: 新しいクラスで元のオブジェクトを作成することを合成と呼びます。こうすることで、既存のコードの形式を変更せずに再利用できます。
推奨される関連ビデオ チュートリアル: java ビデオ チュートリアル
1. 継承された構文
キーワード extends は、新しいクラスが既存のクラスに派生します。既存のクラスは親クラスまたは基本クラスと呼ばれ、新しいクラスはサブクラスまたは派生クラスと呼ばれます。例:
class Student extends Person { }
クラス Student は Person を継承します。パーソン クラスは親クラスまたは基本クラスと呼ばれ、Student クラスはサブクラスまたは派生クラスと呼ばれます。
2. 合成の構文
合成は比較的単純で、クラス内に既存のクラスを作成します。
class Student { Dog dog; }
モデリングの更新
1. 基本概念
継承の役割は、コードの使用が重複している。継承とは、親クラスのすべてのメソッドが子クラスでも使用できることを意味するため、親クラスに送信されたメッセージは派生クラスにも送信できます。 Person クラスに Eat メソッドがある場合、Student クラスにもこのメソッドが存在します。これは、Student オブジェクトも Person のタイプであることを意味します。
class Person { public void eat() { System.out.println("eat"); } static void show(Person p) { p.eat(); } } public class Student extends Person{ public static void main(String[] args) { Student s = new Student(); Person.show(s); // ① } }
[実行結果]:
eat
PERSONハンドルを受け取るには、PERSONに定義されているshowメソッドを使用しますが、①で受け取るのはStudentオブジェクトへの参照です。これは、Student オブジェクトが person オブジェクトでもあるためです。 show メソッドでは、受信ハンドル (オブジェクト参照) は、person オブジェクトおよび person 派生クラス オブジェクトにすることができます。 Student ハンドルを Person ハンドルに変換するこの動作は、アップキャストと呼ばれます。
2. 形状をトレースバックする必要があるのはなぜですか?
eat を呼び出すときに、それを呼び出すオブジェクト型を意図的に無視するのはなぜですか? show メソッドが単純に Student ハンドルを取得する方が直観的で理解しやすいように思えますが、その場合、Person クラスから派生した新しいクラスごとに独自の show メソッドを実装することになります。
class Value { private int count = 1; private Value(int count) { this.count = count; } public static final Value v1 = new Value(1), v2 = new Value(2), v3 = new Value(3); } class Person { public void eat(Value v) { System.out.println("Person.eat()"); } } class Teacher extends Person { public void eat(Value v) { System.out.println("Teacher.eat()"); } } class Student extends Person { public void eat(Value v) { System.out.println("Student.eat()"); } } public class UpcastingDemo { public static void show(Student s) { s.eat(Value.v1); } public static void show(Teacher t) { t.eat(Value.v1); } public static void show(Person p) { p.eat(Value.v1); } public static void main(String[] args) { Student s = new Student(); Teacher t = new Teacher(); Person p = new Person(); show(s); show(t); show(p); } }
このアプローチの欠点は明らかです。それは、密接に関連したメソッドを Person クラスの派生クラスごとに定義する必要があるため、多くの重複コードが発生するということです。一方、メソッドをオーバーロードするのを忘れた場合、エラーは報告されません。上記の例の 3 つの show メソッドは 1 つに結合できます。
public static void show(Person p) { p.eat(Value.v1); }
動的バインディング
show が実行されると、出力結果は Student.eat() で、これは確かに望ましい結果ですが、必要な形式で実行されないようです。show メソッドを見てみましょう:
public static void show(Person p) { p.eat(Value.v1); }
これは Person を受け取ります。実行時 show(s) のとき、パーソン ハンドルが Teacher オブジェクトではなく Student オブジェクトを指していることをどのようにして知るのでしょうか?コンパイラーにはそれを知る方法がありません。これには、次に説明するバインディングの問題が関係します。
1. メソッド呼び出しのバインディング
メソッドとメソッド本体を接続することをバインディングと呼びます。実行前にバインドが実行される場合、それは「早期バインディング」と呼ばれます。上記の例では、Person ハンドルが 1 つしかない場合、コンパイラーはどのメソッドを呼び出すべきかわかりません。 Java は、実行時にオブジェクトの型を決定し、対応するメソッドを呼び出すことができるメソッド呼び出しメカニズムを実装しています。実行時に実行され、オブジェクトの型に基づいて実行されるこのバインディングは、動的バインディングと呼ばれます。メソッドがfinal宣言されていない限り、Javaのすべてのメソッドは動的にバインドされます。
上流モデリングの継承関係を図で表現します:
コードで要約します:
Shape s = new Shape();
継承関係に従ってCircle は Shape の一種であるため、Circle オブジェクト ハンドルを Shape に割り当てることは正当です。
基本クラス メソッドの 1 つが呼び出されるとき:
Shape s = new Shape();
このとき、Circle.draw() が呼び出されます。これは動的バインディングによるものです。
class Person { void eat() {} void speak() {} } class Boy extends Person { void eat() { System.out.println("Boy.eat()"); } void speak() { System.out.println("Boy.speak()"); } } class Girl extends Person { void eat() { System.out.println("Girl.eat()"); } void speak() { System.out.println("Girl.speak()"); } } public class Persons { public static Person randPerson() { switch ((int)(Math.random() * 2)) { default: case 0: return new Boy(); case 1: return new Girl(); } } public static void main(String[] args) { Person[] p = new Person[4]; for (int i = 0; i < p.length; i++) { p[i] = randPerson(); // 随机生成Boy或Girl } for (int i = 0; i < p.length; i++) { p[i].eat(); } } }
person は、person から派生したすべてのクラスに共通のインターフェイスを確立しており、すべての派生クラスには食べると話すという 2 つの動作があります。派生クラスはこれらの定義をオーバーライドし、両方の動作を再定義します。
メイン クラスでは、randPerson が Person オブジェクトのハンドルをランダムに選択します。 **アピールの形成は return ステートメントで行われます。 **return ステートメントは、Boy または Girl ハンドルを取得し、それを Person タイプとして返します。この時点では、特定のタイプはわかりません。それが Person オブジェクト ハンドルであることだけがわかります。
main メソッドで randPerson メソッドを呼び出して、配列に Person オブジェクトを代入しますが、具体的な状況がわかりません。配列の各要素の Eat メソッドが呼び出されたときに、動的バインディングの役割は、オブジェクトの再定義されたメソッドを実行することです。
ただし、動的バインディングには前提条件があり、バインディング メソッドは基本クラスに存在する必要があり、存在しない場合はコンパイルできません。
class Person { void eat() { System.out.println("Person.eat()"); } } class Boy extends Person { void eat() { System.out.println("Boy.eat()"); } void speak() { System.out.println("Boy.speak()"); } } public class Persons { public static void main(String[] args) { Person p = new Boy(); p.eat(); p.speak(); // The method speak() is undefined for the type Person } }
如果子类中没有定义覆盖方法,则会调用父类中的方法:
class Person { void eat() { System.out.println("Person.eat()"); } } class Boy extends Person { } public class Persons { public static void main(String[] args) { Person p = new Boy(); p.eat(); } }
【运行结果】:
Person.eat()
2.静态方法的绑定
将上面的方法都加上static关键字,变成静态方法:
class Person { static void eat() { System.out.println("Person.eat()"); } static void speak() { System.out.println("Person.speak()"); } } class Boy extends Person { static void eat() { System.out.println("Boy.eat()"); } static void speak() { System.out.println("Boy.speak()"); } } class Girl extends Person { static void eat() { System.out.println("Girl.eat()"); } static void speak() { System.out.println("Girl.speak()"); } } public class Persons { public static Person randPerson() { switch ((int)(Math.random() * 2)) { default: case 0: return new Boy(); case 1: return new Girl(); } } public static void main(String[] args) { Person[] p = new Person[4]; for (int i = 0; i < p.length; i++) { p[i] = randPerson(); // 随机生成Boy或Girl } for (int i = 0; i < p.length; i++) { p[i].eat(); } } }
【运行结果】:
Person.eat() Person.eat() Person.eat() Person.eat()
观察结果,对于静态方法而言,不管父类引用指向的什么子类对象,调用的都是父类的方法。
更多java相关文章请关注java基础教程栏目。
以上がJavaの継承について詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

PHPは、サーバー側で広く使用されているスクリプト言語で、特にWeb開発に適しています。 1.PHPは、HTMLを埋め込み、HTTP要求と応答を処理し、さまざまなデータベースをサポートできます。 2.PHPは、ダイナミックWebコンテンツ、プロセスフォームデータ、アクセスデータベースなどを生成するために使用され、強力なコミュニティサポートとオープンソースリソースを備えています。 3。PHPは解釈された言語であり、実行プロセスには語彙分析、文法分析、編集、実行が含まれます。 4.PHPは、ユーザー登録システムなどの高度なアプリケーションについてMySQLと組み合わせることができます。 5。PHPをデバッグするときは、error_reporting()やvar_dump()などの関数を使用できます。 6. PHPコードを最適化して、キャッシュメカニズムを使用し、データベースクエリを最適化し、組み込み関数を使用します。 7

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

Java は、初心者と経験豊富な開発者の両方が学習できる人気のあるプログラミング言語です。このチュートリアルは基本的な概念から始まり、高度なトピックに進みます。 Java Development Kit をインストールしたら、簡単な「Hello, World!」プログラムを作成してプログラミングを練習できます。コードを理解したら、コマンド プロンプトを使用してプログラムをコンパイルして実行すると、コンソールに「Hello, World!」と出力されます。 Java の学習はプログラミングの旅の始まりであり、習熟が深まるにつれて、より複雑なアプリケーションを作成できるようになります。

Spring Bootは、Java開発に革命をもたらす堅牢でスケーラブルな、生産対応のJavaアプリケーションの作成を簡素化します。 スプリングエコシステムに固有の「構成に関する慣習」アプローチは、手動のセットアップを最小化します。
