Java名称隐藏:艰难的方式

我有一个很难解决的名称隐藏问题。 以下是解释问题的简化版本:

有一个类: org.A

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

然后有一个类net.foo.X

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

而现在,这里是从Ainheritance的有问题的类,并且想要调用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 } } 

如你所见,这是不可能的。 我不能使用简单的名称X因为它被隐藏的types。 我不能使用完全限定的名字net.foo.X ,因为net被一个inheritance的字段隐藏。

只有B类在我的代码库中; net.foo.Xorg.A类是库类,所以我不能改变它们!

我唯一的解决scheme是这样的:我可以调用另一个类,然后调用X.doSomething() ; 但是这个类只会因为名字冲突而存在,这看起来很乱! 有没有解决scheme,我可以直接从B.doSomething()调用B.doSomething()

在允许指定全局名称空间的语言中,例如C ++中的global:: ,或者C ++中的,我可以简单地在这个全局前缀前加net ,但是Java不允许这样做。

您可以将null转换为该types,然后调用该方法(这将起作用,因为目标对象不参与调用静态方法)。

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

这有好处

  • 无副作用(实例化net.foo.X的问题),
  • 不需要重命名任何东西(所以你可以给B的方法指定你想要的名称;这就是为什么import static在你的确切情况下不起作用)
  • 不需要引入委托类(尽pipe这可能是一个好主意……),而且
  • 不需要使用reflectionAPI的开销或复杂性。

缺点是这个代码真的太可怕了! 对我来说,它会产生一个警告,这通常是一件好事。 但是由于它正在解决一个本来不切实际的问题,所以增加一个

 @SuppressWarnings("static-access") 

在一个合适的(最小的!)封闭点将closures编译器。

也许最简单的(不一定是最简单的)方式来pipe理这个是委托类:

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

接着 …

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

这有点冗长,但非常灵活 – 你可以用任何你想要的方式来expression它; 加上它与static方法和实例化对象的工作方式大致相同

有关委托对象的更多信息,请访问http://en.wikipedia.org/wiki/Delegation_pattern

你可以使用静态导入:

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

注意BA不包含名为doSomething方法

做事情的正确方法是静态导入,但是在绝对最坏的情况下,如果知道完全限定名称,则可以使用reflection构造类的实例。

Java:没有默认构造函数的类的newInstance

然后调用实例上的方法。

或者,只需使用reflection调用方法本身: 使用reflection调用静态方法

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

当然,这显然是最后的胜地。

不是真的答案,但你可以创build一个X的实例,并调用静态方法。 这将是一种方式(肮脏,我承认)打电话给你的方法。

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

没有必要做任何投射或压制任何奇怪的警告或创build任何多余的实例。 只是使用这个事实,你可以通过子类调用父类的静态方法。 (类似我这里的解决办法)

只要像这样创build一个类

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

(这个最后一个类中的私有构造函数确保没有人可以无意中创build这个类的实例。)

然后你可以通过它自由地调用X.doSomething()

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

如果您尝试获取全球文件名在相同的文件夹中,那该怎么办? ( 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... } } 

这是构图比inheritance更好的原因之一。

 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(); } } 

我会使用战略模式。

 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(); } } 

现在你还解耦了你的依赖关系,所以你的unit testing会更容易编写。