Почему внутренний класс может переопределить частный конечный метод?

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

public class Boom {

    private void touchMe() {
        System.out.println("super::I am not overridable!");
    }

    private class Inner extends Boom {

        private void touchMe() {
            super.touchMe();
            System.out.println("sub::You suck! I overrided you!");
        }
    }

    public static void main(String... args) {
        Boom boom = new Boom();
        Boom.Inner inner = boom.new Inner();
        inner.touchMe();
    }
}

Скомпилировано и работает. "Я должен сделать touchMe() final" Я подумал и сделал это:

public class Boom {

    private final void touchMe() {
        System.out.println("super::I am not overridable!");
    }

    private class Inner extends Boom {

        private void touchMe() {
            super.touchMe();
            System.out.println("sub::You suck! I overrided you!");
        }
    }

    public static void main(String... args) {
        Boom boom = new Boom();
        Boom.Inner inner = boom.new Inner();
        inner.touchMe();
    }
}

и он также работает и говорит мне

[email protected]:~$ java Boom
super::I am not overridable!
sub::You suck! I overrided you!

почему?

Ответ 1

Частные методы не могут быть переопределены (частные методы не наследуются!) На самом деле, не имеет значения, если вы объявляете закрытый метод final или нет.

Два метода, которые вы указали, Boom.touchMe и Boom.Inner.touchMe - это два полностью отдельных метода, которые просто имеют один и тот же идентификатор. Тот факт, что super.touchMe относится к другому методу, чем touchMe, заключается только в том, что Boom.Inner.touchMe shadows Boom.touchMe (а не потому, что он переопределяет его).

Это можно продемонстрировать несколькими способами:

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

  • Если вы сохраните методы private и добавьте аннотацию @Override, компилятор будет жаловаться.

  • Как указывает альпинист, если вы нажмете объект Boom.Inner на объект Boom (((Boom) inner).touchMe()), вызывается Boom.touchMe (если он действительно был переопределен, приведение не имеет значения).

Связанный вопрос:

Ответ 2

Я думаю, что факт, что на самом деле существуют два отдельных метода, хорошо продемонстрирован, изменив ваш основной принцип следующим образом:

public static void main(String... args) {
    Boom boom = new Boom();
    Boom.Inner inner = boom.new Inner();
    inner.touchMe();
    System.out.println("And now cast it...");
    ((Boom)(inner)).touchMe();
}

Теперь это печатает:

super::I am not overridable!
sub::You suck! I overrided you!
And now cast it...
super::I am not overridable!

И причина, по которой вызов super работает в Inner, заключается в том, что вы ищете метод под названием touchMe в вашем суперклассе (Boom), который действительно существует и видим для Inner как он находится в одном классе.

Ответ 3

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

Попробуйте добавить аннотацию @Override - вы получите ошибку компилятора.

Ответ 4

Вы можете переопределить метод, потому что он private для каждого класса.

Ответ 5

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

public class Boom {

    private final void touchMe() {
        System.out.println("super [touchMe] ::I am not overridable!");
    }

    public void overrideMe(){
        System.out.println("super [overrideMe]::I am overridable!");
    }

    private class Inner extends Boom {

        private void touchMe() {
            super.touchMe();
            System.out.println("sub [touchMe]::You suck! I overrided you!");
        }

        public void overrideMe(){
            System.out.println("sub [overrideMe] ::I overrided you!");
        }
    }

    public static void main(String... args) {
        Boom boom = new Boom();
        Boom.Inner inner = boom.new Inner();

        inner.touchMe();

        Boom newBoom = inner;
        newBoom.touchMe();
        newBoom.overrideMe();
    }
}



super [touchMe] ::I am not overridable!
sub [touchMe]::You suck! I overrided you!
super [touchMe] ::I am not overridable!
sub [overrideMe] ::I overrided you!