Неожиданное поведение по отношению к окончательному модификатору - PullRequest
2 голосов
/ 28 июля 2011

Это мой код

package alpha ;

class A1
{
    static class A11
    {
        private
            final // WHAT IS THE EFFECT OF THIS MODIFIER?
            void fun ( String caller )
            {
                System . out . println ( "A11:\t" + caller ) ;
            }
    }

    static class A12 extends A11
    {
        private void fun ( String caller )
        {
            super . fun ( caller + caller ) ;
        }
    }

    public static void main ( String [ ] args )
    {
        A12 a12 = new A12 ( ) ;
        a12 . fun ( "Hello" ) ;
    }
}

Я обнаружил, что с или без финального mdifer в A1.A11 программа компилируется и запускается.

Я могу понять, что без финального модификатора, A1.A12 может видеть и, таким образом, переопределять забавный метод.Это личное, но они находятся в одном классе, поэтому проблем с видимостью нет.

Я не могу понять, почему он работает с модификатором final.Не следует ли запретить переопределение в A1.A12?

Это вывод программы с последним модификатором на месте

java alpha/A1
A11:    HelloHello

Если он просто игнорировал другой забавный метод, тогда

  1. если бы компилятор не жаловался на супер-ссылку
  2. , то A11 не был бы в выводе

Ответы [ 2 ]

7 голосов
/ 28 июля 2011

Ваши методы private .

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

Выполнение чего-то подобного -

class A1
{
    static class A11
    {
        public
            final // WHAT IS THE EFFECT OF THIS MODIFIER?
            void fun ( String caller )
            {
                System . out . println ( "A11:\t" + caller ) ;
            }
    }

    static class A12 extends A11
    {
        public void fun ( String caller )
        {
            super . fun ( caller + caller ) ;
        }
    }

    public static void main ( String [ ] args )
    {
        A12 a12 = new A12 ( ) ;
        a12 . fun ( "Hello" ) ;
    }
}

теперь вызовет исключение времени компиляции

fun(java.lang.String) in A1.A12 cannot override fun(java.lang.String) in A1.A11; overridden method is final
2 голосов
/ 28 июля 2011

Для public, protected и пакетных частных / стандартных методов доступа final действительно предотвращает переопределение метода.

Тем не менее, все private методы являются «не виртуальными», так что, по сути, финал. Метод private в суперклассе не имеет значения для производного класса. Вы не переопределяете, просто метод в базовом классе игнорируется.

Первое издание Спецификация языка Java, на которой основана JVM, не имеет внутренних или вложенных классов, поэтому методы private могут рассматриваться специально. Более поздние версии языка согнуты вокруг JVM.

В терминах байт-кода методы private вызываются с invokespecial вместо invokevirtual.

Доступ по умолчанию / пакет private * Методы 1020 * в разных пакетах также не зависят друг от друга. Внутри одного пакета можно переопределять друг друга, и final имеет значение. В разных пакетах подходящие методы не переопределяют друг друга.

...