¿Puedes escribir funciones / métodos virtuales en Java?

166

¿Es posible escribir métodos virtuales en Java, como se haría en C ++?

¿O existe un enfoque Java adecuado que pueda implementar que produzca un comportamiento similar? ¿Podría por favor tener algunos ejemplos?

yonatan
fuente

Respuestas:

306

De wikipedia

En Java , todos los métodos no estáticos son por defecto " funciones virtuales " . Solo los métodos marcados con la palabra clave final , que no pueden anularse, junto con los métodos privados , que no se heredan, no son virtuales .

Klaus Byskov Pedersen
fuente
3
Aquí está una de las respuestas de Jon Skeet .
Quazi Irfan
Me preguntaba si es realmente cierto, porque por lo que he leído, en Java, el despacho dinámico de métodos ocurre solo para el objeto al que se llama el método, como se explica aquí, por lo que el ejemplo que explica las funciones virtuales para C ++ aquí no es válido para Java.
Brócoli
@QuaziIrfan Sin embargo, esa es la diferencia entre Java y C #.
Sreekanth Karumanaghat
101

¿Puedes escribir funciones virtuales en Java?

Si. De hecho, todos los métodos de instancia en Java son virtuales por defecto. Solo ciertos métodos no son virtuales:

  • Métodos de clase (porque generalmente cada instancia contiene información como un puntero a una tabla v sobre sus métodos específicos, pero aquí no hay ninguna instancia disponible).
  • Métodos de instancias privadas (debido a que ninguna otra clase puede acceder al método, la instancia que realiza la llamada siempre tiene el tipo de la clase definitoria y, por lo tanto, es inequívocamente conocida en tiempo de compilación).

Aquí hay unos ejemplos:

Funciones virtuales "normales"

El siguiente ejemplo es de una versión anterior de la página de Wikipedia mencionada en otra respuesta.

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

Salida:

Como como un animal genérico.
¡Como como un pez!
¡Como como un pez dorado!
Como como un animal genérico.

Ejemplo con funciones virtuales con interfaces

Los métodos de la interfaz Java son todos virtuales. Ellos deben ser virtual porque se basan en las clases que implementan para proporcionar las implementaciones de métodos. El código a ejecutar solo se seleccionará en tiempo de ejecución.

Por ejemplo:

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

Ejemplo con funciones virtuales con clases abstractas.

Similar a las interfaces Las clases abstractas deben contener métodos virtuales porque dependen de la implementación de las clases extendidas. Por ejemplo:

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
fuente
1
Esta tiene que ser la respuesta más completa. Proporciona 2 formas de implementar una función virtual ya que Java no tiene la palabra clave. Gracias.
Christopher Bales
Respuesta mucho mejor que la cita de Wikipedia. Viniendo de c ++ y siendo flojo con mis estudios de Java, resumen era lo que estaba buscando.
David
@David ¿Cómo es mejor esta respuesta? La cita de wikipedia es completa, concisa y correcta. Esta respuesta, por el contrario, no menciona al elefante en la sala: por defecto, todas las funciones en Java (con las excepciones enumeradas en el artículo de Wikipedia) son virtuales. Ni las clases abstractas ni las interfaces son necesarias para las funciones virtuales, por lo que eso solo agrega ruido engañoso. Y luego esto "requiere grandes habilidades de comunicación y un profundo dominio de los principios subyacentes" ... por Dios. Esa es una declaración de auto falsificación: nadie que tenga eso desperdiciará un valioso espacio en el disco.
Peter - Restablece a Mónica el
La publicación de wikipedia es inferior y menos específica a esta respuesta porque trata sobre el concepto de funciones virtuales en cualquier idioma, en lugar de solo Java. El ejemplo dado en la página de Wikipedia está escrito en C, y en el mejor de los casos es incompleto, y es más engañoso. El detalle acerca de que todas las funciones son virtuales y que no se necesitan clases abstractas o interfaces para que las funciones virtuales sean ruidosas. Nunca dije que fueran obligatorios, lo leíste mal. No entiendo tu punto final, ¿quieres que elimine esta pregunta porque no te gusta?
Eric Leschinski
1
Pocos años tarde aquí pero respuesta fantástica
Tom O.
55

Todas las funciones en Java son virtuales por defecto.

Debe hacer todo lo posible para escribir funciones no virtuales agregando la palabra clave "final".

Esto es lo opuesto al valor predeterminado de C ++ / C #. Las funciones de clase no son virtuales por defecto; los haces agregando el modificador "virtual".

duffymo
fuente
44
Las funciones privadas como se indica en la respuesta de Klaus también no son virtuales.
Don Larynx
9

Todos los métodos de instancias no privadas son virtuales por defecto en Java.

En C ++, los métodos privados pueden ser virtuales. Esto puede explotarse para el lenguaje de interfaz no virtual (NVI). En Java, necesitaría proteger los métodos anulables de NVI.

De la especificación del lenguaje Java, v3:

8.4.8.1 Anulación (por métodos de instancia) Un método de instancia m1 declarado en una clase C anula otro método de instancia, m2, declarado en la clase A si se cumple todo lo siguiente:

  1. C es una subclase de A.
  2. La firma de m1 es una sub firma (§8.4.2) de la firma de m2.
  3. * * M2 es público, está protegido o declarado con acceso predeterminado en el mismo paquete que C, o * m1 anula un método m3, m3 distinto de m1, m3 distinto de m2, de modo que m3 anula m2.
Andy Thomas
fuente
4

Sí, puedes escribir "funciones" virtuales en Java.

RepDetec
fuente
1

En Java, todas las variables y funciones públicas (no privadas) son virtuales de forma predeterminada. Además, las variables y funciones que usan la palabra clave final no son virtuales .

Parvej Ahmed
fuente
¿Qué quieres decir con "variables virtuales"?
neoexpert