问题
我有一个名称隐藏问题,这是一个非常难以解决的问题。这是一个解释问题的简化版本:
有一个类:org.A
package org;
public class A{
public class X{...}
...
protected int net;
}
然后有一个classnet.foo.X
package net.foo;
public class X{
public static void doSomething();
}
现在,这是有问题的类继承自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
}
}
如你所见,这是不可能的。我不能使用简单的名称X
,因为它被继承的类型隐藏。我不能使用完全限定名称net.foo.X
,因为net
是由继承字段隐藏的。
只有classB
在我的代码库中; classesnet.foo.X
和org.A
是库类,所以我无法改变它们!
我唯一的解决方案是这样的:我可以打电话给另一个类,然后调用X.doSomething()
;但是这个类只会因为名字冲突而存在,这看起来非常混乱!有没有解决方案,我可以直接致电X.doSomething()
fromB.doSomething()
?
在允许指定全局命名空间的语言中,例如,在C#或344846450in中,我可以简单地使用此全局前缀作为前缀net
,但Java不允许这样做。
#1 热门回答(84 赞)
你可以将anull
转换为该类型,然后在该方法上调用该方法(这将起作用,因为目标对象不涉及静态方法的调用)。
((net.foo.X) null).doSomething();
这有好处
- 没有副作用(实例化net.foo.X时出现问题),
- 不需要重命名任何东西(所以你可以给B中的方法提供你想要的名称;这就是为什么导入静态在你的确切情况下不起作用),
- 不要求引入代表类(虽然这可能是个好主意......),以及
- 不需要使用反射API的开销或复杂性。
缺点是这段代码非常可怕!对我来说,它会产生一个警告,这是一件好事。但是,因为它正在解决一个原本不切实际的问题,所以添加一个
@SuppressWarnings("static-access")
在适当的(最小!)封闭点将关闭编译器。
#2 热门回答(38 赞)
管理这个的最简单(不一定是最简单)的方法可能是委托类:
import net.foo.X;
class C {
static void doSomething() {
X.doSomething();
}
}
接着 ...
class B extends A {
void doX(){
C.doSomething();
}
}
这有点冗长,但非常灵活 - 你可以让它以你想要的任何方式行事;加上它与static
方法和实例化对象的工作方式大致相同
有关委托对象的更多信息,请访问:http://en.wikipedia.org/wiki/Delegation_pattern
#3 热门回答(37 赞)
你可以使用静态导入:
import static net.foo.X.doSomething;
class B extends A {
void doX(){
doSomething();
}
}
注意那个B
和A
不包含名为doSomething
的方法