J'ai un problème de masquage de nom qui est extrêmement difficile à résoudre. Voici une version simplifiée qui explique le problème:
Il y a une classe: org.A
package org;
public class A{
public class X{...}
...
protected int net;
}
Puis il y a une classe net.foo.X
package net.foo;
public class X{
public static void doSomething();
}
Et maintenant, voici la classe problématique qui hérite A
et veut appelernet.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
}
}
Comme vous le voyez, ce n'est pas possible. Je ne peux pas utiliser le nom simple X
car il est masqué par un type hérité. Je ne peux pas utiliser le nom complet net.foo.X
, car il net
est masqué par un champ hérité.
Seule la classe B
est dans ma base de code; les classes net.foo.X
et org.A
sont des classes de bibliothèque, donc je ne peux pas les modifier!
Ma seule solution ressemble à ceci: je pourrais appeler une autre classe qui à son tour appelle X.doSomething()
; mais cette classe n'existerait qu'à cause du nom clash, qui semble très désordonné! Yat - il pas de solution dans laquelle je peux appeler directement à X.doSomething()
partir B.doSomething()
?
Dans un langage qui permet de spécifier l'espace de noms global, par exemple, global::
en C # ou ::
en C ++, je pourrais simplement préfixer net
avec ce préfixe global, mais Java ne le permet pas.
la source
public void help(net.foo.X x) { x.doSomething(); }
et appelez avechelp(null);
net.foo.X
a la méthode, nonorg.A.X
!A
? L'héritage peut être si méchant, comme vous l'avez trouvé…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 pour l'attitude du code propre. Mais pour moi, il semble que ce soit une situation dans laquelle vous devriez faire un compromis. Faites-le simplement et jetez un long commentaire sur les raisons pour lesquelles vous deviez le faire (probablement avec un lien vers cette question).Réponses:
Vous pouvez convertir a
null
en type, puis appeler la méthode sur celui-ci (ce qui fonctionnera, car l'objet cible n'est pas impliqué dans l'appel des méthodes statiques).Cela a les avantages de
net.foo.X
),B
le nom que vous voulez; c'est pourquoi aimport static
ne fonctionnera pas dans votre cas exact),L'inconvénient est que ce code est vraiment horrible! Pour moi, cela génère un avertissement, et c'est une bonne chose en général. Mais comme cela fonctionne autour d'un problème qui est autrement tout à fait irréalisable, l'ajout d'un
à un point englobant approprié (minimal!) fermera le compilateur.
la source
doSomething
méthode n'importe où dans votre hiérarchie), alors oui, la meilleure solution.Le moyen le plus simple (pas nécessairement le plus simple) de gérer cela serait probablement d'utiliser une classe déléguée:
puis ...
C'est quelque peu verbeux, mais très flexible - vous pouvez le faire se comporter comme vous le souhaitez; de plus, il fonctionne à peu près de la même manière avec les
static
méthodes et les objets instanciésPlus d'informations sur les objets délégués ici: http://en.wikipedia.org/wiki/Delegation_pattern
la source
Vous pouvez utiliser une importation statique:
Attention à cela
B
etA
ne contiennent pas de méthodes nomméesdoSomething
la source
doSomething
comme nom de la méthode enB
…doSomething
n'importe où dans la hiérarchie d'héritage (en raison de la façon dont les cibles d'appel de méthode sont résolues). Alors Knuth vous aide si vous souhaitez appeler unetoString
méthode. La solution proposée par Donal est celle qui se trouve dans le livre Java Puzzlers de Bloch (je pense que je ne l'ai pas recherchée), nous pouvons donc la considérer comme la réponse faisant autorité :-)La bonne façon de faire les choses serait l'importation statique, mais dans le pire des cas, vous POUVEZ construire une instance de la classe en utilisant la réflexion si vous connaissez son nom complet.
Java: newInstance de classe qui n'a pas de constructeur par défaut
Et puis invoquez la méthode sur l'instance.
Ou, appelez simplement la méthode elle-même avec la réflexion: Appel d'une méthode statique à l'aide de la réflexion
Bien sûr, ce sont évidemment les derniers recours.
la source
static import
fonctionnalité était uniquement ajoutéeJava 1.5
. Je n'envie pas les gens qui ont besoin de se développer pour la version 1.4 ou inférieure, je devais le faire une fois et c'était terrible!((net.foo.X)null).doSomething()
solution qui fonctionne dans l'ancien java. Mais si le typeA
contient même un type internenet
, ALORS c'est la seule réponse qui reste valide :).Pas vraiment LA réponse mais vous pouvez créer une instance de X et appeler la méthode statique dessus. Ce serait une façon (sale je l'admets) d'appeler votre méthode.
la source
null
Il serait préférable de lancer le type puis d'appeler la méthode, car la création d'un objet peut avoir des effets secondaires que je ne veux pas.null
semble être l'un des moyens les plus propres de le faire. Doit@SuppressWarnings("static-access")
être sans avertissement…null
, mais le castingnull
a toujours été un coup de cœur pour moi.Il n'est pas nécessaire de lancer ou de supprimer les avertissements étranges ou de créer une instance redondante. Juste une astuce utilisant le fait que vous pouvez appeler des méthodes statiques de classe parent via la sous-classe. (Similaire à ma solution hackish ici .)
Créez simplement une classe comme celle-ci
(Le constructeur privé de cette classe finale s'assure que personne ne peut créer accidentellement une instance de cette classe.)
Ensuite, vous êtes libre d'appeler
X.doSomething()
via:la source
Que faire si vous essayez d'obtenir le gobalnamespace étant donné que tous les fichiers sont dans le même dossier. ( http://www.beanshell.org/javadoc/bsh/class-use/NameSpace.html )
la source
getGlobal()
n'est pas une méthode Java standard pour les packages ... (je pense que les packages ne peuvent avoir aucune méthode en Java ...)C'est l'une des raisons pour lesquelles la composition est préférable à l'héritage.
la source
J'utiliserais le modèle de stratégie.
Maintenant, vous avez également découplé votre dépendance, de sorte que vos tests unitaires seront plus faciles à écrire.
la source
implements SomethingStrategy
sur laXSomethingStrategy
déclaration de classe.