Puoi scrivere funzioni / metodi virtuali in Java?


165

È possibile scrivere metodi virtuali in Java, come si farebbe in C ++?

Oppure esiste un approccio Java adeguato che è possibile implementare che produce un comportamento simile? Potrei avere degli esempi, per favore?

Risposte:


305

Da Wikipedia

In Java , tutti i metodi non statici sono per impostazione predefinita " funzioni virtuali " . Solo i metodi contrassegnati con la parola chiave final , che non possono essere sovrascritti, insieme ai metodi privati , che non sono ereditati, non sono virtuali .


3
Ecco una delle risposte di Jon Skeet .
Quazi Irfan,

Mi chiedevo se fosse davvero vero, perché per quello che ho letto, in Java, l'invio di metodi dinamici avviene solo per l'oggetto su cui viene chiamato il metodo - come spiegato qui, quindi l'esempio che spiega le funzioni virtuali per C ++ qui non è valido per Java.
Broccoli,

@QuaziIrfan Questa è la differenza tra Java e C # però.
Sreekanth Karumanaghat,

101

Sai scrivere funzioni virtuali in Java?

Sì. In effetti, tutti i metodi di istanza in Java sono virtuali per impostazione predefinita. Solo alcuni metodi non sono virtuali:

  • Metodi di classe (perché in genere ogni istanza contiene informazioni come un puntatore a una vtable sui suoi metodi specifici, ma qui non è disponibile alcuna istanza).
  • Metodi di istanza privata (poiché nessun'altra classe può accedere al metodo, l'istanza chiamante ha sempre il tipo della classe di definizione stessa ed è quindi inequivocabilmente conosciuta al momento della compilazione).

Ecco alcuni esempi:

Funzioni virtuali "normali"

L'esempio seguente è tratto da una vecchia versione della pagina di Wikipedia citata in un'altra risposta.

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 {}

Produzione:

Mangio come un animale generico.
Mangio come un pesce!
Mangio come un pesce rosso!
Mangio come un animale generico.

Esempio con funzioni virtuali con interfacce

I metodi di interfaccia Java sono tutti virtuali. Essi devono essere virtuale perché si basano sulle classi di attuazione di fornire delle implementazioni del metodo. Il codice da eseguire sarà selezionato solo in fase di esecuzione.

Per esempio:

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
    }
}

Esempio con funzioni virtuali con classi astratte.

Simile alle interfacce Le classi astratte devono contenere metodi virtuali perché si basano sull'implementazione delle classi estese. Per esempio:

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.
    }
}

1
Questa deve essere la risposta più completa. Fornisce 2 modi per implementare una funzione virtuale poiché java non ha la parola chiave. Grazie.
Christopher Bales,

Risposta molto migliore della citazione di Wikipedia. Venendo dal c ++ ed essendo pigro con i miei studi Java, astratto era quello che stavo cercando.
David

@ David Come è migliore questa risposta? La citazione di Wikipedia è completa, concisa e corretta. Questa risposta, al contrario, non menziona l'elefante nella stanza: per impostazione predefinita tutte le funzioni in Java (con le eccezioni elencate nell'articolo di Wikipedia) sono virtuali. Né le classi astratte né le interfacce sono necessarie per le funzioni virtuali, quindi questo aggiunge solo rumore fuorviante. E poi questo "richiede grandi capacità comunicative e una profonda padronanza dei principi di base" ... jeez. Questa è un'affermazione auto-falsificante proprio lì: nessuno che ne avesse avuto avrebbe sprecato prezioso spazio su disco con esso.
Peter - Ripristina Monica il

Il post di Wikipedia è inferiore e meno specifico per questa risposta perché riguarda il concetto di funzioni virtuali in qualsiasi lingua, piuttosto che solo Java. L'esempio fornito nella pagina di Wikipedia è scritto in C, nella migliore delle ipotesi è incompleto ed è più fuorviante. I dettagli su tutte le funzioni sono virtuali e sul fatto che non hai bisogno di classi o interfacce astratte per avere funzioni virtuali come rumore. Non ho mai detto che sono richiesti, hai letto male quello. Non capisco il tuo ultimo punto, vuoi che elimini questa domanda perché non ti piace?
Eric Leschinski,

1
Pochi anni dopo qui, ma risposta fantastica
Tom O.

55

Tutte le funzioni in Java sono virtuali per impostazione predefinita.

Devi fare di tutto per scrivere funzioni non virtuali aggiungendo la parola chiave "finale".

Questo è l'opposto del valore predefinito C ++ / C #. Le funzioni di classe sono non virtuali per impostazione predefinita; li rendi così aggiungendo il modificatore "virtuale".


4
Anche le funzioni private come indicato nella risposta di Klaus non sono virtuali.
Don Larynx,

9

Tutti i metodi di istanza non privati sono virtuali per impostazione predefinita in Java.

In C ++, i metodi privati ​​possono essere virtuali. Questo può essere sfruttato per il linguaggio non-virtual-interface (NVI). In Java, è necessario rendere protetti i metodi sostituibili NVI.

Da Java Language Specification, v3:

8.4.8.1 Sostituzione (con metodi di istanza) Un metodo di istanza m1 dichiarato in una classe C ignora un altro metodo di istanza, m2, dichiarato in classe A se sono vere tutte le seguenti condizioni:

  1. C è una sottoclasse di A.
  2. La firma di m1 è una sottoscrizione (§8.4.2) della firma di m2.
  3. * M2 è pubblico, protetto o dichiarato con accesso predefinito nello stesso pacchetto di C, oppure * m1 ignora un metodo m3, m3 distinto da m1, m3 distinto da m2, in modo tale che m3 ignori m2.


1

In Java, tutte le variabili e le funzioni pubbliche (non private) sono Virtuali per impostazione predefinita. Inoltre, le variabili e le funzioni che utilizzano la parola chiave final non sono virtuali .


cosa intendi con "variabili virtuali"?
neoexpert,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.