2016-07-13 4 views
1

У меня есть интерфейс:Как защитить метод, реализующий интерфейс от переопределения?

public interface Doable { 
    void doSomething(); 
} 

и класс, который реализует его:

public class DoJump() implements Doable { 
    @Override 
    private void doSomething() { 
     fireJumpHandler(); 
    } 
} 

Это глупо пример, но я хотел бы представить эту проблему.

Этот код не компилируется, я получаю сообщение об ошибке в Eclipse IDE:

Не удается уменьшить видимость унаследованного метода от выполнимо

У меня есть общий интерфейс, который декларирует метод. Этот метод переоценивается в конкретном классе. Я хотел бы избежать другого класса, который может расширить этот класс (DoJump), поэтому я хотел бы скрыть этот метод из подклассов. Я бы хотел использовать модификатор private, но Java не позволяет мне это делать.

Почему это невозможно, и как обходиться с ним?

+7

Вы ищете 'final' , а не 'private'. – Tom

+0

См. Также: [модификаторы java-доступа и методы переопределения] (http://stackoverflow.com/questions/6851612/java-access-modifiers-and-overriding-methods) – Jesper

+0

Вы не можете сделать метод скрытым, как он определен в Интерфейс как открытый. Если вы хотите скрыть его, инкапсулируйте функциональность в новый закрытый метод и вызовите новый метод из метода '' doSomething''. – f1sh

ответ

3

Я хотел бы ответить на ваш последний вопрос "How to workaround it?", так как это не описано в соответствующем вопросе. Создайте второй интерфейс NotDoable, который просто не имеет doSomething(). Затем пусть ваш DoJump реализует оба интерфейса. Дайте всем, кто не должен переопределять doSomething ссылку на интерфейс NotDoable вместо истинного типа DoJump. Тогда они не будут знать, что объект действительно может doSomething, они не будут знать дизайн каждого класса. Конечно, можно обойти это, но на самом деле можно обойти все. Дизайн класса более правильный. Вот код:

public interface Doable { 
    public void doSomething(); 
} 

public interface NotDoable { 

} 

public class DoJump implements Doable, NotDoable { 
    @Override 
    public void doSomething() { 
     System.out.println("hi"); 
    } 

    public NotDoable meAsNotDoable() { 
     return this; 
    } 

    public static void main(String[] args) { 
     DoJump object = new DoJump(); 

     // This call is possible, no errors 
     object.doSomething(); 

     NotDoable hidden = object.meAsNotDoable(); 

     // Not possible, compile error, the true type is hidden! 
     hidden.doSomething(); 
    } 
} 

Но, как сказал один может обойти это с помощью if (hidden instanceof DoJump) { DoJump trueObject = (DoJump) hidden; }. Но хорошо, можно также получить доступ к частным значениям через отражение.

Другие классы теперь реализуют NotDoable вместо расширения DoJump. Если вы объявите все, что другие должны знать о DoJump в этом интерфейсе, тогда они смогут делать то, что должны делать. Вы можете назвать этот интерфейс IDoJump и реализующим классом DoJump, общим шаблоном.

Теперь то же самое более конкретное.

public interface IDog { 
    public void bark(); 
} 

public interface ICanFly { 
    public void fly(); 
} 

public class FlyingDog implements IDog, ICanFly { 
    @Override 
    public void bark() { 
     System.out.println("wuff"); 
    } 

    @Override 
    public void fly() { 
     System.out.println("Whuiiii"); 
    } 

    public static void main(String[] args) { 
     FlyingDog flyingDog = new FlyingDog(); 

     // Both works 
     flyingDog.fly(); 
     flyingDog.bark(); 

     IDog dog = (IDog) flyingDog; 

     // Same object but does not work, compile error 
     dog.fly(); 

     ICanFly canFly = (ICanFly) flyingDog; 

     // Same object but does not work, compile error 
     canFly.bark(); 
    } 
} 

И теперь расширение класса.

public class LoudDog implements IDog { 
    @Override 
    public void bark() { 
     System.out.println("WUUUUFF"); 
    } 

    // Does not work, compile error as IDog does not declare this method 
    @Override 
    public void fly() { 
     System.out.println("I wanna fly :("); 
    } 
} 

В конце концов, быть в курсе, что если другие знают, что их на самом деле IDog является FlyingDog (и они бросили его), то они должны быть в состоянии назвать fly() как FlyingDog сусло может летать. Кроме того, они должны быть в состоянии переопределить поведение, если они соответствуют спецификации fly(), указанной его method-signature. Представьте себе subclass под названием PoorFlyingDog, ему нужно переопределить поведение по умолчанию, иначе он может отлично летать, но он бедный летающий.

Подведено: Скрыть для других, что вы на самом деле DoJump, также скрываете, что вы являетесь Doable, притворяетесь только NotDoable. Или с животными, притворяйтесь только IDog вместо FlyingDog или ICanFly. Если другие не делают чит (литье), они не смогут использовать fly() на вас, хотя вы действительно можете летать.

2

Добавить final в объявление DoJump, чтобы предотвратить переоценку этого класса (и, следовательно, doSomething() тоже будет переоценено).

public final class DoJump implements Doable { 
    @Override 
    public void doSomething() { 
     fireJumpHandler(); 
    } 
} 

Если вам все еще нужно, чтобы иметь возможность наследовать DoJump, но вы не хотите doSomething() быть переопределен, поставить модификатор final в сигнатуре метода

public class DoJump implements Doable { 
    @Override 
    public final void doSomething() { 
     fireJumpHandler(); 
    } 
} 
+0

Хорошее место при втором варианте! Я думаю, что это именно то, что * op * хотел. – Zabuza

Смежные вопросы