Java 名称隐藏:艰难的方式

2022-08-31 10:39:00

我有一个名字隐藏的问题,很难解决。下面是一个简化版本来解释这个问题:

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

现在,这是一个有问题的类,它继承并想要调用Anet.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
    }
}

如您所见,这是不可能的。我不能使用简单名称,因为它被继承的类型隐藏。我不能使用完全限定名,因为它被继承的字段隐藏。Xnet.foo.Xnet

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

我唯一的解决方案是这样的:我可以调用另一个类,该类反过来调用;但是这个类只会因为名称冲突而存在,这看起来很混乱!有没有可以直接从 中调用的解决方案?X.doSomething()X.doSomething()B.doSomething()

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


答案 1

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

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

这样做的好处是

  • 无副作用(实例化问题 ),net.foo.X
  • 不需要重命名任何内容(因此您可以以您希望它具有的名称提供方法;这就是为什么a在您的确切情况下不起作用的原因),Bimport static
  • 不需要引入委托类(尽管这可能是一个好主意...),并且
  • 不需要使用反射 API 的开销或复杂性。

缺点是这段代码真的很可怕!对我来说,它会产生一个警告,这通常是一件好事。但是,由于它正在解决一个在其他方面完全不切实际的问题,因此添加一个

@SuppressWarnings("static-access")

在适当的(最小!)封闭点将使编译器关闭。


答案 2

管理这个问题的最简单(不一定是最简单的)方法可能是使用委托类:

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


推荐