2016-02-03 9 views
5

Я не мог найти такой вопрос, как мой, поэтому я надеюсь, что это не дубликат.Java - Hiding Overriding и окончательный модификатор

Снова о переопределении и укрытии. Я думаю - но я могу ошибаться - я понял оба.

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

public class Child extends Parent { 
    public void method1(){System.out.println("child");}  
    public static void method2(){ System.out.println("static child");} 
} 

class Parent{ 
    private void method1(){ System.out.println("parent");}  
    public static void method2(){ System.out.println("static parent");} 

    public static void main(String[] args){ 
      Parent p = new Child(); 
      p.method1(); //prints out "parent" 
      p.method2(); //prints out "static parent" 
    } 
} 

Если я читал спецификацию он говорит:

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.3.3

Метод может быть объявлен окончательным, чтобы предотвратить подклассы переопределения или скрывая его.

Если изменить method1 в классе Parent до "окончательного"

private final void method1(){ System.out.println("parent");} 

Все работает отлично. edit start: Я ожидал, что ошибка компилятора говорит о том, что окончательные методы не могут быть скрыты, но этого не произошло. : Редактировать конец

Вопрос № 1: означает ли это, что только скрытые методы могут быть скрыты? В книге, которую я читаю (учебное пособие OCA, Jeanne Boyarsky и Scott Selikoff стр. 252), они ясно говорят, что частный метод был скрыт.

Тогда я изменил method2 в классе Parent к

public final static void method2(){ System.out.println("static parent");} 

Теперь компилятор не жалуется, ошибка говорит: «Ребенок не может переопределить method2()», который является довольно запутанным, потому что я думал, что я пытался скрыть метод ,

Вопрос № 2: Разве это не должно быть «Ребенок не может скрыть метод2()»?

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

+0

Ваш пример немного запутан, потому что метод2 определен до метода1. Для удобства чтения вы можете захотеть реструктурировать: a) сначала определите метод1, затем metho2 и b) сначала определите класс Parent, затем класс Child и, наконец, некоторый открытый класс, содержащий основной метод в качестве тестового кадра. – penguineer

+0

А теперь мой настоящий вопрос: что вы подразумеваете под «Все работает отлично»? Пожалуйста, укажите, что вы ожидали и что произошло. Я ожидал бы ошибку компилятора при переопределении окончательного метода - вы получили эту ошибку? Или компилятор прошел с ним? Вы видели распечатку метода overriden? – penguineer

+0

Учебник Oracle подразумевает, что вы не можете переопределить метод 'static', только скройте его: https://docs.oracle.com/javase/tutorial/java/IandI/override.html –

ответ

8

Вопрос 1

Вопрос № 1: значит ли это только статические методы могут быть скрыты?

Parent.method1() не было видно в ни наследуется Child просто в силу того, private. Таким образом, Child.method1() не переопределил или не спрятал Parent.method1(), он просто создал новый метод в Child, который имел то же имя, параметры и тип возврата.

См http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.3:

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

Вопрос 2

Вопрос № 2: Не должно быть "Ребенок не может скрыть method2()"?

Да, вы в порядке. Это должно быть «скрыть». В соответствии с JLS (http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.2),

Если класс C объявляет или наследует статический метод м, то м, как говорят, чтобы скрыть какой-либо метод т», где подпись т является подсигнатурой (§8.4.2) сигнатуры т», в суперкласса и суперинтерфейсах C, которые могли бы быть доступными для кода в C.

„скрытие“является то, что static методы делают для static методов. «Переопределение» - это методы экземпляра для методов экземпляра. Эти два не могут быть смешаны: метод static не может переопределить или скрыть метод экземпляра, и метод экземпляра не может переопределить или скрыть метод static.

Кстати, мой Eclipse, компилятор дает аналогичное сообщение об ошибке: «Невозможно переопределить окончательный метод от Родителя»

+0

частные методы и скрытие: я прочитал это в упомянутой книге, что частный метод был скрыт, и из-за поведения компилятора я думал, что он не может быть скрыт (из-за спецификаций о конечном модификаторе и скрытых методах). Однако я не нашел часть (8.4.8.3) о частных методах. Спасибо, что проливает свет на все это. – whoCares

+0

P.S. Компилятор Eclipse: я знаю, я тестировал все это в консоли и затмении. Такая же ошибка. – whoCares

2

Ну, я совсем новичок в Java, но я постараюсь ответить.

Разница заключается в том, что вы используете разные модификаторы уровня доступа: вы используете private на method1() родительского класса и общедоступны по адресу method1() в классе Child. Фактически, вы не скрываете метод, поскольку это не тот же метод. Частный модификатор указывает, что к элементу можно получить доступ только в своем классе, поэтому вы используете новый метод, когда объявляете method1() в классе Child. Хотя ребенок наследует все методы из родителя (по мере его расширения), частные методы не наследуются. В случае method2(), как объявлено public, он наследуется классом Child и может быть скрыт.

Подробнее об этом (Взято из oracle tutorials):

Частных члены суперкласс

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

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

Редакция: Вопроса 2:

скрывает статический метод, а не окончательный.Только статические из них могут быть скрыты, как здесь:

class SuperClass { 
    static void display() { 
     System.out.println("Super"); 
    } 
} 

class SubClass extends SuperClass { 
    static void display() { 
     System.out.println("Sub"); 
    } 
} 

public class Test { 
    public static void main(String[] args) { 
     // Prints "Super" in console 
     SuperClass sup = new SubClass(); 
     sup.display(); 

     // Prints "Sub" in console 
     SubClass sub = new SubClass(); 
     sub.display(); 
    } 
} 

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

overridden method is static,final (обратите внимание на final).

Компилятор жалуется на это, потому что вы больше не скрываете его. Когда вы объявили его final, вы его переопределите. Это даст вам ту же ошибку, если вы не используете модификатор static в классе Child, поскольку вы будете пытаться переопределить то, что больше не static. Скрытие используется только тогда, когда статический метод скрывает другой статический метод. Если вы попробуете:

  1. нестатический метод «скрывает» статический: это переопределение.
  2. окончательный метод «скрывает» статический: это переопределение.

В таких случаях вы больше не пытаетесь спрятаться (потому что укрытие используется только на статике), но вы пытаетесь переопределить.

+0

Точно. Я говорил о компиляторе. Если вы попробуете: метод экземпляра «скрывает» статический, компилятор подумает, что вы пытаетесь его переопределить, потому что вы можете скрывать только статические методы. Вот почему компилятор не говорит, что «скрытый метод статический, окончательный». Понимаете, компилятор знает, что статический может скрыть статичность. Если вы попытаетесь изменить статику любым другим способом, кроме «статического сокрытия статического», компилятор подумает, что вы его переопределяете. Не существует «скрытого метода», это статическая, окончательная ошибка, потому что скрытие происходит только в статическом контексте, насколько я думаю. :) – ClauCece

+0

О, мой плохой. Я говорил гипотетически. Я говорил: Гипотетически, предположим, что вы пишете: метод экземпляра «скрывает» статический. Благодаря :) – ClauCece