Чи можете ви писати віртуальні функції / методи на Java?


165

Чи можна писати віртуальні методи на Java, як це можна зробити в C ++?

Або, чи є правильний підхід Java, який ви можете реалізувати, що виробляє подібну поведінку? Чи можу я отримати приклади?

Відповіді:


305

З вікіпедії

У Java всі нестатичні методи за замовчуванням є " віртуальними функціями ". Тільки методи, позначені ключовим словом остаточне , яке неможливо переоправити разом із приватними методами , які не успадковуються, є невіртуальними .


3
Ось одна з відповідей Джона Скіта .
Куазі Ірфан

Я замислювався, чи справді це правда, тому що для того, що я читав, у Java динамічна диспетчеризація методів відбувається лише для об'єкта, за допомогою якого використовується метод - як пояснено тут, тому приклад, що пояснює віртуальні функції для C ++, тут не справедливий для Java.
Брокколі

@QuaziIrfan Це різниця між Java і C #, хоча.
Sreekanth Karumanaghat

101

Чи можете ви писати віртуальні функції на Java?

Так. Насправді всі методи екземпляра на Java за замовчуванням є віртуальними. Тільки певні методи не є віртуальними:

  • Методи класу (тому що зазвичай кожен екземпляр містить інформацію, як вказівник на vtable про його конкретні методи, але жоден екземпляр тут не доступний).
  • Методи приватного екземпляра (оскільки жоден інший клас не може отримати доступ до методу, викликає екземпляр завжди має тип визначаючого класу, і тому однозначно відомий під час компіляції).

Ось кілька прикладів:

"Нормальні" віртуальні функції

Наступний приклад - зі старої версії сторінки вікіпедії, згаданої в іншій відповіді.

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

Вихід:

Я їмо, як родова тварина.
Я їмо, як риба!
Я їмо, як золота рибка!
Я їмо, як родова тварина.

Приклад з віртуальними функціями з інтерфейсами

Методи інтерфейсу 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 implement applyBrakes()
       System.out.println("Brakes applied"); //function
    }
}

Приклад з віртуальними функціями з абстрактними класами.

Подібно до інтерфейсів Анотаційні класи повинні містити віртуальні методи, оскільки вони покладаються на реалізацію класів, що розширюються. Наприклад:

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
Це має стати найбільш повною відповіддю. Він пропонує 2 способи реалізації віртуальної функції, оскільки у Java немає ключового слова. Дякую.
Крістофер Бейлз

Набагато краща відповідь, ніж цитування Вікіпедії. Починаючи з c ++ і лінуючись навчанням на Java, те, що я шукав, був абстрактним.
Девід

@David Як краще відповісти на цю відповідь? Цитування вікіпедій є повним, стислим та правильним. Ця відповідь, навпаки, не згадує слона в кімнаті: за замовчуванням всі функції на Яві (за винятком, перелічених у статті вікіпедії) є віртуальними. Ні абстрактні класи, ні інтерфейси не потрібні для віртуальних функцій, тому це лише додає оманливого шуму. І тоді це "вимагає великих навичок спілкування та глибокого оволодіння основними принципами" ... джез. Це твердження, яке є фальсифікацією. Ніхто, хто мав це, не витрачав би на нього цінний дисковий простір.
Пітер - Відновіть Моніку

Повідомлення у вікіпедії поступається і менш специфічно відповідає цій відповіді, оскільки йдеться про концепцію віртуальних функцій на будь-якій мові, а не просто на Java. Приклад, наведений на сторінці вікіпедії, написаний на С, і в кращому випадку він є неповним, і він є більш оманливим. Докладно про всі функції, що є віртуальними, і про те, що вам не потрібні абстрактні класи чи інтерфейси, щоб віртуальні функції були шумом. Я ніколи не казав, що вони потрібні, ви неправильно це прочитали. Я не розумію вашої остаточної точки, чи хочете я видалити це запитання, тому що вам це не подобається?
Ерік Лещинський

1
Тут запізнюється кілька років, але фантастична відповідь
Том О.

55

Усі функції на Java за замовчуванням є віртуальними.

Вам потрібно вийти зі свого шляху, щоб написати невіртуальні функції, додавши ключове слово «остаточне».

Це протилежне за замовчуванням C ++ / C #. Функції класу за замовчуванням є невіртуальними; ви робите їх так, додаючи "віртуальний" модифікатор.


4
приватні функції, зазначені у відповіді Клауса, також є невіртуальними.
Дон Ларинкс

9

Усі методи, які не є приватними екземплярами, за замовчуванням є Java.

У C ++ приватні методи можуть бути віртуальними. Це можна використати для ідіоми невіртуального інтерфейсу (NVI). У Java вам потрібно буде захистити методи перезапису NVI.

З специфікації мови Java, v3:

8.4.8.1 Переопределення (методами інстанцій) Метод екземпляра m1, оголошений у класі C, перекриває інший метод екземпляра, м2, оголошений у класі A, якщо все наступне є правдивим:

  1. С - підклас А.
  2. Підпис m1 - це підпис (§ 8.4.2) підпису m2.
  3. Або * m2 є загальнодоступним, захищеним або оголошеним з доступом за замовчуванням у тому ж пакеті, що і C, або * m1 перекриває метод m3, m3 відрізняється від m1, m3 відрізняється від m2, так що m3 перевищує м2.


1

У Java всі загальнодоступні (не приватні) змінні та функції за замовчуванням є Virtual . Більше того, змінні та функції, що використовують ключове слово final , не є віртуальними .


що ви маєте на увазі під "віртуальними змінними"?
неоексперт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.