Может ли Java вызвать родительский переопределенный метод в других объектах, но не в подтипе? - PullRequest
36 голосов
/ 23 июня 2009

здесь работает код java

class Cup {
    public String sayColor() {
        return "i have a color .";
    }
}

class TCup extends Cup{
    public String sayColor(){
        System.out.println(super.getClass().getName());
        return super.sayColor()+"color is tee green.";
    }
}

class MyTCup extends TCup {
    public String sayColor(){
        System.out.println(super.getClass().getName());
        return super.sayColor()+"but brushed to red now!";
    }
}
class Test {
    public static void main(String[] args) {
        Cup c = new MyTCup();
        System.out.print(c.sayColor());
    }
}

и запускает тестовый класс печатает

MyTCup
MyTCup
i have a color .color is tee green.but brushed to red now!

вопрос 1: Во время выполнения типом объекта C является MyTCup, но он всегда может вызывать супер-метод. Если в MyTCup после инициализации объекта есть стек методов в памяти, а затем он может вызываться во время выполнения, как в коде?

вопрос 2: Нет никакого способа вызвать метод super в других объектах. Как я знаю, c ++ может привести к вызову родительского метода в любое время. Почему такой дизайн Java?

Ответы [ 4 ]

68 голосов
/ 23 июня 2009

Вы не можете вызывать метод super в других объектах - это нарушит инкапсуляцию. Все дело в том, что объект управляет тем, что делают его переопределенные методы. Например, вы можете переопределить метод add коллекции, чтобы вызвать исключение при определенных обстоятельствах, чтобы он мог гарантировать, что в коллекцию были добавлены только «правильные» элементы. Это было бы бессмысленно, если бы вызывающие абоненты могли просто обойти это с броском!

Единственная причина, по которой объект получает вызов super.foo() для себя - это возможность реализовать один вызов с помощью родительской реализации. Это зависит от кода в классе, чтобы убедиться, что он делает это только разумно. Опять же, чтобы взять пример надстройки в коллекции, если коллекция переопределяет add, она должна иметь некоторый способ добавления проверенного элемента в коллекцию, который он будет делать с super.add().

Обратите внимание, что по той же причине инкапсуляции вы можете только вызывать родительскую реализацию, а не реализацию прародителя - так что super.foo() допустимо, но super.super.foo() нет.

1 голос
/ 23 июня 2009

1

Ваш вопрос не совсем понятен. Что вы подразумеваете под «вызывать во время выполнения, как код»? Если вы спрашиваете, как экземпляр c знает, что такое его суперкласс, тогда да, иерархия классов хранится в памяти и может быть доступна для виртуальной машины.

2

Java действительно позволяет вам приводить экземпляр к его родителю. Просто при вызове метода для экземпляра всегда используется фактический класс экземпляра, а не его класс времени компиляции. То есть в Java все методы являются так называемыми «виртуальными» в C ++. Почему это было решено, я не знаю.

Редактировать: На самом деле Джон Скит очень хорошо объясняет, почему нельзя вызвать метод суперкласса для экземпляра подкласса, поэтому теперь я знаю: -).

0 голосов
/ 26 сентября 2016

На самом деле вы можете, но вы должны использовать методологию, чтобы она работала только с вашим кодом.
В суперклассе добавьте параметр «Class» в метод, например:

public String sayColor(Class classFilter){...

теперь при каждом переопределении вы проверяете, является ли текущий подкласс одним из указанных фильтров, например:

if(TCup.class!=classFilter)return super.sayColor(classFilter);
return "some text for TCup only";

Я кодировал эксклюзивным способом. Вы можете добавить больше параметров или сравнить с нулем, чтобы объединить результаты с суперклассами, используя свое творчество:)

0 голосов
/ 18 июля 2011

Вы можете определить новый вспомогательный метод в подклассе так, чтобы вы не переопределяли оригинал - вызовите это - он может вызвать супер метод или нет, в зависимости от того, что вы хотите.

...