2016-07-13 11 views
1

Ich habe Schnittstelle:Wie kann eine Methode, die eine Schnittstelle implementiert, vor dem Überschreiben geschützt werden?

public interface Doable { 
    void doSomething(); 
} 

und die Klasse, die es implementiert:

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

Das ist dumm Beispiel, aber ich möchte das Problem präsentieren.

Dieser Code kompiliert nicht, ich einen Fehler in Eclipse IDE bin immer:

nicht die Sichtbarkeit der geerbten Methode von Doable

Ich habe gemeinsame Schnittstelle reduzieren können, die eine erklärt Methode. Diese Methode wird in der konkreten Klasse überschrieben. Ich möchte eine andere Klasse vermeiden, die diese Klasse erweitern kann (DoJump), also möchte ich diese Methode vor Unterklassen verstecken. Ich möchte private Modifier verwenden, aber Java erlaubt mir nicht, es zu tun.

Warum ist es unmöglich, und wie man es umgehen kann?

+7

Sie suchen 'final' nicht "privat". – Tom

+0

Siehe auch: [java access modifiers und overriding methods] (http://stackoverflow.com/questions/6851612/java-access-modifiers-and-overriding-methods) – Jesper

+0

Sie können die Methode nicht verbergen, wie sie in definiert ist die Schnittstelle als öffentlich. Wenn Sie es ausblenden möchten, kapseln Sie die Funktionalität in eine neue private Methode und rufen Sie eine neue Methode von der "doSomething" -Methode auf. – f1sh

Antwort

3

Ich würde gerne Ihre letzte Frage "How to workaround it?" beantworten, da dies in der verwandten Frage nicht beschrieben ist. Erstellen Sie eine zweite Schnittstelle NotDoable, die einfach doSomething() nicht deklariert hat. Dann lassen Sie Ihre DoJump beide Schnittstellen implementieren. Geben Sie jedem Benutzer, der doSomething nicht überschreiben soll, einen Verweis auf die Schnittstelle NotDoable anstelle des echten Typs DoJump. Dann werden sie nicht wissen, dass das Objekt wirklich doSomething, sie pro Klassenentwurf nicht wissen kann. Natürlich kann man das umgehen, aber man kann eigentlich alles umgehen. Das Klassendesign ist auf diese Weise korrekter. Hier einige Code:

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(); 
    } 
} 

Aber wie gesagt, kann man dies umgehen, indem Sie if (hidden instanceof DoJump) { DoJump trueObject = (DoJump) hidden; } verwenden. Aber gut, man kann auch über Reflexion auf private Werte zugreifen.

Andere Klassen implementieren jetzt NotDoable anstatt DoJump zu erweitern. Wenn Sie in dieser Schnittstelle alles erklären, was andere über DoJump wissen sollten, dann können sie nur das tun, was sie tun sollten. Sie können diese Schnittstelle IDoJump und die implementierende Klasse DoJump ein allgemeines Muster nennen.

Jetzt das gleiche ein bisschen konkreter.

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(); 
    } 
} 

Und jetzt ein erstreckt Klasse.

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 :("); 
    } 
} 

Am Ende bewusst sein, dass, wenn andere wissen, dass ihre IDog ist eigentlich ein FlyingDog (und sie es cast), dann müssen sie Lage sein fly() als FlyingDog muss fliegen können nennen. Darüber hinaus müssen sie in der Lage sein, das Verhalten zu überschreiben, solange sie der Spezifikation fly() von method-signature entsprechen. Stellen Sie sich ein subclass genannt PoorFlyingDog vor, er muss das Standardverhalten außer Kraft setzen, sonst kann er perfekt fliegen, aber er ist ein armer Flieger.

Zusammengefasst: Verstecken Sie anderen, dass Sie tatsächlich eine DoJump sind, auch verstecken, dass Sie eine Doable sind, so tun, als ob nur eine NotDoable. Oder mit den Tieren, geben Sie vor, nur eine IDog anstelle einer FlyingDog oder ICanFly zu sein. Wenn die anderen nicht Cheat (Casting), können sie nicht fly() auf Sie verwenden, obwohl Sie tatsächlich fliegen können.

2

Fügen Sie final zur DoJump Deklaration hinzu, um zu verhindern, dass diese Klasse überschrieben wird (und daher auch doSomething() überschrieben wird).

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

Wenn Sie noch in der Lage sein DoJump zu erben, aber Sie wollen nicht doSomething() außer Kraft gesetzt werden, legen Sie die final Modifikator in der Methodensignatur

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

Guter Platz bei der zweiten Option! Ich denke, das ist genau das, was * op * wollte. – Zabuza

Verwandte Themen