96 votes

Java Name Hiding: Le chemin dur

J'ai un problème avec le nom de masquage qui est extrêmement difficile à résoudre. Voici une version simplifiée qui explique le problème:

Il existe une classe: org.A

package org;
public class A{
     public class X{...}
     ...
     protected int net;
}

Ensuite, il ya une classe net.foo.X

package net.foo;
public class X{
     public static void doSomething();
}

Et maintenant, voici la problématique de classe qui hérite de l' A et veut appeler net.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 simple nom X parce qu'il est caché par un type héréditaire. Je ne peux pas utiliser le nom complet net.foo.Xcar net est caché par un champ héritée.

Seule la classe B est dans mon code de base; les classes net.foo.X et org.A sont de la bibliothèque de classes, 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'existe que parce que le conflit de nom, ce qui semble très salissant! Il n'y a pas de solution dont je peux appeler directement X.doSomething() de 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 le préfixe net avec ce préfixe global, mais Java ne permet pas que l'.

84voto

Donal Fellows Points 56559

Vous pouvez jeter un null pour le type et ensuite appeler la méthode (qui va travailler, puisque l'objet cible n'est pas impliqué dans l'invocation de méthodes statiques).

((net.foo.X) null).doSomething();

Cela a l'avantage d'

  • d'être sans effets secondaires (un problème avec l'instanciation net.foo.X),
  • ne nécessitant pas de changement de nom de quoi que ce soit (de sorte que vous pouvez donner la méthode en B le nom que vous voulez lui donner; c'est pourquoi un import static ne fonctionne pas dans votre cas précis),
  • ne nécessitant pas l'introduction de délégué de classe (bien que cela pourrait être une bonne idée...), et
  • ne nécessitant pas de la surcharge ou de la complexité du travail avec l'API reflection.

L'inconvénient est que ce code est vraiment horrible!!! Pour moi, il génère un message d'avertissement, et c'est une bonne chose en général. Mais puisque c'est de travailler autour d'un problème qui est par ailleurs complètement impraticable, l'ajout d'un

@SuppressWarnings("static-access")

appropriée (minimum!) joignant le point va arrêter le compilateur.

38voto

blgt Points 3325

Probablement le plus simple (pas forcément le plus simple) pour gérer ce serait avec un délégué de classe:

import net.foo.X;
class C {
    static void doSomething() {
         X.doSomething();
    }
}

et puis ...

class B extends A {
    void doX(){
        C.doSomething();
    }
}

C'est un peu verbeux, mais très flexible - vous pouvez l'obtenir à se comporter de la manière que vous voulez; de plus il fonctionne de la même manière avec le static des méthodes et des objets instanciés

Plus sur les objets délégués ici: http://en.wikipedia.org/wiki/Delegation_pattern

37voto

Absurd-Mind Points 2617

Vous pouvez utiliser une importation statique:

 import static net.foo.X.doSomething;

class B extends A {
    void doX(){
        doSomething();
    }
}
 

Attention: B et A ne contiennent pas de méthodes nommées doSomething

16voto

Zhuinden Points 3074

La bonne façon de faire les choses serait la statique de l'importation, mais dans l'absolu pire des cas, on PEUT construire une instance de la classe à l'aide de réflexion si vous connaissez son nom complet.

Java: newInstance de la classe qui n'a pas de constructeur par défaut

Puis d'appeler la méthode sur l'exemple.

Ou, il suffit d'invoquer la méthode elle-même avec la réflexion: l'invocation d'une méthode statique à l'aide de la réflexion

Class<?> clazz = Class.forName("net.foo.X");
Method method = clazz.getMethod("doSomething");
Object o = method.invoke(null);

Bien sûr, ce sont évidemment les dernières stations.

6voto

Michael Laffargue Points 5190

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'avoue) d'appeler votre méthode.

 (new net.foo.X()).doSomething();
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X