仮想関数はC#とJavaでどのように機能しますか?
C++と同様の同じvtableおよびvpointerの概念を使用していますか、それともまったく異なるものですか?
コーディングインタビュアーはこの質問が大好きです。はい。 Javaには仮想キーワードがありませんが、Javaには仮想関数があり、それらを記述できます。
オブジェクト指向プログラミングでは、 仮想関数 または仮想メソッドは、継承クラス内で同じシグネチャを持つ関数によって動作をオーバーライドできる関数またはメソッドです。この概念は、オブジェクト指向プログラミング(OOP)のポリモーフィズム部分の非常に重要な部分です。
このような特定の言語についてアーキテクチャの質問をするためには、優れたコミュニケーションスキルと、Javaコンパイラ、特にインターフェイス、抽象クラス、および継承のしくみ)の基本原則を深く習得する必要があります。
インタビュアーを仮想関数の特定の例に導きます。
はい、仮想関数をJavaインターフェイス付きで記述できます。
Java インターフェースメソッド は、オーバーライドされるように設計されているため、すべて「純粋な仮想」です。例えば:
interface Bicycle { //the function applyBrakes() is virtual because
void applyBrakes(); //functions in interfaces are designed to be
} //overridden.
class ACMEBicycle implements Bicycle {
public void applyBrakes(){ //Here we implementing applyBrakes()
System.out.println("Brakes applied"); //function, proving it is virtual.
}
}
はい、仮想関数をJava抽象クラスで記述できます。
Java 抽象クラス 暗黙的に「仮想」メソッドが含まれ、それを拡張するクラスによって実装されます。例えば:
abstract class Dog {
final void bark() { //bark() is not virtual because it is
System.out.println("woof"); //final and if you tried to override it
} //you would get a compile time error.
abstract void jump(); //jump() is a virtual function because it
} //is part of an abstract class and isn't
//final.
class MyDog extends Dog{
void jump(){
System.out.println("boing"); //here jump() is being overridden, a
} //demonstration that it is virtual.
}
public class Runner {
public static void main(String[] args) {
MyDog myDog = new MyDog(); //instantiating myDog
myDog.jump(); //calling the overridden function jump()
}
}
関数をfinal
にすることで、ジェネリッククラスで関数を仮想化しないように強制できます。
例えば:
class myJavaFoobarClass {
final boolean giveMeTrueFunction() //this Java function is NOT virtual
{ //because final keyword prevents this
return true; //function from being modified in a
} //subclass.
boolean isItRainingFunction() //this Java function IS virtual because
{ //without the final keyword, the function
return false; //can be overridden in a subclass.
}
}
少なくともJava)には仮想キーワードはありません。
呼び出しているメソッドの最も派生したバージョンに解決されるだけです...
class A{
void sayhi(){ System.out.println("A");}
}
class B extends A{
void sayhi(){ System.out.println("B");}
}
A a = new B();
a.sayhi();
「B」を印刷します。
クラスAbstractを宣言し、純粋仮想メソッドを宣言したが実装しないままにしておくことで、「純粋仮想」メソッドを作成できます。または、class/extendsの代わりにinterface/implementsを使用します。インターフェイスは基本的に、すべてのメソッドが純粋な仮想であるクラスです。これには、C++とは異なり、Javaクラスは他の1つのクラスしか直接継承できないため、クラスが複数のインターフェイスを実装できるという追加のボーナスがあります。
編集:
あなたのコメントに応えて、Naveen:
A a = new A();と言った場合a.sayhi(); 「A」と表示されます。
Javaの用語は動的です。仮想と考えることもできますが、一部のJava開発者。C++を知らない開発者は少なくとも。Javaには明示的なポインタがないため、仮想/非仮想について心配する必要はありません。VTableはありません。クラスとその祖先を見つけるまで、クラスとその祖先をバックトラックするだけです。必要なメソッドの実装。継承は1つしかないため、コンストラクターの順序について心配する必要はありません(常にボトムアップです)。
C++では、仮想メソッドがあり、次のようなことを行うと、異なる動作が発生します。
a->sayhi();
ここで、aはA *であり、代わりにBのインスタンスを指しています。
a.sayhi();
ここで、aはタイプBのオブジェクトを保持するタイプAのオブジェクトでした。
Java仮想関数は完全に異なります。Javaでは、仮想関数はそのサブクラスでオーバーライドできる関数を意味します。したがって、Javaのすべての非静的メソッドは仮想関数です。final関数とprivate関数のみが継承されないため、仮想関数ではありません。
したがって、finalおよびprivateではないすべての非静的関数はJavaの仮想関数であると言えます。
ポリモーフィズムをサポートするすべての言語は、vtablesを使用して、正しい関数へのメソッド呼び出しを解決します。したがって、Javaおよび.NET。
どちらも中間言語(.NETの場合はIL、Javaの場合はバイトコード)にコンパイルされますが、vtableはこの中間言語では表示されません。基盤となるエンジン(CLR for .NET)でサポートされています
Javaはバイナリ互換性をサポートできるため、vtablesを使用しないと確信しています。
明確にするために:vtableは、派生/サブクラスがコンパイルされるときに構築されます。ベース/スーパークラスのレイアウトが変更された場合は、d/sのvtableを再コンパイルする必要があります。 Javaでは、これは当てはまりません。d/ sを再コンパイルせずにb/sを変更できます。
うーん。実行時にvtableが構築される可能性があります。クラスがロードされたとき。この場合、JavaとC++は同じですが、異なります。