Ich habe ein Problem mit dem Verstecken von Namen, das extrem schwer zu lösen ist. Hier ist eine vereinfachte Version, die das Problem erklärt:
Es gibt eine Klasse: org.A
package org;
public class A{
public class X{...}
...
protected int net;
}
Dann gibt es eine Klasse net.foo.X
package net.foo;
public class X{
public static void doSomething();
}
Und jetzt ist hier die problematische Klasse, die von erbt A
und anrufen möchtenet.foo.X.doSomething()
package com.bar;
class B extends A {
public void doSomething(){
net.foo.X.doSomething(); // doesn't work; package net is hidden by inherited field
X.doSomething(); // doesn't work; type net.foo.X is hidden by inherited X
}
}
Wie Sie sehen, ist dies nicht möglich. Ich kann den einfachen Namen nicht verwenden, X
da er von einem geerbten Typ ausgeblendet wird. Ich kann den vollständig qualifizierten Namen nicht verwenden net.foo.X
, da er net
durch ein geerbtes Feld ausgeblendet wird.
Nur die Klasse B
befindet sich in meiner Codebasis. die Klassen net.foo.X
und org.A
sind Bibliotheksklassen, also kann ich sie nicht ändern!
Meine einzige Lösung sieht so aus: Ich könnte eine andere Klasse aufrufen, die wiederum aufruft X.doSomething()
; aber diese Klasse würde nur wegen des Namenskonflikts existieren, der sehr chaotisch erscheint! Gibt es keine Lösung , in der ich direkt anrufen kann X.doSomething()
aus B.doSomething()
?
In einer Sprache, in der der globale Namespace angegeben werden kann, z. B. global::
in C # oder ::
C ++, könnte ich einfach net
dieses globale Präfix voranstellen, aber Java lässt dies nicht zu.
quelle
public void help(net.foo.X x) { x.doSomething(); }
und mithelp(null);
net.foo.X
hat die Methode nichtorg.A.X
!A
? Vererbung kann so böse sein, wie Sie gefunden haben ...I could call another class that in turn calls X.doSomething(); but this class would only exist because of the name clash, which seems very messy
+1 für die Einstellung von sauberem Code. Aber für mich scheint dies eine Situation zu sein, in der Sie einen Kompromiss eingehen sollten. Tun Sie dies einfach und geben Sie einen schönen langen Kommentar darüber ab, warum Sie es tun mussten (wahrscheinlich mit einem Link zu dieser Frage).Antworten:
Sie können ein
null
in den Typ umwandeln und dann die Methode darauf aufrufen (was funktioniert, da das Zielobjekt nicht am Aufruf statischer Methoden beteiligt ist).Dies hat die Vorteile von
net.foo.X
),B
dem Namen angeben können, den Sie möchten; deshalbimport static
funktioniert a in Ihrem genauen Fall nicht).Der Nachteil ist, dass dieser Code wirklich schrecklich ist! Für mich erzeugt es eine Warnung, und das ist im Allgemeinen eine gute Sache. Aber da es sich um ein Problem handelt, das ansonsten völlig unpraktisch ist, fügen Sie a hinzu
An einem geeigneten (minimalen!) Einschlusspunkt wird der Compiler heruntergefahren.
quelle
doSomething
irgendwo in Ihrer Hierarchie eine Methode gibt ), also yep beste Lösung.Der wahrscheinlich einfachste (nicht unbedingt einfachste) Weg, dies zu verwalten, wäre eine Delegatenklasse:
und dann ...
Dies ist etwas ausführlich, aber sehr flexibel - Sie können dafür sorgen, dass es sich so verhält, wie Sie es möchten. Außerdem funktioniert es sowohl mit
static
Methoden als auch mit instanziierten Objekten ähnlichWeitere Informationen zum Delegieren von Objekten finden Sie hier: http://en.wikipedia.org/wiki/Delegation_pattern
quelle
Sie können einen statischen Import verwenden:
Beachten Sie dies
B
undA
enthalten Sie keine benannten MethodendoSomething
quelle
doSomething
als Name der Methode inB
...doSomething
irgendwo in der Vererbungshierarchie sind (aufgrund der Auflösung von Methodenaufrufzielen). Knuth hilft Ihnen also, wenn Sie einetoString
Methode aufrufen möchten . Die von Donal vorgeschlagene Lösung ist die in Blochs Java Puzzlers-Buch (ich glaube, ich habe sie nicht nachgeschlagen), daher können wir sie wirklich als maßgebliche Antwort betrachten :-)Die richtige Vorgehensweise wäre der statische Import. Im schlimmsten Fall KÖNNTEN Sie jedoch eine Instanz der Klasse mithilfe von Reflection erstellen, wenn Sie den vollständig qualifizierten Namen kennen.
Java: newInstance einer Klasse ohne Standardkonstruktor
Rufen Sie dann die Methode für die Instanz auf.
Oder rufen Sie einfach die Methode selbst mit Reflektion auf: Rufen Sie eine statische Methode mit Reflektion auf
Dies sind natürlich die letzten Mittel.
quelle
static import
Funktion nur in hinzugefügt wurdeJava 1.5
. Ich beneide keine Leute, die sich für 1.4 oder weniger entwickeln müssen, ich musste es einmal und es war schrecklich!((net.foo.X)null).doSomething()
Lösung, die in altem Java funktioniert. Aber wenn der TypA
auch einen inneren Typen enthältnet
, DANN ist dies die einzige Antwort , die gültig :) bleibt.Nicht wirklich DIE Antwort, aber Sie könnten eine Instanz von X erstellen und die statische Methode darauf aufrufen. Das wäre eine Möglichkeit (schmutzig, gebe ich zu), Ihre Methode aufzurufen.
quelle
null
in den Typ und das anschließende Aufrufen der Methode wäre besser, da das Erstellen eines Objekts Nebenwirkungen haben kann, die ich nicht möchte.null
scheint eine der saubereren Möglichkeiten zu sein, dies zu tun. Braucht eine@SuppressWarnings("static-access")
Warnung frei zu sein ...null
, aber Castingnull
war für mich immer ein Herzensbrecher.Es ist nicht erforderlich, seltsame Warnungen auszuführen oder zu unterdrücken oder redundante Instanzen zu erstellen. Nur ein Trick mit der Tatsache, dass Sie statische Methoden der übergeordneten Klasse über die Unterklasse aufrufen können. (Ähnlich wie bei meiner hackigen Lösung hier .)
Erstellen Sie einfach eine Klasse wie diese
(Der private Konstruktor in dieser letzten Klasse stellt sicher, dass niemand versehentlich eine Instanz dieser Klasse erstellen kann.)
Dann können Sie darüber anrufen
X.doSomething()
:quelle
Was ist, wenn Sie versuchen, den Gobalnamespace abzurufen, da sich alle Dateien im selben Ordner befinden? ( http://www.beanshell.org/javadoc/bsh/class-use/NameSpace.html )
quelle
getGlobal()
ist keine Standard-Java-Methode für Pakete ... (Ich denke, Pakete können keine Methoden in Java haben ...)Dies ist einer der Gründe, warum die Zusammensetzung der Vererbung vorzuziehen ist.
quelle
Ich würde das Strategiemuster verwenden.
Jetzt haben Sie auch Ihre Abhängigkeit entkoppelt, sodass Ihre Komponententests einfacher zu schreiben sind.
quelle
implements SomethingStrategy
derXSomethingStrategy
Klassendeklaration eine hinzuzufügen .