Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java名称隐藏:艰难之路_Java_Name Clash_Member Hiding - Fatal编程技术网

Java名称隐藏:艰难之路

Java名称隐藏:艰难之路,java,name-clash,member-hiding,Java,Name Clash,Member Hiding,我有一个名字隐藏的问题,这是非常难以解决的。以下是解释问题的简化版本: 有一个类: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(); } 现在,这里是一个有问题的类,它继承自A,并希

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

有一个类:
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();
}
现在,这里是一个有问题的类,它继承自
A
,并希望调用
net.foo.X.doSomething()

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

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

我唯一的解决方案如下所示: 我可以调用另一个类,它依次调用
X.doSomething()
;但是这个类只会因为名称冲突而存在,这看起来非常混乱!没有解决方案可以直接从
B.doSomething()
调用
X.doSomething()


<>在允许指定全局命名空间的语言中,例如C++中的代码> Global::/Cuff>:在C++中,代码> C++,我可以用这个全局前缀简单地前缀<代码> NET<代码>,但是java不允许。

不是真正的答案,但是您可以创建X的实例并调用静态方法。 这将是一种(我承认是肮脏的)调用您的方法的方式

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

您可以使用静态导入:

import static net.foo.X.doSomething;

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

注意
B
A
不包含名为
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
    }
}

然后在实例上调用该方法

或者,只需通过反射调用方法本身:

Class clazz=Class.forName(“net.foo.X”);
方法方法=clazz.getMethod(“doSomething”);
objecto=method.invoke(null);
当然,这些显然是最后的手段。

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

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

class B extends A {
    void doX(){
        C.doSomething();
    }
}
这有点冗长,但非常灵活——你可以让它以任何你想要的方式运行;此外,它的工作方式与
静态方法和实例化对象的工作方式基本相同


关于委托对象的更多信息:

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

这具有以下优点:

  • 无副作用(实例化
    net.foo.X
    时出现问题)
  • 不需要重命名任何内容(因此您可以在
    B
    中为方法指定您想要的名称;这就是为什么
    import static
    在您的情况下不起作用的原因)
  • 不需要引入委托类(尽管这可能是个好主意…),以及
  • 不需要处理反射API的开销或复杂性
缺点是这段代码非常可怕!对我来说,这会产生一个警告,总的来说这是一件好事。但由于它正在解决一个在其他方面完全不切实际的问题,因此添加

@SuppressWarnings("static-access")

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

这是组合优于继承的原因之一

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();
    }
}
package.com.bar;
导入java.util.concurrent.Callable;
公共类C实现了可调用
{
私有类B扩展了org.A{
公共无效剂量测定法(){
C.这是做某事的方法;
}
}
私人无效剂量(){
net.foo.X.doSomething();
}
公共组织A call(){
返回新的B();
}
}

无需执行任何强制转换或抑制任何奇怪的警告或创建任何冗余实例。这只是一个技巧,它利用了一个事实,即您可以通过子类调用父类静态方法。(类似于我的黑客解决方案。)

创建一个这样的类

public final class XX extends X {
    private XX(){
    }
}
(最后一个类中的私有构造函数确保没有人会意外地创建该类的实例。)

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

    public class B extends A {

        public void doSomething() {
            XX.doSomething();
        }

如果所有文件都在同一个文件夹中,那么尝试获取gobalnamespace会怎么样。()


我会使用策略模式

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

现在,您还解耦了依赖项,因此单元测试将更容易编写。

一些快速修复程序可能是这样的:
public void help(net.foo.X){X.doSomething();}
并使用
help(null)调用@荒谬的头脑:嗯,通过一个不存在的对象调用静态方法似乎比我的解决方案更混乱:)。我甚至会收到编译器警告。但确实,这将是除我之外的另一个黑客解决方案。@JamesB:这将实例化错误的X
net.foo.X
有方法,而不是
org.A.X
!您必须从
A
继承吗?继承可能非常糟糕,正如您所发现的…
我可以调用另一个类,该类反过来调用X.doSomething();但是这个类只会因为名称冲突而存在,这对于干净代码的态度来说似乎非常混乱。但对我来说,这似乎是一种情况,你应该做一个权衡。简单地这样做,并抛出一个很长的关于为什么你必须这样做的评论(可能有一个到这个问题的链接)。net.foo.X.doSomething不是只有包访问权限吗?这意味着您无法从包com访问它。bar@JamesB是的,但是这样的话,完整的问题就没有意义了,因为这个方法无论如何都是不可访问的。我认为在简化示例时这是一个错误,但最初的问题似乎积极希望使用
doSomething
作为
B
中的方法名称。…@donalvellows:你是对的;如果我的代码为h,则此解决方案不起作用
    public class B extends A {

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

       public void doSomething(){
         com.bar.getGlobal().net.foo.X.doSomething(); // drill down from the top...

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