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
}
}
メソッドのオーバーロードは静的多型の例です。
一方、オーバーライドは動的多型の一例です。
なぜなら、オーバーロードの場合、コンパイル時にコンパイラはどのメソッドを呼び出しにリンクするかを知っているからです。ただし、動的多型については実行時に決定されます。
動的(実行時)多型は実行時に存在する多型です。ここで、Javaコンパイラは、コンパイル時にどのメソッドが呼び出されるのか理解していません。実行時に呼び出されるメソッドはJVMだけが決定します。インスタンスメソッドを使用したメソッドのオーバーロードおよびメソッドのオーバーライドは、動的多態性の例です。
たとえば
さまざまな種類の文書をシリアライズおよびデシリアライズするアプリケーションを考えます。
基本クラスとして「Document」を、それから派生するさまざまなドキュメントタイプクラスを作成できます。例えば。 XMLDocument、WordDocumentなど.
ドキュメントクラスは 'Serialize()'および 'De-serialize()'メソッドを仮想メソッドとして定義し、各派生クラスはドキュメントの実際の内容に基づいて独自の方法でこれらのメソッドを実装します。
異なる種類の文書をシリアライズ/デシリアライズする必要がある場合、文書オブジェクトは 'Document'クラス参照(またはポインタ)によって参照され、 'Serialize()'または 'De-serialize()'メソッドが呼び出されるときに参照されます。その上で、適切なバージョンの仮想メソッドが呼び出されます。
静的(コンパイル時)ポリモーフィズムはコンパイル時に示されるポリモーフィズムです。ここで、Javaコンパイラはどのメソッドが呼び出されるのかを知っています。静的メソッドを使用したメソッドのオーバーロードとオーバーライドプライベートメソッドまたはファイナルメソッドを使用したメソッドのオーバーライドは、静的多型の例です。
たとえば
従業員オブジェクトには、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;
}
}
出力:内部コレクションのソート方法
メソッドのオーバーロードは、メソッド呼び出しとメソッド定義の間のメソッドバインディングがコンパイル時に行われ、クラスの参照(コンパイル時に作成され、スタックに移動する)に依存するため、コンパイル時/静的多相の例です。 ).
メソッドのオーバーライドは、メソッド呼び出しとメソッド定義の間のメソッドバインディングが実行時に行われ、クラスのオブジェクト(実行時に作成され、ヒープに移動するオブジェクト)に依存するため、実行時/動的多相の例です。 ).
簡単に言うと、
静的ポリモーフィズム:同じメソッド名がオーバーロードされたタイプやパラメータ数が異なる同じクラス(異なる署名)対象となるメソッド呼び出しはコンパイル時に解決されます。
動的多態性:同じ方法はオーバーライドされたと同じシグネチャで異なるクラス。メソッドが呼び出されているオブジェクトの種類はコンパイル時にはわかりませんが、実行時に決定されます。
一般的に、オーバーロードは多態性とは見なされません。
Javaチュートリアルから page :
クラスのサブクラスは、独自の独自の動作を定義しながら、親クラスと同じ機能を共有できます。
Static Polymorphism:は、どのメソッドを実行するかを決定する決定が、コンパイル時に決定される場所です。メソッドのオーバーロードはその一例です。
動的多態性:は、実行するメソッドを選択する決定を実行時に設定します。メソッドオーバーライドがこの例です。
多態性とは、オブジェクトが同じトリガーに対して異なる動作をする能力のことです。
静的多型(コンパイル時多型)
動的多態性(ランタイム多態性)
メソッドのオーバーロードは静的ポリモーフィズムとしても知られていますが、コンパイル時ポリモーフィズムまたは静的バインディングとしても知られています。引数リストとメソッドを呼び出している参照に基づいて、コンパイラによってコンパイル時に解決されます。
そしてMethod OverridingはDynamic Polymorphismまたはsimple PolymorphismまたはRuntime Method Dispatchまたは動的バインディング]として知られています。オーバーライドされたメソッド呼び出しは実行時に解決されるためです。
その理由を理解するために、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")のバイトコードは、引数リストに基づいて区別できるため、まったく異なることがわかります。そしてクラス参照。そしてこれがMethod OverloadingがStatic Polymorphismとして知られている理由です。
ただし、anyMammal.speak()とhumanMammal.speak()のバイトコードは同じです。コンパイラによれば両方のメソッドがMammal参照で呼び出されるためです。ただし、実行時にJVMは参照が保持しているオブジェクトとJVM呼び出しを認識します。メソッドのオーバーライドが動的多態性として知られているのは、オブジェクト上のメソッドとこれが理由です。
そのため、上記のコードとバイトコードから、コンパイル段階では呼び出し元のメソッドが参照型から考慮されることは明らかです。しかし実行時には、メソッドは参照が保持しているオブジェクトから呼び出されます。
これについてもっと知りたいのなら、もっと詳しく読むことができます JVMはメソッドのオーバーロードとオーバーライドを内部的に処理する方法 。
以下のコードを見てください。
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()のどの実装が実行されるのかわかりません。実行時にユーザーがどのような値を与えるのかによって決まるからです。したがって、どのメソッドが呼び出されるかについては、実行時にのみ決定されます。したがって、ランタイムポリモーフィズム。
コンパイル時ポリモーフィズム(静的バインディング/早期バインディング):静的ポリモーフィズムでは、コード内でメソッドを呼び出すと、実際にどのメソッドの定義を呼び出すかは、コンパイル時にのみ解決されます。
(または)
コンパイル時に、Javaはメソッドのシグネチャをチェックすることによってどのメソッドを呼び出すべきかを知っています。そのため、これはコンパイル時ポリモーフィズムまたは静的バインディングと呼ばれます。
動的多態性(Late Binding/Runtime Polymorphism):実行時に、Javaは実行時まで待機して、どのオブジェクトが実際に参照によって指されているかを判断します。実行時ポリモーフィズムと呼んでいるため、メソッド解決は実行時に行われました。
メソッドのオーバーロードはコンパイル時のポリモーフィズムです。その概念を理解するために例を取りましょう。
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行目で指定されたメソッド定義で解決します。メソッド呼び出しをメソッド定義で置き換えるプロセスはバインディングと呼ばれ、この場合はコンパイラーによって行われるため、早期バインディングと呼ばれます。