Методы в объектно-ориентированных парадигмах могут быть переопределены методами с той же сигнатурой в наследующих классах. Переменные, однако, не могут. Почему?

Википедия определяет виртуальные методы как:

В объектно-ориентированном программировании виртуальная функция или виртуальный метод - это функция или метод, поведение которых может быть переопределено в наследующем классе функцией с подпись ame [для обеспечения полиморфного поведения].

Согласно определению, каждый нестатический метод в Java по умолчанию является виртуальным , кроме методов final и private. Метод, который не может быть унаследован для полиморфного поведения, является не виртуальным методом.

Статические методы в Java никогда нельзя переопределить; следовательно, бессмысленно объявлять статический метод как final в Java, потому что сами статические методы ведут себя так же, как final методы. Их можно просто скрыть в подклассах методами с той же сигнатурой. Очевидно, это так, потому что статические методы никогда не могут иметь полиморфного поведения: метод, который переопределяется, должен достигать полиморфизма, чего нельзя сказать о статических методах.

Из предыдущего абзаца можно сделать важный вывод. Все методы в C ++ по умолчанию являются статическими, потому что никакие методы в C ++ не могут вести себя полиморфно до тех пор, пока они не будут явно объявлены виртуальными в суперклассе. Напротив, все методы в Java, кроме final, static и private, по умолчанию являются виртуальными, потому что по умолчанию они имеют полиморфное поведение (нет необходимости явно объявлять методы как виртуальные в Java, и, следовательно, в Java нет такого ключевого слова, как "virtual" ).

Теперь давайте продемонстрируем, что переменные экземпляра (статические тоже) не могут вести себя полиморфно из следующего простого примера на Java.

class Super
{
    public int a=5;
    public int show()
    {
        System.out.print("Super method called a = ");
        return a;
    }
}

final class Child extends Super
{
    public int a=6;

    @Override
    public int show()
    {
        System.out.print("Child method called a = ");
        return a;
    }
}

final public class Main
{
    public static void main(String...args)
    {
        Super s = new Child();
        Child c = new Child();

        System.out.println("s.a = "+s.a);
        System.out.println("c.a = "+c.a);        

        System.out.println(s.show());
        System.out.println(c.show());
    }
}

Результат, полученный с помощью приведенного выше фрагмента кода, выглядит следующим образом.

 s.a = 5
c.a = 6
Дочерний метод с именем a = 6
Дочерний метод с именем a = 6

В этом примере оба вызова s.show () и c.show () выполняются для метода show () через переменные типа Super и типа Child соответственно вызывают метод show () в классе Child .Это означает, что метод show () в классе Child переопределяет метод show () в классе Super , потому что оба из них иметь одинаковую подпись.

Это, однако, не может быть применено к переменной экземпляра a , объявленной в обоих классах. В этом случае sa будет относиться к a в классе Super , а display 5 и ca будет относиться к на a в классе Child и отображение 6 означает, что a в классе Child просто скрывает (и не переопределяет, как это произошло с нестатическими методами) a в классе Super .

После этого долгого обсуждения остается только один вопрос. Почему переменные экземпляра (и остальные тоже) не переопределяются? В чем заключались особые причины для внедрения такого механизма? Были бы какие-то преимущества или недостатки, если бы они были отвергнуты?

5
задан outis 28 December 2011 в 18:49
поделиться