it-swarm.com.de

Kann ich eine private Methode in Java überschreiben?

Ich weiß, dass ich Reflection verwenden kann, um eine private Methode aufzurufen und den Wert einer privaten Variablen abzurufen oder festzulegen, aber ich möchte eine Methode überschreiben.

public class SuperClass {

    public void printInt() {
        System.out.println("I am " + getClass() + ". The int is " + getInt());
    }

    private int getInt() {
        return 1;
    }
}

public class SubClass extends SuperClass {

    public static void main(String[] args) {
        (new SubClass()).printInt();
    }

    public int getInt() {
        return 2;
    }
}

Ich möchte, dass die main-Methode in SubClass den 2 ausgibt, aber sie druckt den 1 aus. Ich habe gehört, dass dies durch Reflektion geschehen kann, aber ich kann nicht herausfinden, wie. Wenn nicht Nachdenken, kennt jemand einen anderen Weg, es zu tun? (Abgesehen davon, SuperClass.getInt() geschützt zu machen oder printInt() in SubClass zu kopieren und einzufügen.) Wenn das Überschreiben der privaten Methode tatsächlich nicht möglich ist, gibt es eine Möglichkeit, eine Art Trigger darauf zu platzieren, der eine Methode in meiner Unterklasse aufruft entweder vor oder nach der Ausführung der privaten Methode?

12
numbers longer

Private Methoden werden nicht vererbt und können in keiner Weise überschrieben werden. Wer dir gesagt hat, du kannst es mit Nachdenken tun, hat entweder gelogen oder über etwas anderes geredet.

Sie können jedoch auf die private Methode getInt der Subklasse zugreifen, die printInt wie folgt aufruft:

public void printInt() throws Exception {
    Class<? extends SuperClass> clazz = getClass();
    System.out.println("I am " + clazz + ". The int is " +
                       clazz.getMethod("getInt").invoke(this) );
}

Dies hat den Effekt, dass die getInt-Methode der Unterklasse von der Superklasse printInt aufgerufen wird. Natürlich wird dies jetzt fehlschlagen, wenn die Unterklasse nicht eine getInt deklariert, so dass Sie hinzufügen müssen ein Häkchen, um mit "normalen" Unterklassen umgehen zu können, die nicht versuchen, eine private Methode zu "überschreiben":

public void printInt() throws Exception {
    Class<? extends SuperClass> clazz = getClass();

    // Use superclass method by default
    Method theGetInt = SuperClass.class.getDeclaredMethod("getInt");

    // Look for a subclass method
    Class<?> classWithGetInt = clazz;
    OUTER: while( classWithGetInt != SuperClass.class ){

        for( Method method : classWithGetInt.getDeclaredMethods() )
            if( method.getName().equals("getInt") && method.getParameterTypes().length == 0 ){
                theGetInt = method;
                break OUTER;
            }

        // Check superclass if not found
        classWithGetInt = classWithGetInt.getSuperclass();
    }

    System.out.println("I am " + classWithGetInt + ". The int is " + theGetInt.invoke(this) );
}

Sie müssen den Superklasse-Code immer noch ändern, damit dies funktioniert. Da Sie den Superklasse-Code ändern müssen, sollten Sie einfach den Zugriffsmodifizierer für getInt in protected ändern, anstatt Reflexions-Hack-arounds auszuführen.

14
trutheality

Sie können eine private Methode nicht überschreiben, da keine andere Klasse, einschließlich einer abgeleiteten Klasse, erkennen kann, dass sie existiert. Es ist privat.

Private Methoden sind implizit final.

In einer verwandten Anmerkung kann eine Unterklasse ein Feld oder eine Methode mit demselben Namen wie ein private-Feld oder eine __-Methode in einer Superklasse deklarieren, da diese Mitglieder aus Sicht der Unterklasse nicht vorhanden sind. Es gibt keine besondere Beziehung zwischen diesen Mitgliedern.

17
erickson

Nein, das kannst du nicht. Sie können ein Programm erstellen, das look so ausgeführt werden soll, dass der Code in einer äußeren Klasse auf private Mitglieder der verschachtelten Klasse zugreifen kann. Private Methoden können jedoch immer noch nicht überschrieben werden. Beispiel:

public class Test {

    public static class Superclass {
        private void foo() {
            System.out.println("Superclass.foo");
        }
    }

    public static class Subclass extends Superclass {
        private void foo() {
            System.out.println("Subclass.foo");
            // Looks like it shouldn't work, but does...
            super.foo();
        }
    }

    public static void main(String[] args) throws Exception {
        Superclass x = new Subclass();
        // Only calls Superclass.foo...
        x.foo();
    }
}

Da dies die Situation only wäre, in der eine private Methode überschrieben werden konnte, ist es kein großer Verlust, dass sie nicht unterstützt wird.

Wenn Sie das Verhalten eines privaten Mitglieds Ihrer Superklasse ändern möchten, ist Ihr Design im Prinzip defekt.

13
Jon Skeet

Ich kann das nicht mit Nachdenken machen, aber ich habe einen Weg gefunden, es mit Instrumenten zu erreichen. Ich habe ASM verwendet, wie auf Dhruba Bandopadhyays Blog vorgeschlagen. Wenn Sie interessiert sind, können Sie meinen Code ansehen (es gibt zu viel, um es hier zu posten).

5
numbers longer

Wenn Sie dies wirklich mit Reflektion machen wollten, könnten Sie:

public class SuperClass {

    private final Method getInt;

    public SuperClass() {
        /** Find the appropriate method to call and cache it. **/
        Method getInt = null;
        try {
            getInt = getClass().getDeclaredMethod("getInt");
        }
        catch (NoSuchMethodException e) {
            try {
                getInt = SuperClass.class.getDeclaredMethod("getInt");
            } catch (NoSuchMethodException e1) {
                throw new RuntimeException(e1);
            }
        }
        getInt.setAccessible(true);
        this.getInt = getInt;
    }

    public void print() {
        int val = 0;
        try {
            val = (Integer) getInt.invoke(this);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        System.out.println(val);
    }

    private int getInt() {
        return 1;
    }
}

public class SubClass extends SuperClass {
    public int getInt() {
        return 2;
    }

    public static void main(String[] args) throws Exception {
        new SubClass().print();
    }
}

Ich vermute, Sie möchten Ihr Programm anders gestalten, als diesen Ansatz zu wählen. Es ist nicht performant und wird definitiv jeden treffen, der SuperClass überrascht.

Beachten Sie, dass die getInt () - Methode der Unterklasse privat sein kann, wenn Sie Reflection auf diese Weise verwenden. Dieser Ansatz ist, zumindest aus den zwei genannten Gründen, fast definitiv eine schlechte Idee. Die Chancen stehen gut, dass Sie Ihre Ziele auf andere Weise erreichen können. Paketschutz ist wirklich keine Option?

2

Sie können eine private Methode nicht überschreiben, aber Sie können eine Methode in einer abgeleiteten Klasse einführen/neu definieren.

class Super
{
   private void fun()
   {
   }
}

class Child extends Super
{
    private void fun()
    {
    }
}

In diesem Fall überschreiben Sie dieses fun () in der Child-Klasse nicht. Sie definieren eine neue Methode mit demselben Namen. Wenn Sie jedoch versuchen, @override oben in fun () der Child-Klasse zu verwenden, wird der Kompilierzeitfehler angezeigt Sie zwingen diesen Spaß () zu überschreiben, sonst definieren Sie den neuen Spaß () in der Kindklasse neu

0
Moni

kannst du var per reference -> Klassen mit Java übergeben?

denn wenn es überhaupt möglich ist: oben Problem könnte umgeschrieben werden als:

(Beachten Sie, dass dies nur zu Spezifikationszwecken gilt)

VB:

funktion (ByRef intX als Integer) // Wert kann explizit geändert werden, nicht jedoch die Methode selbst: P Endefunktion

so viel mehr, denke ich ...

0
i am ArbZ

Nein, wir können private Methoden nicht überschreiben, aber es gibt einen Fall, in dem wir auch private Methoden überschreiben können, d. H. Die innere Klasse

class PrivateTest { 

private String msg = "OuterAndInner";

private void fun() {
     System.out.println("Outer fun()");
}

class Inner extends PrivateTest {
    private void fun()  {
          System.out.println("Accessing Private Member of Outer: " + msg);
    }
}
public static void main(String args[])  {
     PrivateTest o = new PrivateTest();
     Inner  i   = o.new Inner();
     i.fun();
     // o.fun() calls Outer's fun (No run-time polymorphism).
     o = i; 
     o.fun();
}

}

0
Rahul Maurya

Sie können eine private Methode nicht überschreiben. 

Eine überschreibende Methode kann nur in einer Unterklasse der überschriebenen Methode vorhanden sein. Wenn die Methode, die Sie überschreiben möchten, mit private markiert ist, ist das Überschreiben nicht möglich, da die Unterklasse nichts mit dem Zeichen private erbt, wodurch die Verbindung zwischen dieser privaten Methode und den darin enthaltenen Elementen getrennt wird die Unterklasse, einschließlich der Methoden der Unterklasse.

"Überschreiben" bedeutet, dass die JVM basierend auf dem Instanztyp, mit dem Sie sie aufrufen, bestimmen kann, welche Methode verwendet werden soll. Die Theorie des Polymorphismus erklärt, was dies möglich macht. Damit die JVM sagen kann, dass "diese Methoden verbunden sind, überschreibt eine die andere", muss die JVM in der Lage sein, die überschrieben method innerhalb der enthaltenen Unterklasse anzuzeigen die überschreibende Methode. 

Davon abgesehen werden die Klassen in dem von Ihnen angegebenen Fall immer noch kompiliert, aber keine der Methoden wird auf der Grundlage der JVMs aufgerufen, die unabhängig voneinander den instanzbasierten Aufruf ausführen. Es handelt sich lediglich um verschiedene Methoden, die von der JVM nicht als übersteuert oder überschrieben erkannt werden.

Wenn Sie einen IDE wie NetBeans verwenden, wird der Compiler durch die Annotation @Override darüber informiert, dass Sie die Methode mit derselben Signatur in der Superklasse überschreiben. Wenn Sie dies nicht tun, erhalten Sie eine Warnmeldung, in der Sie die Annotation vorschlagen. Sie erhalten jedoch einen Kompilierungsfehler, wenn Sie diese Anmerkung anwenden, wenn:

  • es gibt keine Methode mit übereinstimmender Signatur in der Oberklasse

OR

  • die Methode in der übergeordneten Klasse, die Sie überschreiben möchten, ist mit private oder final markiert.

In der offiziellen Oracle-Dokumentationhttps://docs.Oracle.com/javase/tutorial/Java/IandI/override.html Finden Sie den folgenden Auszug:

Instanzmethoden

... Die Fähigkeit einer Unterklasse, eine Methode zu überschreiben, ermöglicht es einer Klasse, Von Einer Superklasse zu erben, deren Verhalten "nahe genug" ist, und dann das Verhalten Nach Bedarf zu ändern. ... Wenn Sie eine Methode überschreiben, sollten Sie die Annotation @Override Verwenden, die den Compiler anweist, dass Sie eine -Methode in der Superklasse überschreiben möchten. Wenn der Compiler aus irgendeinem Grund Feststellt, dass die Methode in einer der Superklassen nicht vorhanden ist, dann erzeugt Einen Fehler.

Das Überschreiben kann sehr verwirrend sein, da die JVM scheinbar selbstständig handelt. Denken Sie nur daran, dass die Unterklasse ohne Zugriff auf die Methoden [s] in der Oberklasse (dh für alle mit private ) gekennzeichneten Methoden die genannten Methoden [s] nicht aufrufen oder überschreiben kann, da '' t erben sie dazu.

0