誰かがJavaの動的ポリモーフィズムと静的ポリモーフィズムの違いを説明する簡単な例を提供できますか?
誰かがJavaの動的ポリモーフィズムと静的ポリモーフィズムの違いを説明する簡単な例を提供できますか?
回答:
ポリモーフィズム
1.静的バインディング/コンパイル時バインディング/早期バインディング/メソッドのオーバーロード(同じクラス内)
2.動的バインディング/実行時バインディング/遅延バインディング/メソッドのオーバーライド。(異なるクラスで)
class Calculation {
void sum(int a,int b){System.out.println(a+b);}
void sum(int a,int b,int c){System.out.println(a+b+c);}
public static void main(String args[]) {
Calculation obj=new Calculation();
obj.sum(10,10,10); // 30
obj.sum(20,20); //40
}
}
class Animal {
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move();//output: Animals can move
b.move();//output:Dogs can walk and run
}
}
Animal reference but Dog object
なぜ使用できないのDog reference and dog object
ですか?
動的(実行時)ポリモーフィズムは、実行時に存在したポリモーフィズムです。ここでは、Javaコンパイラーはコンパイル時に呼び出されるメソッドを理解していません。実行時に呼び出されるメソッドを決定するのはJVMだけです。メソッドのオーバーロードとインスタンスメソッドを使用したメソッドのオーバーライドは、動的なポリモーフィズムの例です。
例えば、
さまざまな種類のドキュメントをシリアル化および逆シリアル化するアプリケーションを考えてみましょう。
基本クラスとして 'Document'を持ち、それから派生するさまざまなドキュメントタイプクラスを持つことができます。たとえば、XMLDocument、WordDocumentなど。
ドキュメントクラスは 'Serialize()'および 'De-serialize()'メソッドを仮想として定義し、各派生クラスはドキュメントの実際のコンテンツに基づいて独自の方法でこれらのメソッドを実装します。
さまざまなタイプのドキュメントをシリアル化/シリアル化解除する必要がある場合、ドキュメントオブジェクトは「Document」クラス参照(またはポインタ)によって参照され、「Serialize()」または「De-serialize()」メソッドが呼び出されたときにその上で、仮想メソッドの適切なバージョンが呼び出されます。
静的(コンパイル時)多態性は、コンパイル時に示される多態性です。ここで、Javaコンパイラーはどのメソッドが呼び出されるかを認識しています。静的メソッドを使用したメソッドのオーバーロードとメソッドのオーバーライド。プライベートメソッドまたはfinalメソッドを使用してオーバーライドするメソッドは、静的ポリモーフィズムの例です。
例えば、
従業員オブジェクトには2つのprint()メソッドがあり、1つは引数を取らず、もう1つは従業員データとともに表示されるプレフィックス文字列を取ります。
これらのインターフェースの場合、引数なしでprint()メソッドが呼び出されると、コンパイラーは関数の引数を見て、どの関数が呼び出されるかを認識し、それに応じてオブジェクトコードを生成します。
詳細については、「ポリモーフィズムとは」(Google it)をお読みください。
バインディングとは、メソッド呼び出しとメソッド定義の間のリンクを指します。
この写真は、拘束力のあるものを明確に示しています。
この図では、「a1.methodOne()」呼び出しは対応するmethodOne()定義にバインドされており、「a1.methodTwo()」呼び出しは対応するmethodTwo()定義にバインドされています。
すべてのメソッド呼び出しには、適切なメソッド定義が必要です。これはJavaのルールです。コンパイラーがすべてのメソッド呼び出しの適切なメソッド定義を認識しない場合、エラーがスローされます。
ここで、Javaの静的バインディングと動的バインディングについて説明します。
Javaの静的バインディング:
静的バインディングは、コンパイル中に発生するバインディングです。プログラムが実際に実行される前にバインディングが行われるため、事前バインディングとも呼ばれます。
。
静的バインディングは、下の図のように示されます。
この図では、 'a1'はクラスAのオブジェクトを指すクラスAの参照変数です。'a2 'もクラスAの参照変数ですが、クラスBのオブジェクトを指します。
コンパイル中、バインド中、コンパイラは特定の参照変数が指しているオブジェクトのタイプをチェックしません。メソッドが呼び出される参照変数のタイプをチェックし、そのタイプのメソッド定義が存在するかどうかをチェックするだけです。
たとえば、上の図の「a1.method()」メソッド呼び出しの場合、コンパイラーはクラスAにmethod()のメソッド定義が存在するかどうかをチェックします。「a1」はクラスAタイプなので、同様に、「a2.method()」メソッド呼び出しの場合、クラスAにmethod()のメソッド定義が存在するかどうかを確認します。「a2」もクラスAタイプであるためです。'a1'と 'a2'が指しているオブジェクトはチェックしません。このタイプのバインディングは静的バインディングと呼ばれます。
Javaの動的バインディング:
動的バインディングは、実行時に発生するバインディングです。プログラムが実際に実行されているときにバインディングが発生するため、遅延バインディングとも呼ばれます。
実行時には、実際のオブジェクトがバインドに使用されます。たとえば、上の図の「a1.method()」呼び出しでは、「a1」が指している実際のオブジェクトのmethod()が呼び出されます。「a2.method()」呼び出しでは、「a2」が指している実際のオブジェクトのmethod()が呼び出されます。このタイプのバインディングは動的バインディングと呼ばれます。
上記の例の動的バインディングは、以下のように示すことができます。
ポリモーフィズム: ポリモーフィズムは、オブジェクトがさまざまな形をとる能力です。OOPでのポリモーフィズムの最も一般的な使用法は、親クラス参照を使用して子クラスオブジェクトを参照する場合に発生します。
動的バインディング/実行時ポリモーフィズム:
実行時のポリモーフィズムは、メソッドのオーバーライドとも呼ばれます。このメカニズムでは、オーバーライドされた関数の呼び出しが実行時に解決されます。
public class DynamicBindingTest {
public static void main(String args[]) {
Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
vehicle.start(); //Car's start called because start() is overridden method
}
}
class Vehicle {
public void start() {
System.out.println("Inside start method of Vehicle");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("Inside start method of Car");
}
}
出力:
車内スタート方法
静的バインディング/コンパイル時のポリモーフィズム:
どのメソッドを呼び出すかは、コンパイル時にのみ決定されます。
public class StaticBindingTest {
public static void main(String args[]) {
Collection c = new HashSet();
StaticBindingTest et = new StaticBindingTest();
et.sort(c);
}
//overloaded method takes Collection argument
public Collection sort(Collection c){
System.out.println("Inside Collection sort method");
return c;
}
//another overloaded method which takes HashSet argument which is sub class
public Collection sort(HashSet hs){
System.out.println("Inside HashSet sort method");
return hs;
}
}
出力:Inside Collection sort metho
簡単な言葉で :
静的ポリモーフィズム:同じメソッド名が、同じクラスの異なる型または数のパラメーターでオーバーロードされています(異なるシグニチャー)。ターゲットメソッドの呼び出しはコンパイル時に解決されます。
動的ポリモーフィズム:同じメソッドが異なるクラスの同じシグネチャでオーバーライドされます。メソッドが呼び出されているオブジェクトのタイプはコンパイル時には不明ですが、実行時に決定されます。
一般的に、オーバーロードはポリモーフィズムとは見なされません。
Javaチュートリアルページから:
クラスのサブクラスは、独自の動作を定義しながら、親クラスと同じ機能の一部を共有できます
Generally overloading won't be considered as polymorphism.
この点について詳しく教えてください。
メソッドのオーバーロードは静的ポリモーフィズムと呼ばれ、コンパイル時ポリモーフィズムまたは静的バインディングとも呼ばれますます。オーバーロードされたメソッド呼び出しは、引数リストと、メソッドを呼び出す参照に基づいて、コンパイラーによってコンパイル時に解決されるためです。
また、オーバーライドされたメソッド呼び出しは実行時に解決されるため、メソッドのオーバーライドは、動的ポリモーフィズムまたは単純なポリモーフィズムまたはランタイムメソッドディスパッチまたはダイナミックバインディングとして知られています。
なぜそうなのかを理解するためにMammal
、Human
クラスとクラスの例を見てみましょう
class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
class Human extends Mammal {
@Override
public void speak() { System.out.println("Hello"); }
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
}
以下のコード行に出力とバイトコードを含めました
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
上記のコードを見ると、humanMammal.speak()、human.speak()、およびhuman.speak( "Hindi")のバイトコードは、コンパイラが引数リストに基づいて区別できるため、まったく異なることがわかります。およびクラス参照。これが、メソッドのオーバーロードが静的ポリモーフィズムとして知られている理由ですです。
しかし、anyMammal.speak()とhumanMammal.speak()のバイトコードは同じです。コンパイラによれば、両方のメソッドが哺乳類参照で呼び出されますが、実行時にJVMは参照が保持しているオブジェクトとJVM呼び出しを知っているため、両方のメソッド呼び出しの出力は異なります。オブジェクトのメソッド。これがメソッドのオーバーライドが動的ポリモーフィズムとして知られている理由です。
したがって、上記のコードとバイトコードから、コンパイル段階でメソッドの呼び出しが参照型から考慮されることは明らかです。ただし、実行時には、参照が保持しているオブジェクトからメソッドが呼び出されます。
これについて詳しく知りたい場合は、JVMによるメソッドのオーバーロードと内部でのオーバーライドの処理方法を参照してください。
多態性とは、同じトリガーに対して異なる動作をするオブジェクトの機能を指します。
静的ポリモーフィズム(コンパイル時ポリモーフィズム)
動的ポリモーフィズム(実行時ポリモーフィズム)
コンパイル時のポリモーフィズム(静的バインディング/早期バインディング):静的ポリモーフィズムでは、コードでメソッドを呼び出すと、そのメソッドのどの定義が実際に呼び出されるかは、コンパイル時にのみ解決されます。
(または)
コンパイル時に、Javaはメソッドシグネチャをチェックすることにより、どのメソッドを呼び出すかを認識します。したがって、これはコンパイル時のポリモーフィズムまたは静的バインディングと呼ばれます。
動的ポリモーフィズム(遅延バインディング/実行時ポリモーフィズム):実行時に、Javaは実行時まで待機して、参照によって実際に参照されているオブジェクトを判別します。メソッドの解決は実行時に行われました。これは、ランタイムポリモーフィズムと呼ばれるためです。
以下のコードを検討してください:
public class X
{
public void methodA() // Base class method
{
System.out.println ("hello, I'm methodA of class X");
}
}
public class Y extends X
{
public void methodA() // Derived Class method
{
System.out.println ("hello, I'm methodA of class Y");
}
}
public class Z
{
public static void main (String args []) {
//this takes input from the user during runtime
System.out.println("Enter x or y");
Scanner scanner = new Scanner(System.in);
String value= scanner.nextLine();
X obj1 = null;
if(value.equals("x"))
obj1 = new X(); // Reference and object X
else if(value.equals("y"))
obj2 = new Y(); // X reference but Y object
else
System.out.println("Invalid param value");
obj1.methodA();
}
}
コードを見ると、実行時にmethodA()のどの実装が実行されるかはわかりません。これは、実行時にユーザーが指定する値に依存するためです。したがって、どのメソッドが呼び出されるかは、実行時にのみ決定されます。したがって、ランタイムポリモーフィズム。
メソッドのオーバーロードはコンパイル時のポリモーフィズムです。例を見て、概念を理解しましょう。
class Person //person.java file
{
public static void main ( String[] args )
{
Eat e = new Eat();
e.eat(noodle); //line 6
}
void eat (Noodles n) //Noodles is a object line 8
{
}
void eat ( Pizza p) //Pizza is a object
{
}
}
この例では、Personにeatメソッドがあり、PizzaまたはNoodlesのいずれかを食べることができることを表しています。このPerson.javaをコンパイルすると、メソッドeatがオーバーロードされます。コンパイラは、メソッド呼び出し "e.eat(noodles)[6行目]]を8行目に指定されたメソッド定義で解決します。つまり、noodlesをパラメータとして受け取るメソッドです。プロセス全体がコンパイラによって行われるため、コンパイル時のポリモーフィズムになります。メソッド呼び出しをメソッド定義で置き換えるプロセスはバインディングと呼ばれます。この場合、コンパイラによって行われるため、アーリーバインディングと呼ばれます。
Nareshの回答に続き、動的ポリモーフィズムはJavaでは「動的」に過ぎません。これは、仮想マシンが存在し、ネイティブに実行されているコードではなく実行時にコードを解釈する機能があるためです。
C ++では、明らかにgccを使用してネイティブバイナリにコンパイルされている場合、コンパイル時に解決する必要があります。ただし、仮想テーブルでのランタイムジャンプとサンクは、引き続き「ルックアップ」または「ダイナミック」と呼ばれます。CがBを継承し、を宣言するとB* b = new C(); b->method1();
、bはC内のBオブジェクトを指すようにコンパイラーによって解決されます(単純なクラスがクラスの状況を継承する場合、CとC内のBオブジェクトは同じメモリアドレスから始まるため、何もありません。実行する必要があります。両方が使用するvptrをポイントします)。CがBとAを継承する場合、method1のCエントリ内のAオブジェクトの仮想関数テーブルには、カプセル化しているCオブジェクトの先頭へのポインターをオフセットし、それを実際のA :: method1()に渡すサンクがあります。 Cがオーバーライドしたテキストセグメント内。ためにC* c = new C(); c->method1()
、cはすでに外側のCオブジェクトを指しており、ポインタはテキストセグメントのC :: method1()に渡されます。参照:http : //www.programmersought.com/article/2572545946/
Javaでは、のB b = new C(); b.method1();
場合、仮想マシンはbとペアになっているオブジェクトのタイプを動的にチェックし、正しいポインタを渡して正しいメソッドを呼び出すことができます。仮想マシンの追加のステップにより、コンパイル時に既知である場合でも、コンパイル時に解決される仮想関数テーブルまたは型の必要がなくなります。これは、仮想マシンが関与し、コードがバイトコードにのみコンパイルされる場合に意味のある別の方法です。