问题

我有一个名称隐藏问题,这是一个非常难以解决的问题。这是一个解释问题的简化版本:

有一个类: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.Xorg.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();
    }
}

注意那个BA不包含名为doSomething的方法


原文链接