Können Sie virtuelle Funktionen / Methoden in Java schreiben?

165

Ist es möglich, virtuelle Methoden in Java zu schreiben , wie dies in C ++ der Fall wäre?

Oder gibt es einen geeigneten Java-Ansatz, den Sie implementieren können und der ein ähnliches Verhalten erzeugt? Könnte ich bitte einige Beispiele haben?

Yonatan
quelle

Antworten:

305

Aus Wikipedia

In Java sind alle nicht statischen Methoden standardmäßig " virtuelle Funktionen ". Nur Methoden, die mit dem Schlüsselwort final gekennzeichnet sind und nicht überschrieben werden können, sowie private Methoden , die nicht vererbt werden, sind nicht virtuell .

Klaus Byskov Pedersen
quelle
3
Hier ist eine Antwort von Jon Skeet .
Quazi Irfan
Ich habe mich gefragt, ob es wirklich stimmt, denn für das, was ich gelesen habe, findet in Java der dynamische Methodenversand nur für das Objekt statt, für das die Methode aufgerufen wird - wie hier erläutert , sodass das Beispiel, in dem virtuelle Funktionen für C ++ hier erläutert werden , für Java nicht gültig ist.
Brokkoli
@QuaziIrfan Das ist allerdings der Unterschied zwischen Java und C #.
Sreekanth Karumanaghat
101

Können Sie virtuelle Funktionen in Java schreiben?

Ja. Tatsächlich sind alle Instanzmethoden in Java standardmäßig virtuell. Nur bestimmte Methoden sind nicht virtuell:

  • Klassenmethoden (da normalerweise jede Instanz Informationen wie einen Zeiger auf eine vtable über ihre spezifischen Methoden enthält, hier jedoch keine Instanz verfügbar ist).
  • Private Instanzmethoden (da keine andere Klasse auf die Methode zugreifen kann, hat die aufrufende Instanz immer den Typ der definierenden Klasse selbst und ist daher zur Kompilierungszeit eindeutig bekannt).

Hier sind einige Beispiele:

"Normale" virtuelle Funktionen

Das folgende Beispiel stammt aus einer alten Version der Wikipedia-Seite, die in einer anderen Antwort erwähnt wurde.

import java.util.*;

public class Animal 
{
   public void eat() 
   { 
      System.out.println("I eat like a generic Animal."); 
   }

   public static void main(String[] args) 
   {
      List<Animal> animals = new LinkedList<Animal>();

      animals.add(new Animal());
      animals.add(new Fish());
      animals.add(new Goldfish());
      animals.add(new OtherAnimal());

      for (Animal currentAnimal : animals) 
      {
         currentAnimal.eat();
      }
   }
}

class Fish extends Animal 
{
   @Override
   public void eat() 
   { 
      System.out.println("I eat like a fish!"); 
   }
}

class Goldfish extends Fish 
{
   @Override
   public void eat() 
   { 
      System.out.println("I eat like a goldfish!"); 
   }
}

class OtherAnimal extends Animal {}

Ausgabe:

Ich esse wie ein generisches Tier.
Ich esse wie ein Fisch!
Ich esse wie ein Goldfisch!
Ich esse wie ein generisches Tier.

Beispiel mit virtuellen Funktionen mit Schnittstellen

Java- Schnittstellenmethoden sind alle virtuell. Sie müssen virtuell sein, da sie sich auf die implementierenden Klassen stützen, um die Methodenimplementierungen bereitzustellen. Der auszuführende Code wird nur zur Laufzeit ausgewählt.

Beispielsweise:

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 implement applyBrakes()
       System.out.println("Brakes applied"); //function
    }
}

Beispiel mit virtuellen Funktionen mit abstrakten Klassen.

Ähnlich wie Schnittstellen Abstrakte Klassen müssen virtuelle Methoden enthalten , da sie die Umsetzung auf der Verlängerung Klassen verlassen. Beispielsweise:

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 "pure" virtual function 
}                                     
class MyDog extends Dog{
    void jump(){
        System.out.println("boing");    //here jump() is being overridden
    }                                  
}
public class Runner {
    public static void main(String[] args) {
        Dog dog = new MyDog();       // Create a MyDog and assign to plain Dog variable
        dog.jump();                  // calling the virtual function.
                                     // MyDog.jump() will be executed 
                                     // although the variable is just a plain Dog.
    }
}
Eric Leschinski
quelle
1
Dies muss die vollständigste Antwort sein. Es bietet zwei Möglichkeiten, eine virtuelle Funktion zu implementieren, da Java nicht über das Schlüsselwort verfügt. Danke dir.
Christopher Bales
Viel bessere Antwort als das Wikipedia-Zitat. Ich kam aus C ++ und war faul mit meinen Java-Studien. Ich suchte nach Abstraktem.
David
@ David Wie ist diese Antwort besser? Das Wikipedia-Zitat ist vollständig, präzise und korrekt. In dieser Antwort wird der Elefant im Raum dagegen nicht erwähnt: Standardmäßig sind alle Funktionen in Java (mit den im Wikipedia-Artikel aufgeführten Ausnahmen) virtuell. Weder abstrakte Klassen noch Schnittstellen sind für virtuelle Funktionen erforderlich, sodass nur irreführendes Rauschen entsteht. Und dann "erfordert dies große Kommunikationsfähigkeiten und eine tiefe Beherrschung der zugrunde liegenden Prinzipien" ... Herrgott. Das ist genau dort eine selbstverfälschende Aussage: Niemand, der das hatte, würde damit wertvollen Speicherplatz verschwenden.
Peter - Stellen Sie Monica
Der Wikipedia-Beitrag ist minderwertig und weniger spezifisch für diese Antwort, da es um das Konzept virtueller Funktionen in jeder Sprache geht und nicht nur um Java. Das Beispiel auf der Wikipedia-Seite ist in C geschrieben, bestenfalls unvollständig und irreführender. Das Detail, dass alle Funktionen virtuell sind und dass Sie keine abstrakten Klassen oder Schnittstellen benötigen, damit virtuelle Funktionen Rauschen sind. Ich habe nie gesagt, dass sie benötigt werden, das hast du falsch verstanden. Ich verstehe Ihren letzten Punkt nicht. Soll ich diese Frage löschen, weil sie Ihnen nicht gefällt?
Eric Leschinski
1
Ein paar Jahre zu spät hier, aber fantastische Antwort
Tom O.
55

Alle Funktionen in Java sind standardmäßig virtuell.

Sie müssen sich alle Mühe geben, um nicht virtuelle Funktionen zu schreiben, indem Sie das Schlüsselwort "final" hinzufügen.

Dies ist das Gegenteil des C ++ / C # -Standards. Klassenfunktionen sind standardmäßig nicht virtuell. Sie machen sie so, indem Sie den Modifikator "virtuell" hinzufügen.

Duffymo
quelle
4
private Funktionen, wie in Klaus 'Antwort angegeben, sind ebenfalls nicht virtuell.
Don Larynx
9

Alle nicht privaten Instanzmethoden sind in Java standardmäßig virtuell.

In C ++ können private Methoden virtuell sein. Dies kann für die NVI-Sprache (Non-Virtual-Interface) ausgenutzt werden. In Java müssen Sie die überschreibbaren NVI-Methoden schützen.

Aus der Java-Sprachspezifikation, Version 3:

8.4.8.1 Überschreiben (durch Instanzmethoden) Eine in einer Klasse C deklarierte Instanzmethode m1 überschreibt eine andere in Klasse A deklarierte Instanzmethode m2, wenn alle der folgenden Bedingungen erfüllt sind:

  1. C ist eine Unterklasse von A.
  2. Die Signatur von m1 ist eine Unterzeichnung (§8.4.2) der Signatur von m2.
  3. Entweder ist * m2 öffentlich, geschützt oder mit Standardzugriff im selben Paket wie C deklariert, oder * m1 überschreibt eine Methode m3, m3 verschieden von m1, m3 verschieden von m2, so dass m3 m2 überschreibt.
Andy Thomas
quelle
4

Ja, Sie können virtuelle "Funktionen" in Java schreiben.

RepDetec
quelle
1

In Java sind alle öffentlichen (nicht privaten) Variablen und Funktionen standardmäßig virtuell . Darüber hinaus sind Variablen und Funktionen, die das Schlüsselwort final verwenden, nicht virtuell .

Parvej Ahmed
quelle
Was meinst du mit "virtuellen Variablen"?
Neoexpert