Почему super.super.method (); не позволенный в Java?

Попробуйте преобразовать id_eval в строку, подобную этой.

type Props = {
};

type State = {
    id_evaluation: string,
};

class Evaluation extends Component < Props, State > {
    state = {
        id_evaluation: '1',
    }

    componentDidMount() {
        const id_eval = getEvaluation();

        this.setState({
            id_evaluation: String(id_eval) || '',
        });
347
задан Community 23 May 2017 в 02:10
поделиться

9 ответов

Это нарушает инкапсуляцию. Вы не должны быть в состоянии обойти поведение родительского класса. Имеет смысл иногда быть в состоянии обойти Ваш собственный поведение класса (особенно из того же метода), но не Ваш родитель. Например, предположите, что у нас есть основной "набор объектов", подкласс, представляющий "набор красных объектов" и подкласса того представления "набора больших красных объектов". Имеет смысл иметь:

public class Items
{
    public void add(Item item) { ... }
}

public class RedItems extends Items
{
    @Override
    public void add(Item item)
    {
        if (!item.isRed())
        {
            throw new NotRedItemException();
        }
        super.add(item);
    }
}

public class BigRedItems extends RedItems
{
    @Override
    public void add(Item item)
    {
        if (!item.isBig())
        {
            throw new NotBigItemException();
        }
        super.add(item);
    }
}

Это прекрасно - RedItems может всегда быть уверен, что объекты, которые он содержит, являются полностью красными. Теперь предположите, что мы были способны назвать super.super.add ():

public class NaughtyItems extends RedItems
{
    @Override
    public void add(Item item)
    {
        // I don't care if it's red or not. Take that, RedItems!
        super.super.add(item);
    }
}

Теперь мы могли добавить, что мы любим, и инвариант в RedItems повреждается.

, который имеет смысл?

465
ответ дан Jon Skeet 23 November 2019 в 00:28
поделиться

В предположении, потому что это не используется настолько часто. Единственная причина я видел использование его, состоит в том, если Ваш прямой родитель переопределил некоторую функциональность, и Вы пытаетесь восстановить его назад к оригиналу.

, Который, кажется, мне против принципов OO, так как прямой родитель класса должен быть более тесно связан с Вашим классом, чем прародитель.

3
ответ дан Powerlord 23 November 2019 в 00:28
поделиться

Я думаю, перезаписываете ли Вы метод и хотите ко всей версии суперкласса ее (как, говорите для equals), тогда Вы фактически всегда хотите назвать прямую версию суперкласса сначала, которую назовет своей версией суперкласса в свою очередь, если она хочет.

я думаю, что это только редко имеет смысл (если вообще. я не могу думать о случае, где он делает) назвать версию некоторого произвольного суперкласса метода. Я не знаю, возможно ли это вообще в Java. Это может быть сделано в C++:

this->ReallyTheBase::foo();
4
ответ дан Johannes Schaub - litb 23 November 2019 в 00:28
поделиться

В дополнение к правильным замечаниям, которые сделали другие, я думаю, что существует другая причина: что, если суперкласс не имеет суперкласса?

, Так как каждый класс естественно расширяется (по крайней мере) Object, super.whatever() будут всегда обращаться к методу в суперклассе. Но что, если бы Ваш класс только расширяет Object - к чему super.super относился бы тогда? Как то поведение должно быть обработано - ошибка компилятора, NullPointer, и т.д.?

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

6
ответ дан matt b 23 November 2019 в 00:28
поделиться

У меня нет достаточной репутации для комментария, таким образом, я добавлю это к другим ответам.

Jon Skeet отвечает превосходно с красивым примером. Матовый B имеет точку: не все суперклассы имеют ужины. Ваш код повредился бы при вызове супер из супер, которое имело не супер.

Объектно-ориентированное программирование (который Java) является всем об объектах, не функциях. Если Вы хотите ориентированное программирование задачи, выберите C ++ или что-то еще. Если Ваш объект не вписывается, это - суперкласс, то необходимо добавить его к "классу прародителя", создать новый класс или найти другого супер, это действительно вписывается.

Лично, я нашел, что это ограничение одни из самых больших преимуществ Java. Код несколько тверд по сравнению с другими языками, которые я использовал, но я всегда знаю, что ожидать. Это помогает с "простой и знакомой" целью Java. В моем уме, звоня super.super не просто или знаком. Возможно, разработчики чувствовали то же?

11
ответ дан TM. 23 November 2019 в 00:28
поделиться

Я думаю, что у Jon Skeet есть корректный ответ. Я был бы точно так же, как, чтобы добавить, что Вы можете доступ затененные переменные от суперклассов суперклассов путем кастинга this:

interface I { int x = 0; }
class T1 implements I { int x = 1; }
class T2 extends T1 { int x = 2; }
class T3 extends T2 {
        int x = 3;
        void test() {
                System.out.println("x=\t\t"          + x);
                System.out.println("super.x=\t\t"    + super.x);
                System.out.println("((T2)this).x=\t" + ((T2)this).x);
                System.out.println("((T1)this).x=\t" + ((T1)this).x);
                System.out.println("((I)this).x=\t"  + ((I)this).x);
        }
}

class Test {
        public static void main(String[] args) {
                new T3().test();
        }
}

, который производит вывод:

x=              3
super.x=        2
((T2)this).x=   2
((T1)this).x=   1
((I)this).x=    0

(пример от JLS)

Однако это не работает на вызовы метода, потому что вызовы метода определяются на основе типа выполнения объекта.

68
ответ дан Michael Myers 23 November 2019 в 00:28
поделиться

Похоже, возможно получить хотя бы класс суперкласса суперкласса, хотя и не обязательно его экземпляр, используя отражение; если это может быть полезно, рассмотрите Javadoc по адресу http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass ()

1
ответ дан 23 November 2019 в 00:28
поделиться

Я думаю, что следующий код позволяет использовать super.super ... super.method () в большинстве случаев. (даже если это уродливо делать)

Короче

  1. создать временный экземпляр типа предка
  2. копировать значения полей из исходного объекта во временный
  3. вызвать целевой метод для временного объекта
  4. скопировать измененные значения обратно в исходный объект

Использование:

public class A {
   public void doThat() { ... }
}

public class B extends A {
   public void doThat() { /* don't call super.doThat() */ }
}

public class C extends B {
   public void doThat() {
      Magic.exec(A.class, this, "doThat");
   }
}


public class Magic {
    public static <Type, ChieldType extends Type> void exec(Class<Type> oneSuperType, ChieldType instance,
            String methodOfParentToExec) {
        try {
            Type type = oneSuperType.newInstance();
            shareVars(oneSuperType, instance, type);
            oneSuperType.getMethod(methodOfParentToExec).invoke(type);
            shareVars(oneSuperType, type, instance);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private static <Type, SourceType extends Type, TargetType extends Type> void shareVars(Class<Type> clazz,
            SourceType source, TargetType target) throws IllegalArgumentException, IllegalAccessException {
        Class<?> loop = clazz;
        do {
            for (Field f : loop.getDeclaredFields()) {
                if (!f.isAccessible()) {
                    f.setAccessible(true);
                }
                f.set(target, f.get(source));
            }
            loop = loop.getSuperclass();
        } while (loop != Object.class);
    }
}
39
ответ дан 23 November 2019 в 00:28
поделиться

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

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

(SuperSuperClass this).theMethod();

Я сейчас занимаюсь этой проблемой - быстрое решение заключается в копировании и вставке метода суперкласса в метод подкласса :)

7
ответ дан 23 November 2019 в 00:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: