que mejor lenguaje historia caracteristicas java name-clash member-hiding

mejor - que es java



Ocultar el nombre de Java: el camino difĂ­cil (9)

¿Qué pasa si intenta obtener el espacio gobalnames dado que todos los archivos están en la misma carpeta? ( http://www.beanshell.org/javadoc/bsh/class-use/NameSpace.html )

package com.bar; class B extends A { public void doSomething(){ com.bar.getGlobal().net.foo.X.doSomething(); // drill down from the top... } }

Tengo un problema con el ocultamiento de nombres que es extremadamente difícil de resolver. Aquí hay una versión simplificada que explica el problema:

Hay una clase: org.A

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

Luego hay una clase net.foo.X

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

Y ahora, aquí está la clase problemática que hereda de A y quiere llamar a 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 } }

Como ves, esto no es posible. No puedo usar el nombre simple X porque está oculto por un tipo heredado. No puedo usar el nombre completamente calificado net.foo.X , porque net está oculto por un campo heredado.

Solo la clase B está en mi base de código; las clases net.foo.X y org.A son clases de biblioteca, ¡así que no puedo alterarlas!

Mi única solución es la siguiente: podría llamar a otra clase que a su vez llame a X.doSomething() ; pero esta clase solo existiría debido al nombre Choque, ¡que parece muy desordenado! ¿No hay una solución en la que pueda llamar directamente a X.doSomething() desde B.doSomething() ?

En un lenguaje que permite especificar el espacio de nombres global, por ej., global:: en C # o :: en C ++, podría simplemente prefijar net con este prefijo global, pero Java no permite eso.


Esta es una de las razones por las que la composición es preferible a la herencia.

package com.bar; import java.util.concurrent.Callable; public class C implements Callable<org.A> { private class B extends org.A{ public void doSomething(){ C.this.doSomething(); } } private void doSomething(){ net.foo.X.doSomething(); } public org.A call(){ return new B(); } }


La forma correcta de hacer las cosas sería la importación estática, pero en el peor de los casos, PODRÍA construir una instancia de la clase utilizando la reflexión si conoce su nombre completamente calificado.

Java: nueva instancia de la clase que no tiene un constructor predeterminado

Y luego invocar el método en la instancia.

O bien, solo invoque el método en sí con la reflexión: Invocar un método estático usando la reflexión

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

Por supuesto, estos son obviamente los últimos resorts.


No es necesario realizar ningún lanzamiento ni suprimir advertencias extrañas ni crear ninguna instancia redundante. Es solo un truco usando el hecho de que puedes llamar a los métodos estáticos de la clase padre a través de la subclase. (Similar a mi solución hackish here .)

Solo crea una clase como esta

public final class XX extends X { private XX(){ } }

(El constructor privado en esta clase final se asegura de que nadie pueda crear accidentalmente una instancia de esta clase).

Entonces puedes llamar a X.doSomething() través de él:

public class B extends A { public void doSomething() { XX.doSomething(); }


Probablemente la forma más simple (no necesariamente la más fácil) de gestionar esto sería con una clase de delegado:

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

y entonces ...

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

Esto es algo detallado, pero muy flexible: puede lograr que se comporte de la manera que desee; además, funciona de la misma manera tanto con métodos static como con objetos instanciados

Más sobre delegar objetos aquí: http://en.wikipedia.org/wiki/Delegation_pattern


Puede convertir un null en el tipo y luego invocar el método en eso (lo cual funcionará, ya que el objeto de destino no está involucrado en la invocación de métodos estáticos).

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

Esto tiene los beneficios de

  • siendo libre de efectos secundarios (un problema con instanciar net.foo.X ),
  • no requiere cambiar el nombre de nada (para que pueda darle al método en B el nombre que desea que tenga, por eso una import static no funcionará en su caso exacto),
  • no requiere la introducción de una clase de delegado (aunque podría ser una buena idea ...), y
  • no requiere la sobrecarga ni la complejidad de trabajar con la API de reflexión.

¡El inconveniente es que este código es realmente horrible! Para mí, genera una advertencia, y eso es algo bueno en general. Pero dado que se está trabajando en torno a un problema que de otra manera no es práctico, se agrega un

@SuppressWarnings("static-access")

en un punto apropiado (¡mínimo!) cerrará el compilador.


Puedes usar una importación estática:

import static net.foo.X.doSomething; class B extends A { void doX(){ doSomething(); } }

Tenga en cuenta que B y A no contienen métodos llamados doSomething


Realmente no es LA RESPUESTA, pero podrías crear una instancia de X y llamar al método estático sobre ella. Esa sería una forma (sucia, lo admito) de llamar a su método.

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


Yo usaría el patrón de Estrategia.

public interface SomethingStrategy { void doSomething(); } public class XSomethingStrategy implements SomethingStrategy { import net.foo.X; @Override void doSomething(){ X.doSomething(); } } class B extends A { private final SomethingStrategy strategy; public B(final SomethingStrategy strategy){ this.strategy = strategy; } public void doSomething(){ strategy.doSomething(); } }

Ahora también ha desacoplado su dependencia, por lo que las pruebas de su unidad serán más fáciles de escribir.