個人的には、プログラミングのいわゆるクラスは、オブジェクトを分類する現実世界のクラスと同じ概念ですが、プログラミングで借りています。クラスは、一連の共通点と同じ操作またはアクションを備えたものを表します。これらは、プログラミングの抽象データ型です。各特定の個人(現実世界)とインスタンス変数(プログラミング用)はオブジェクトです。
クラスは、現実世界の特定のオブジェクトの共通の特徴(属性と操作)の表現であり、オブジェクトはクラスのインスタンスです。
クラス属性:クラスの静的属性の略語は、変数やその他のクラスオブジェクトなど、クラスに含まれるさまざまなデータを指します。
クラスサービス:メンバー関数またはメソッドと呼ばれます。
¨
Javaのクラスの定義形式は次のとおりです。
[修飾子]クラス名[親クラスを拡張] [インターフェイス名を実装] {クラスメンバー変数宣言クラスメソッド宣言}これの各部分について詳細に話しましょう。
クラスキーワードの前に、クラス修飾子は通常、3つのタイプに分割されます。AccessModifiers Public Public Class、Final Class Specifier)、およびAbstract Modifier(Abstract Class仕様)
その中で、許可修飾子は公開またはデフォルトのみ(つまり、空で、何も、フレンドリーとして定義されていることを示します)であり、パブリックは、同じパッケージまたは異なるパッケージで、クラスがクラスの場所を見つけることができる限り)どこにでも使用およびアクセスできることを意味します。これはC ++とは異なることに注意してください。 C ++には、クラスへのアクセス権を制限する修飾子はありませんが、クラス間の相続関係に対するアクセス権があります。さらに、それらはすべて、クラス属性とメソッドに対するアクセス権を持っています。デフォルトのアクセス許可(つまり、フレンドリーとして定義)は、同じパッケージのクラスでのみ参照およびアクセスできることを意味しますが、インポートされた場合でも、他のパッケージのクラスでアクセスおよび参照することはできません。
また、後で説明します。クラス属性とメソッドのデフォルトの修飾子が使用されると、同じパッケージのクラスによってのみ参照およびアクセスできることも表明されます。
Javaでは複数の継承は許可されていません。これはC ++とは異なります。この欠点を補うために、Javaはインターフェイスの概念を導入しました。
上記のクラスの定義では、クラス本体には、クラスの属性とクラスの方法など、クラスの特定のコンテンツが主に含まれています。クラスのプロパティは、特定のクラスの単純な変数またはインスタンスにすることができます。クラスのインスタンスである場合、次のように定義できます。
[修飾子]クラス名オブジェクト名=新しいクラス名(パラメーターリスト);
オブジェクトと複雑な変数を宣言する場合、宣言中に作成を使用することはできませんが、将来のコンストラクターで作成できます。
クラスで定義されている方法は通常、2つの役割を果たします。1つは、クラスの属性を中心にさまざまな操作を実行することです。もう1つは、他のクラスまたはオブジェクトでデータ交換、メッセージ配信、その他の操作を実行することです。
Javaでの宣言メソッドの構文は次のとおりです。
[モディファイ] return値タイプメソッド名(パラメーターリスト)スロー例外名1、例外名2、…{メソッドボディ:ローカル変数宣言。ステートメントシーケンス;}メンバー関数とも呼ばれるクラスメソッドは、クラス属性の操作を指定し、クラスの内部関数を実装するために使用されます。また、クラスが外の世界と対話するための重要なウィンドウです。
Javaプログラマーは、クラスと呼ばれるユーザー定義のタイプの作成に焦点を当てています。クラスは、プログラマー定義型とも呼ばれます。各クラスには、データとデータを操作するための一連の方法が含まれています。クラスのデータ部分は、インスタンス変数と呼ばれます。ユーザー定義の型(つまり、クラス)のインスタンスはオブジェクトと呼ばれます。
オブジェクトはクラスのインスタンスです。クラスは、同じタイプのオブジェクトの抽象化と、オブジェクトを作成するためのテンプレートです。プログラム内にオブジェクトを作成すると、オブジェクトのプロパティやメソッドなど、メモリ内のスペースが開きます。キーワードオペレーターを使用してオブジェクトを作成します。
コンストラクター(C ++と比較することができます。これはC ++とほぼ同じです)
独自のコンストラクターを作成します
•コンストラクターの名前とクラスの名前は同じです。従業員クラスのオブジェクトを構築するとき、このコンストラクターが開始され、インスタンスフィールドに初期値が割り当てられます。 Javaでは、定義と初期化が統一されています。どちらも不可欠です。
たとえば、次のコードで従業員クラスのインスタンスを作成するとき、
NewEmployee( "James Bond"、100000,1950,1,1);
コンストラクターの特性は次のとおりです。
(1)コンストラクターとクラスの名前は同じです。
(2)クラスには複数のコンストラクターを持つことができます。
(3)コンストラクターには、0、1、またはそれ以上のパラメーターを持つことができます。
(4)コンストラクターには戻り値がありません。
(5)コンストラクターは常に新しいオペレーターと呼ばれます。
コンストラクターの役割
(1)オブジェクトの初期化
(2)より柔軟性(可変割り当てまたはより複雑な操作)を導入する
(3)コンストラクターはJavaで定義できません
コンストラクターはJavaで定義できず、システムはシステムのデフォルトコンストラクターを自動的に生成します。このコンストラクターの名前はクラス名と同じで、正式なパラメーターがなく、操作を実行しません。
メソッドの概要
Javaプログラムはクラスの定義で構成されており、クラスにはプロパティとメソッドの2つの部分があります。属性説明クラスとは何ですか?また、メソッド説明クラスは何ですか。すべてのオブジェクトには、プロパティを保存するための独立したメモリがあります。クラスのすべてのオブジェクトは、メモリに保存されているメソッドを共有します。
言い換えれば、メソッドはクラスの主なコンポーネントです。クラスでは、プログラムの役割がメソッドに反映されています。
この方法は、Javaによって名前付きサブルーチンを作成することです。主な方法といくつかのサブメソッド。主な方法は他の方法を呼び出し、他の方法も互いに呼び出すことができ、同じ方法を1つ以上の方法でいつでも呼び出すことができます。
1つの方法で別のメソッドを定義すると、構文エラーが生成されます。
(1)ローカル変数「マスク」インスタンス変数を回避することをお勧めします。これは、クラス内の同じ名前の識別子を使用せずに実行できます。メソッド呼び出しのパラメーターは、数値と参照を渡すために使用されます。また、メソッドはネストされた再帰的にも呼び出すことができます。
(2)メソッド本体で非ボイドの返品値タイプが指定されている場合、メソッドには、どの場合にも戻り値があることを確認するための返品ステートメントを含める必要があり、返されるステートメントの後に式が続くことはできません。
Javaプログラムの基本構造は次のとおりです。
Javaクラスライブラリを紹介します。ユーザークラス1を定義します(クラス1のいくつかの変数またはオブジェクトを定義します。クラス1の方法1を定義します。クラス1の方法2を定義します。 …クラス1のメソッドM1を定義します。 }ユーザークラス2を定義します{クラス2のいくつかの変数またはオブジェクトを定義します。クラス2の方法1を定義します。クラス2の方法2を定義します。 …クラス2のメソッドM2を定義}Javaは、ライブラリの作成者がクライアントプログラマーが使用できるものと使用できないものを宣言できるようにする「アクセス制御修飾子」の概念を導入しました。
このレベルのアクセス制御は、「最大アクセス」の範囲と「最小アクセス」の範囲の間にあります。次のリストは、アクセス制御修飾子の意味を説明しています。
パブリックアクセス制御文字
クラスの場合:
Javaのクラスには1つのアクセスコントローラーが1つしかありません。つまり、パブリックです。クラスはパブリッククラスとして宣言され、他のすべてのクラスでアクセスおよび参照できることを示します。ここでのアクセスと参照とは、クラスが目に見えるものであり、全体として使用可能であることを指します。プログラムの他の部分は、このクラスのオブジェクトを作成し、クラス内に表示されるメンバー変数にアクセスし、目に見える方法を呼び出すことができます。
クラスはプログラム全体の他の部分に表示され、クラス内のすべてのプロパティとメソッドもプログラムの他の部分にも表示されていることを表していません。前者は後者に必要な条件にすぎません。クラスのプロパティとメソッドに他のすべてのクラスでアクセスできるかどうかは、これらのプロパティとメソッドのアクセス制御文字に依存します。
クラス内プロパティに使用:
一般に変更されたクラス内属性は、パブリック属性と呼ばれます。このクラスが公開クラスの場合、他のすべてのクラスからアクセスできます。
デフォルトのアクセス制御
クラスに使用されます
クラスにアクセス制御文字がない場合、デフォルトのアクセス制御特性があることを意味します。このデフォルトのアクセス制御により、クラスには同じパッケージのクラスによってのみアクセスおよび参照できることを規定しており、他のパッケージのクラスでは使用できません。このアクセス機能は、パッケージアクセシビリティと呼ばれます。クラスのアクセス制御文字を宣言することにより、プログラム構造全体が明確かつ厳密になり、クラス間干渉とエラーの可能性が減少します。
クラス属性に使用されます
クラス内のプロパティとメソッドがアクセス制御シンボルによって制限されていない場合、それらはパケットアクセシビリティであることも示します。
3プライベートアクセス制御キャラクタープライベート
プライベートで変更された属性またはメソッドは、クラス自体によってのみアクセスおよび変更でき、クラスのサブクラスを含む他のクラスで取得および参照することはできません。
1)。たとえば、プライベートデータには、従業員クラスのインスタンス内で動作するデータを含む3つのインスタンスフィールドがあります。
プライベート文字列名;
プライベートダブルサラリー;
プライベートデート雇用;
秘密のキーワードは、これらのインスタンスフィールドに従業員クラス自体のみがアクセスできるようにするために使用されます。
2).privateメソッドクラスを実装すると、パブリックデータが危険であるため、すべてのデータフィールドをプライベートにします。この方法の状況は何ですか?ほとんどの方法はパブリックですが、プライベート方法も頻繁に使用されます。これらの方法は、同じ方法でのみ分離できます。
要するに、次の場合にはプライベート方法を選択できます。
(1)クラスのユーザーに関係のない方法。
(2)クラスの実装が変更された場合、維持が容易ではない方法。
保護されたアクセス制御文字が保護されています
保護されたメンバー変数は、クラス自体、同じパッケージの他のクラス、および他のパッケージのクラスのサブクラスの3つのタイプで参照できます。保護された修飾子を使用する主な目的は、他のパッケージ内のサブクラスが親クラスの特定のプロパティにアクセスできるようにすることです。
保護されたキーワードは、既存のクラスに基づいて「継承」と呼ばれる概念を紹介し、既存のクラスに影響を与えることなく新しいメンバーを追加します。この既存のクラス「基本クラス」または「ベースクラス」と呼びます。また、そのクラスの既存のメンバーの動作を変更することもできます。既存のクラスからの継承のために、私たちの新しいクラスは既存のクラスを「拡張」していると言います
プライベート保護されたアクセス制御キャラクタープライベート保護されています
プライベートと保護されたものは、完全なアクセス制御キャラクターを形成するために順番に使用されます:プライベート保護アクセス制御文字。プライベート保護で変更されたメンバー変数にアクセスして2つのクラスで参照できます。1つはクラス自体で、もう1つはクラスのサブクラスです。これらのサブクラスはクラスと同じパッケージであろうと他のパッケージです。
保護されたものと比較して、プライベート保護された修飾子は、アクセス可能な範囲から同じパッケージ内の非サブカラスを除外し、メンバー変数を、ゆるくグループ化されたパッケージではなく、明示的な継承関係を持つクラスにより独自のものにします。
静的修飾子
静的は静的修飾子と呼ばれ、クラスのプロパティとメソッドを変更します。
静的キーワードを使用すると、2つの要件を満たすことができます。
(1)1つの状況は、特定のデータを保存するためにストレージエリアを使用したいということです。作成したいオブジェクトの数に関係なく、オブジェクトをまったく作成しないことです。静的によって変更された属性は静的プロパティと呼ばれ、このタイプの属性の最も重要な機能の1つは、クラスの特定のオブジェクトではなく、クラスの属性であることです。言い換えれば、このクラスの特定のオブジェクトの場合、静的プロパティは共通のストレージユニットです。クラスのオブジェクトがアクセスすると、同じ数値値が得られます。クラスのオブジェクトがそれを変更すると、同じメモリユニットで操作を行っています。
(2)別の状況は、このクラスのどのオブジェクトにも関連付けられていない特別な方法が必要だということです。つまり、オブジェクトが作成されていなくても、クラスで直接呼び出すことができる方法が必要です。
静的の重要な目的は、オブジェクトを作成することなく、その方法を呼び出すのを助けることです。
静的定数
静的変数はまれです。ただし、静的定数は一般的です。たとえば、静的定数は数学クラスで定義されます。
パブリッククラスの数学
{…public static final double pi = 3.1.4159265358979323846;…}静的メソッドは、メソッドが静的であることを宣言します。少なくとも3つの意味があります。
(1)この方法を使用する場合、クラス名は特定のオブジェクト名ではなくプレフィックスとして使用する必要があります。
(2)非静的な方法は、オブジェクトに属する方法です。このオブジェクトが作成されると、オブジェクトのメソッドには、メモリに独自の専用コードセグメントがあります。静的メソッドはクラス全体に属し、メモリ内のコードセグメントはクラスの定義に従って割り当てられ、ロードされ、オブジェクトには排他的ではありません。
(3)静的メソッドはクラス全体に属しているため、特定のオブジェクトに属するメンバー変数を操作して処理することはできませんが、クラス全体に属するメンバー変数のみを処理できます。
5つの主要な方法
主な方法は、任意のオブジェクトに操作を適用しません。実際、プログラムが実行を開始すると、オブジェクトはまだ存在しません。静的メソッドが実行され、プログラムに必要なオブジェクトが構築されます。
各クラスにはメインメソッドを持つことができることが促されます。これは、ユニットテストクラスに非常に便利なトリックです。
要約は、クラスまたはメソッドを変更するために使用できる抽象修飾子です。
抽象クラス
クラスが抽象として宣言されると、このクラスは抽象クラスと呼ばれます。いわゆる抽象クラスは、具体的なインスタンスオブジェクトのないクラスです。
この問題に対処するために、Javaは「Abstract Method」と呼ばれるメカニズムを提供します。それは、宣言が1つだけで、メソッド本体がない不完全な方法に属します。抽象的なメソッドを宣言するときに使用される構文は次のとおりです。
抽象void x();
抽象的なメソッド
クラスメソッド修飾子として、要約は、メソッドヘッダーのみを備えているが、特定のメソッドボディと操作の実装を持たない抽象的なメソッドを宣言します。
抽象的なメソッドにはメソッドヘッダーの宣言のみがあり、セミコロンはメソッド本体の定義を置き換えるために使用されます。メソッド本体の特定の実装に関しては、それぞれのクラス定義で現在のクラスの異なるサブクラスによって完了します。
すべての抽象的なメソッドが抽象クラスに存在する必要があることに注意する必要があります
真ん中。
抽象的なメソッドに加えて、抽象クラスは具体的なデータと方法を持つことができます。
抽象的な方法は、Javaプログラミング言語の非常に重要な概念です。インターフェイスで多くの方法で使用します。
注:ここでは、インターフェイスを比較して記憶する必要があります。インターフェイス内のメソッドはすべて抽象的なメソッドです。もちろん、インターフェイスには属性もあり、それらの特定の特性については後で詳しく説明します。
最終クラス、最終属性、最終メソッド、ファイナルライザー(C ++には最終的な修飾子はありません)
ファイナルは、クラス、プロパティ、およびメソッドを変更する最終的な修飾子です。さらに、ターミナルのキーワードは最終に非常に似ており、一緒に紹介されます
最終クラス
クラスが最終と宣言されている場合、新しいサブクラスを導き出すことができず、親クラスとして継承することができないことを意味します。したがって、クラスは抽象的および最終の両方で宣言することはできません。
ファイナルとして定義されるクラスは、通常、標準関数を完了するために使用される特別な関数を備えた一部のクラスです。クラスをファイナルとして定義すると、コンテンツ、属性、機能を修正し、クラス名と安定したマッピング関係を形成することで、このクラスを参照するときに実装された関数が正確であることを保証できます。
最終属性
多くのプログラミング言語には、特定のデータが「定数」であることをコンパイラに伝える独自の方法があります。定数は、主に次の2つの側面で使用されます。
(1)コンピレーションの周期定数、それは決して変わりません。
(2)ランタイム中に初期化された値を変更する必要はありません。
インスタンスフィールドは、最終として定義できます(変更できません)。このフィールドは、オブジェクトが構築されたときに初期化する必要があります。つまり、各コンストラクターの終了前に値が設定されていることを確認する必要があります。将来、フィールドの価値を変更することはできません
最終的な方法
最終的な方法を使用する理由は、2つの理由で考慮事項が原因である可能性があります。
1つ目は、継承クラスが元の意味を変更するのを防ぐための方法を「ロック」することです。プログラムを設計するとき、このプラクティスは、継承中にメソッドの動作を変更せずに維持し、上書きまたは書き換えられない場合に実行できます。
最終的な方法を採用する2番目の理由は、プログラム実行の効率性です
ターミネーター
ターミネーターの関数は、オブジェクトを取得するときに実行される方法です。オブジェクトを作成するときにコンストラクターが実行される方法に似ています。
例
protected voidfinalize(){system.out.println( ""); }その他の修飾子
揮発性
属性が揮発性によって変更されている場合、この属性は複数のスレッドで同時に制御および変更できることを意味します。
同期
主にスレッドの同期に使用されます
ネイティブ
これは、この方法がJava言語で記述されていないことを意味します(C、C ++、その他の言語で記述されています)
オンラインで見つかったいくつかの情報: -内部カテゴリ
簡単に言えば、内部クラスはクラスのクラスです。
クラスA {private int i; private void m(){} class b {mm(int j){i = j; m();}}}}ここでは、BはAの内部クラスであり、外部クラスのプライベートメソッドとプロパティへの便利なアクセスが特徴です。たとえば、ここでは、Aで私的なプロパティIおよびプライベートメソッドM()に直接アクセスできます。
オブジェクト指向プログラミングの最も重要な機能は、カプセル化(抽象化とも呼ばれます)、継承、多型です。オブジェクト指向のプログラミング言語として、Javaには次の点で独自の利点があります。
「継承はソフトウェアの再利用の形式であり、ソフトウェアの複雑さを減らすのに効果的です。継承はオブジェクト指向のプログラミング言語の特徴でもあります。オブジェクトを採用しているが継承がない言語はオブジェクトベースの言語ではありませんが、オブジェクト指向言語ではありません。これは2つの違いです。」
クラス間の相続関係は、現実の世界における遺伝的関係の直接シミュレーションです。これは、クラスと属性と操作の共有との間の本質的なつながりを表します。つまり、サブクラスは親クラスの特定の機能(継承クラス)に従うことができます。もちろん、サブクラスは独自の独立したプロパティと操作を持つこともできます
継承はソフトウェアの再利用の形式です。新しいクラスは既存のクラスによって生成され、新しい属性と動作は、プロパティと動作を保持し、新しいクラスの要件に応じてパフォーマンスを変更することにより追加されます。子クラスが1つの親クラスからのみ継承される場合、それは単一の継承と呼ばれます。子クラスが複数の親クラスから継承する場合、それは多材料と呼ばれます。 Javaは多発性継承をサポートしていませんが、「インターフェイス」の概念をサポートしていることに注意してください。インターフェイスにより、Javaは多発性継承の多くの利点を獲得し、対応する欠点を放棄することができます。注:C ++は複数の継承をサポートします
相続関係の定義:
[修飾子]クラスサブクラス名親クラス名、親クラス名2を拡張します
フォローしている親クラス名が拡張されます
キーワードは、現在のクラスのどのサブクラスが既に存在しているかを示すために使用され、継承関係があります。
従業員クラスの従業員の2つのサブクラスを定義します。
一般従業員カテゴリ:CommonEmployee
スーパーバイザーカテゴリ:マネージャー雇用者
親クラスからのサブクラス継承には、次の2つの主な側面があります。
(1)属性の継承。たとえば、会社は親クラスであり、会社には名前、住所、マネージャー、従業員などがあり、これらはすべて構造的な側面です。
(2)メソッド継承。親クラスは、プロジェクト、利益、マネージャーの任命、従業員の採用などを必要とする会社など、いくつかの業務を定義し、子会社もこれらの行動を継承します。
classCommonemployeEeeTENDS Employee // Subclass 1:{intm_managerno; // class manageremployeeeeedsの従業員を描写するクラスクラス属性m_managernoを定義する// subclass 2:{intm_secretaryno;属性の継承と隠し
従業員クラスは親クラスですが、親クラスであるという理由だけで、より多くの機能があるという意味ではありません。それどころか、サブアナログには、親クラスよりも多くの機能があります。サブクラスは親クラスの拡張であるため、親クラスが追加されていない属性と方法が追加されます(1)サブクラスは親クラスのプライベートメンバーにアクセスできませんが、サブクラスは親クラスの一般にアクセスできます。
(2)保護されたアクセスは、パブリックアクセスとプライベートアクセスの間の保護中間レベルです。
(3)継承された親クラスのメンバーはサブクラス宣言にリストされていないため、これらのメンバーはサブクラスに存在します。
ここでは、継承、上書き、過負荷、いくつかの混乱する概念を区別する必要があります。
メソッドの概念レベルでのみ、これらの3つの概念を簡単に混乱させることができます。
メソッド継承
サブクラスオブジェクトの場合、親クラスのメソッドを使用できます。これらの方法がサブクラスで明確に定義されていなくても、親クラスから自動的に継承されます。
メソッドカバレッジ
メソッドオーバーライドとは、次のことを指します。同じ名前のメソッドを定義して、親クラスを上書きする方法を定義します。これは、多型技術の実装です。親クラスのメソッドが子のクラスで上書きされている場合、通常、親クラスバージョンを呼び出して追加の作業を行うのは子どものクラスバージョンです。
注意すべきことがたくさんあります。ここでは、主にこれとスーパーに言及しています。 C ++にはこれがあります(そして、概念はJavaの概念に似ています)が、スーパーはありません。
これは現在のオブジェクト自体を表し、現在のオブジェクトへの参照を表します。オブジェクトの別名として理解できます。これにより、現在のオブジェクトのメソッドとプロパティを呼び出すことができます。
たとえば、this.getName()およびgetName()はクラスで同じです。
Superは、現在のオブジェクトの直接親クラスオブジェクトを表し、現在のオブジェクトの親クラスオブジェクトの参照メソッドオーバーロードです。
オーバーロードの定義:メソッドは同じメソッド名で定義できますが、異なるパラメーターテーブル(パラメーターテーブルのパラメーターの数、タイプ、または順序は異なる値があります)、これはメソッドオーバーロードと呼ばれます。
•過負荷:複数のメソッドが同じ名前を持ち、異なるパラメーターが含まれている場合、過負荷が発生します。コンパイラは、呼び出す方法を選択する必要があります。異なるメソッドヘッダーのパラメータータイプを特定のメソッド呼び出しで使用する値のタイプと比較することにより、正しい方法を選択します。
多型により、既存の変数と関連するクラスを統一されたスタイルで処理できるようになり、システムに新しい機能を簡単に追加できます。ここで、オンラインで見つけた情報を投稿することで、相続に特別な注意が必要な多型と相続の問題をより明確にすることができます。
Javaの多型
オブジェクト指向プログラミングには、カプセル化、継承、多型の3つの特性があります。
カプセル化は、クラスの内部実装メカニズムを隠し、データを保護しながらユーザーに影響を与えることなくクラスの内部構造を変更できるようにします。
継承は、多型の実装の準備中に親クラスコードを再利用することです。では、多型とは何ですか?
メソッドの書き換え、過負荷、動的接続は多型を構成します。 Javaが多型の概念を導入した理由の1つは、クラスの継承に関してC ++とは異なることです。後者は複数の継承を可能にし、それは非常に強力な機能をもたらしますが、複雑な継承関係はC ++開発者にも大きなトラブルをもたらします。リスクを回避するために、Javaは単一の相続のみを許可し、派生クラスと基本クラスの間にはIS-A関係があります(つまり、「猫」は「動物」です)。これを行うと、相続関係の単純さと明確さが保証されますが、必然的に大きな機能的な制限があります。したがって、Javaは、この欠点を補うために多型の概念を導入しました。さらに、抽象クラスとインターフェイスは、単一の相続規制の制限を解決するための重要な手段でもあります。同時に、多型はオブジェクト指向プログラミングの本質でもあります。
多型を理解するには、まず「上向きの変換」とは何かを知る必要があります。
私は動物のクラスを継承するサブクラス猫を定義しましたが、後者は前者が親クラスであるということです。合格できます
cat c = new Cat();
猫のオブジェクトをインスタンス化することは理解するのが難しくありません。しかし、私がこのように定義するとき:
動物a = new Cat();
これはどういう意味ですか?
それは簡単です、それは私が猫タイプの新しく作成されたオブジェクトへの動物タイプの参照を定義することを意味します。猫は親クラスの動物から継承されているため、動物型への参照は猫タイプのオブジェクトを指すことができます。それで、これをすることのポイントは何ですか?サブクラスは親クラスの改善と拡張であるため、サブクラスは一般に機能の親クラスよりも強力であり、その属性は親クラスよりもユニークです。
親クラスのタイプへの参照を定義すると、サブクラス化されたオブジェクトを指します。サブクラスの強力な関数を使用するだけでなく、親クラスの共通性も抽出できます。
したがって、親クラスのタイプへの参照は、親クラスで定義されたすべてのプロパティと方法を呼び出すことができ、親クラスではなく、子クラスで定義されている方法に対しては無力です。
同時に、親クラスのメソッドは、親クラスで定義されているが、子のクラスでは上書きされない場合にのみ、親クラスのタイプへの参照によって呼び出すことができます。
親クラスで定義されているメソッドの場合、メソッドが子クラスで書き換えられている場合、親クラスタイプへの参照は、ダイナミック接続であるチャイルドクラスでこのメソッドを呼び出します。
次のプログラムを見てください。
クラス父{public void func1(){func2(); } //これは親クラスのFUNC2()メソッドです。これは、メソッドが下のサブクラスでオーバーライドされるため// }} class Child extends father {// func1(int i)はfunc1()メソッドの過負荷//親クラスでは親クラスのタイプで定義されていないため、子どものメソッドの参照では呼び出せないので、func1(68)は間違っています。 } // func2()親クラスの父親のfunc2()メソッドを書き換えます}} public class polymorphismtest {public static void main(string [] args){father child = new child(); child.func1(); //印刷の結果はどうなりますか? }}上記のプログラムは、多型の非常に典型的な例です。チャイルドクラスの子供は、親クラスの父親を継承し、親クラスfunc1()メソッドを過負荷にし、親クラスfunc2()メソッドを上書きします。過負荷func1(int i)とfunc1()は、もはや同じ方法ではありません。親クラスにはfunc1(int i)がないため、親クラスタイプの参照子はfunc1(int i)メソッドを呼び出すことはできません。サブクラスがFUNC2()メソッドをオーバーライドすると、親クラスタイプの参照子は、メソッドを呼び出すときにサブクラスの書き換えられたfunc2()を呼び出します。
では、プログラムはどのような結果を印刷しますか?
明らかに、それは「CCC」でなければなりません。
多型については、次のように要約できます。
(1)親クラスタイプの参照を使用して、サブクラス(実際のオブジェクト)のオブジェクトを指す。
(2)この参照は、親クラスで定義されている方法と変数のみを呼び出すことができます。
(3)親クラスのメソッドがサブクラスで書き換えられた場合、このメソッドを呼び出すとき、サブクラスのメソッドが呼び出されます。 (動的接続、動的呼び出し)
(4)変数を書き直すことはできません(オーバーライド)。 「書き換え」の概念は、方法専用です。親クラスの変数がサブクラスの「書き直し」である場合、コンパイル中にエラーが報告されます。
多型は次のとおりです。
(1)インターフェイスとインターフェイスを実装し、インターフェイスで同じ方法をカバーするいくつかの異なるクラスを上書きします(2)親クラスと親クラスを上書きし、親クラスで同じ方法をカバーするいくつかの異なるサブクラスを上書きします。
1。基本概念
多型:オブジェクトにメッセージを送信し、オブジェクトに応答する動作を決定させます。
動的メソッド呼び出しは、スーパークラスオブジェクト参照変数にサブクラスオブジェクト参照を割り当てることにより実装されます。
このAVAのメカニズムは、原則に従います。スーパークラスオブジェクトが、参照される変数のタイプではなく参照されるオブジェクトのタイプを参照する変数を参照する場合、メンバーメソッドが呼び出されるが、スーパークラス、つまりサブクラスでカバーされているメソッドで定義する必要があります。
(1)AがクラスAへの参照である場合、A CanはクラスAのインスタンス、またはクラスAのサブクラスを指しています。
(2)AがインターフェイスAへの参照である場合、A aはインターフェイスAを実装するクラスのインスタンスを指す必要があります。
Java多型実装メカニズム
Sunの現在のJVM実装メカニズム、クラスインスタンスの参照は、ハンドルへのポインターであり、これは一対のポインターです。
ポインターはテーブルを指します。実際、このテーブルには2つのポインターもあります(1つのポインターはオブジェクトを含むメソッドテーブルを指し、もう1つのポインターはクラスオブジェクトへのポインターを示し、オブジェクトが属するタイプを示します)。
別のポインターは、Javaヒープから割り当てられたメモリスペースの一部を指します。
要約します
(1)動的メソッド呼び出しは、スーパークラスオブジェクト参照変数にサブクラスオブジェクト参照を割り当てることにより実装されます。
derivedc c2 = new derivedc();ベースクラスA1 = C2; //BaseClass base class, DerivedC is a1.play() inherited from BaseClass; //play() is defined in BaseClass and DerivedC, that is, the subclass overrides the method
分析:
* 为什么子类的类型的对象实例可以覆给超类引用?
自动实现向上转型。通过该语句,编译器自动将子类实例向上移动,成为通用类型BaseClass;
* a.play()将执行子类还是父类定义的方法?
子类的。在运行时期,将根据a这个对象引用实际的类型来获取对应的方法。所以才有多态性。一个基类的对象引用,被赋予不同的子类对象引用,执行该方法时,将表现出不同的行为。
在a1=c2的时候,仍然是存在两个句柄,a1和c2,但是a1和c2拥有同一块数据内存块和不同的函数表。
(2)不能把父类对象引用赋给子类对象引用变量
BaseClass a2=new BaseClass(); DerivedC c1=a2;//出错
在java里面,向上转型是自动进行的,但是向下转型却不是,需要我们自己定义强制进行。
c1=(DerivedC)a2; 进行强制转化,也就是向下转型.
(3)记住一个很简单又很复杂的规则,一个类型引用只能引用引用类型自身含有的方法和变量。
你可能说这个规则不对的,因为父类引用指向子类对象的时候,最后执行的是子类的方法的。
其实这并不矛盾,那是因为采用了后期绑定,动态运行的时候又根据型别去调用了子类的方法。而假若子类的这个方法在父类中并没有定义,则会出错。
例如,DerivedC类在继承BaseClass中定义的函数外,还增加了几个函数(例如myFun())
分析:
当你使用父类引用指向子类的时候,其实jvm已经使用了编译器产生的类型信息调整转换了。
这里你可以这样理解,相当于把不是父类中含有的函数从虚拟函数表中设置为不可见的。注意有可能虚拟函数表中有些函数地址由于在子类中已经被改写了,所以对象虚拟函数表中虚拟函数项目地址已经被设置为子类中完成的方法体的地址了。
(4)Java与C++多态性的比较
jvm关于多态性支持解决方法是和c++中几乎一样的,
只是c++中编译器很多是把类型信息和虚拟函数信息都放在一个虚拟函数表中,但是利用某种技术来区别。
Java把类型信息和函数信息分开放。Java中在继承以后,子类会重新设置自己的虚拟函数表,这个虚拟函数表中的项目有由两部分组成。从父类继承的虚拟函数和子类自己的虚拟函数。
虚拟函数调用是经过虚拟函数表间接调用的,所以才得以实现多态的。
Java的所有函数,除了被声明为final的,都是用后期绑定。
1个行为,不同的对象,他们具体体现出来的方式不一样,
比如: 方法重载overloading 以及方法重写(覆盖)override
class Human{ void run(){输出人在跑} } class Man extends Human{ void run(){输出男人在跑} } 这个时候,同是跑,不同的对象,不一样(这个是方法覆盖的例子) class Test{ void out(String str){输出str} void out(int i){输出i} }这个例子是方法重载,方法名相同,参数表不同
ok,明白了这些还不够,还用人在跑举例
Human ahuman=new Man();
这样我等于实例化了一个Man的对象,并声明了一个Human的引用,让它去指向Man这个对象意思是说,把Man这个对象当Human看了.
比如去动物园,你看见了一个动物,不知道它是什么, "这是什么动物? " "这是大熊猫! "
这2句话,就是最好的证明,因为不知道它是大熊猫,但知道它的父类是动物,所以,
这个大熊猫对象,你把它当成其父类动物看,这样子合情合理.
这种方式下要注意new Man();的确实例化了Man对象,所以ahuman.run()这个方法输出的是"男人在跑"
如果在子类Man下你写了一些它独有的方法比如eat(),而Human没有这个方法,
在调用eat方法时,一定要注意强制类型转换((Man)ahuman).eat(),这样才可以...
对接口来说,情况是类似的...
例:
package domain; //Define superA class superA { int i = 100; void fun(int j) { j = i; System.out.println("This is superA"); } } //Define superA subclass subB class subB extends superA { int m = 1; void fun(int aa) { System.out.println("This is subB"); } } //Define superA subC class subC extends superA { int n = 1; void fun(int cc) { System.out.println("This is subB"); } } //Define superA subC class subC extends superA { int n = 1; void fun(int cc) { System.out.println("This is subC"); } } class Test { public static void main(String[] args) { superA a = new superA(); subB b = new subB(); subC c = new subC(); a = b; a.fun(100); a = c; a.fun(200); } } /*
* 上述代码中subB和subC是超类superA的子类,我们在类Test中声明了3个引用变量a, b,
* c,通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。也许有人会问:
* "为什么(1)和(2)不输出:This is superA"。
* java的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,
* 被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,
* 但是这个被调用的方法必须是在超类中定义过的,
* 也就是说被子类覆盖的方法。
* 所以,不要被上例中(1)和(2)所迷惑,虽然写成a.fun(),但是由于(1)中的a被b赋值,
* 指向了子类subB的一个实例,因而(1)所调用的fun()实际上是子类subB的成员方法fun(),
* 它覆盖了超类superA的成员方法fun();同样(2)调用的是子类subC的成员方法fun()。
* 另外,如果子类继承的超类是一个抽象类,虽然抽象类不能通过new操作符实例化,
* 但是可以创建抽象类的对象引用指向子类对象,以实现运行时多态性。具体的实现方法同上例。
* 不过,抽象类的子类必须覆盖实现超类中的所有的抽象方法,
* 否则子类必须被abstract修饰符修饰,当然也就不能被实例化了
*/
以上大多数是以子类覆盖父类的方法实现多态.下面是另一种实现多态的方法-----------重写父类方法
JAVA里没有多继承,一个类之能有一个父类。而继承的表现就是多态。一个父类可以有多个子类,而在子类里可以重写父类的方法(例如方法print()),这样每个子类里重写的代码不一样,自然表现形式就不一样。这样用父类的变量去引用不同的子类,在调用这个相同的方法print()的时候得到的结果和表现形式就不一样了,这就是多态,相同的消息(也就是调用相同的方法)会有不同的结果。举例说明:
//父类public class Father{ //父类有一个打孩子方法public void hitChild(){ } } //子类1 public class Son1 extends Father{ //重写父类打孩子方法public void hitChild(){ System.out.println("为什么打我?我做错什么了!"); } } //子类2 public class Son2 extends Father{ //重写父类打孩子方法public void hitChild(){ System.out.println("我知道错了,别打了!"); } } //子类3 public class Son3 extends Father{ //重写父类打孩子方法public void hitChild(){ System.out.println("我跑,你打不着!"); } } //测试类public class Test{ public static void main(String args[]){ Father father; father = new Son1(); father.hitChild(); father = new Son2(); father.hitChild(); father = new Son3(); father.hitChild(); } }都调用了相同的方法,出现了不同的结果!这就是多态的表现!
import java.io.*;class Super{ Super(){ System.out.println("This is super class!"); } void method(){ System.out.println("Super's method"); }}class Sub extends Super{ Sub(){ super(); System.out.println("/n/t:and here is the child"); } void method(){ System.out.println("child's method"); }}public class Super_Sub{ public static void main(String[] args){ Super sup=new Sub(); sup.method(); Sub child=(Sub)new Super();//Here, the actual allocated memory is Super, but Child is used to refer to it. This is "downward transformation" (the parent class impersonates a child class, because the subclass is down when drawing in UML), and it must be casted by child.method(); }}对于数据来说,继承是否为正确的设计可以用一个简单的规则来判断。“is-a”规则表明子类的每一个对象都是一个超类的对象。例如,每一个经理是一个员工。然而,只有经理类是员工类的子类才是有意义的。很明显,反过来就不行了――并不是每个员工都是经理。
还有一个明确叙述“is-a”规则的方法是替代原则。该原则规定无论何时,如果程序需要一个超类对象,都可以用一个子类对象来代替
动态绑定
理解调用一个对象方法的机制是非常重要的。下面具体介绍:Xf;
(1)编译器检查对象的声明类型和方法名。
(2) Next, the compiler checks the parameter type in the method call. If one of all methods called f has a parameter type whose parameter type best matches the parameter type provided by the call, the method will be selected to call. This process is called overload selection. (静的)
(3)当程序运行并且使用动态绑定来调用一个方法时,那么虚拟机必须调用同x所指向的对象的实际类型相匹配的方法版本。
...
如果类中没有写构造函数,那么系统会自动为该类提供一个默认构造函数,该构造函数将所有的实例字段初始化为默认值:
...
包用途:
Java允许把多个类收集在一起成为一组,称作包(package)。包便于组织任务,以及使自己的任务和其他人提供的代码库相分离。
标准Java库被分类成许多的包,其中包括java.1ang、java.util和java.net等等。标准Java包是分层次的。就像在硬盘上嵌套有各级子目录一样,可以通过层次嵌套组织包。所有的Java包都在Java和Javax包层次内
创建包
已经看到,已有的库,比如JavaAPI中的类和接口,可以导入到Java程序中。
Java API中的每一个类和接口属于一个特定的包。它包含一组相关联的类和接口,实际是对类和接口进行组织的目录结构。
例如,假定文件名是MyClass.java。它意味着在那个文件有一个、而且只能有一个public类。而且那个类的名字必须是MyClass(包括大小写形式):
packagemypackage;publicclass MyClass{……}创建可复用的类的步骤简要说明如下:
(1)定义一个public类。如果类不是public,它只能被同一包中的其他类使用。
(2)选择一个包名,并把package语句加到可复用的类的源代码文件中。
(3)编译这个类。这样,它就被放到适当的包目录结构中,以供编译器和解译器使用。
(4)把这个可复用的类导入到需要用它的程序中。现在就可以使用它了。
注意在Java语言中可以出现在类定义的括号外面的仅有两个语句,它们是package和import。
包引用---每个类名前加上完整的包名
例如,给出一个指向此包中的类的快捷方式。一旦使用import(导入)了以后,就不再需要给出完整的包名。
可以引入一个特定的类,也可以引入整个包。import语句要放在源文件的头部(但在所有package语句的下面)。例如,可以通过下面的语句引入在java.util包中的所有的类:
importjava.util.*;
然后,就可以使用
Datetoday=new Date();
而不需要在前面加上包名。也可以引入包中某个特定的类:
importjava.util.Date;
要把类放人一个包中,必须把此包的名字放在源文件头部,并且放在对包中的类进行定义的代码之前。例如,在文件Employee.java的开始部分如下:
packagecom.horstmann.corejava;publicclass Employee{……}把包中的文件放入与此完整的包名相匹配的子目录中。例如,在包com.horstmann.corejava中的所有的类文件都必须放在子目录com/horstmann/core.java(Windows下的com/horstmann/corejava)下。这是最简单的一种方法
类被存储在文件系统的子目录中。类的路径必须与所在包名相匹配。
在前面的例子中,包目录com/horstmann/corejava是程序目录的一个子目录。然而这样安排很不灵活。一般,有多个程序需要访问包文件。为了使包可以在多个程序间共享,需要做以下事情:
1)把类放在一个或多个特定的目录中,比如/home/user/classdir。此目录是包树的基本目录。如果加入了类com.horstmann.corejava.Employee,那么此类文件必须位于子目录/home/user/classdir/com/horstmann/corejava下。
2)设置类路径。类路径是其子目录包含类文件的所有基本目录的集合。classpath
已经接触过public和private访问指示符。
被标记为Public的部件可以被任何类使用,而私有部件只能被定义它们的类使用。如果没有指定public或private,那么部件(即类、方法或变量)可以被同一个包中的所有方法访问。
Java API包
为了简化面向对象的编程过程,Java系统事先设计并实现了一些体现了常用功能的标准类,如用于输入/输出的类,用于数学运算的类,用于图形用户界面设计的类,用于网络处理的类等。这些系统标准类根据实现的功能不同,可以划分成不同的集合,每个集合是一个包,合称为类库。可以引用这些包,也可以创建自己的包。
Java的类库是系统提供的已实现的标准类的集合,是Java编程的API,它可以帮助开发者方便、快捷地开发Java程序
接口主要作用是可以帮助实现类似于类的多重继承的功能。在Java中,出于简化程序结构的考虑,不再支持类间的多重继承而只支持单重继承,即一个类至多只能有一个直接父类。然而在解决实际问题的过程中,仅仅依靠单重继承在很多情况下都不能将问题的复杂性表述完整,需要其他的机制作为辅助。
接口声明
Java中声明接口的语法如下:
[public] interface 接口名[extends 父接口名列表]{ //接口体;//常量域声明[public] [static] [final] 域类型域名=常量值; //抽象方法声明[public] [abstract] 返回值方法名(参数列表) [throw异常列表];}从上面的语法规定可以看出,定义接口与定义类非常相似,实际上完全可以把接口理解成为一种特殊的类,接口是由常量和抽象方法组成的特殊类
(1)接口中的属性都是用final修饰的常量,
(2)接口中的方法都是用abstract修饰的抽象方法,在接口中只能给出这些抽象方法的方法名、返回值和参数列表,而不能定义方法体,即仅仅规定了一组信息交换、传输和处理的“接口”
接口的实现
一个类要实现某个或某几个接口时,有如下的步骤和注意事项:
(1)在类的声明部分,用implements关键字声明该类将要实现哪些接口;
次のように:
class类名implements接口{ }(2)如果实现某接口的类不是abstract的抽象类,则在类的定义部分必须实现指定接口的所有抽象方法,即为所有抽象方法定义方法体,而且方法头部分应该与接口中的定义完全一致,即有完全相同的返回值和参数列表;
(3)如果实现某接口的类是abstract的抽象类,则它可以不实现该接口所有的方法。
(4)一个类在实现某接口的抽象方法时,必须使用完全相同的方法头。
(5)接口的抽象方法,其访问限制符都已指定是public,所以类在实现方法时,必须显式地使用public修饰符。
まとめ:
多重继承是指一个子类继承多个父类。Java不支持多重继承,但Java提供了接口。
子类不能访问父类的private成员,但子类可以访问其父类的public,protected和包访问成员;要访问父类的包访问成员,子类一定要在父类的包内。
子类构造函数总是先调用(显式的或隐式地)其父类的构造函数,以创建和初始化子类的父类成员。
子类的对象可以当作其父类的对象对待,反之则不行(即向上转型)
protected访问是public和private访问之间一个保护性的中间层次。父类方法、子类方法和在同一个包内类的方法都能访问父类的protected成员,但其他方法均不能访问
一个子类对象引用可以隐式地转换成一个父类对象引用。使用显式的类型转换,可以把父类引用转换成子类引用。如果目标不是子类对象,将产生ClassCastException例外处理。