Search code examples
javaname-clashmember-hiding

Java Name Hiding: The Hard Way


I have a problem with name hiding that is extremely hard to solve. Here is a simplified version that explains the problem:

There is a class: org.A

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

Then there is a class net.foo.X

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

And now, here is the problematic class which inherits from A and wants to call 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
    }
}

As you see, this is not possible. I cannot use the simple name X because it is hidden by an inherited type. I cannot use the fully qualified name net.foo.X, because net is hidden by an inherited field.

Only the class B is in my code base; the classes net.foo.X and org.A are library classes, so I cannot alter them!

My only solution looks like this: I could call another class that in turn calls X.doSomething(); but this class would only exist because of the name clash, which seems very messy! Is there no solution in which I can directly call X.doSomething() from B.doSomething()?

In a language that allows specifying the global namespace, e.g., global:: in C# or :: in C++, I could simply prefix net with this global prefix, but Java does not allow that.


Solution

  • You can cast a null to the type and then invoke the method on that (which will work, since the target object isn't involved in invocation of static methods).

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

    This has the benefits of

    • being side-effect free (a problem with instantiating net.foo.X),
    • not requiring renaming of anything (so you can give the method in B the name you want it to have; that's why a import static won't work in your exact case),
    • not requiring the introduction of delegate class (though that might be a good idea…), and
    • not requiring the overhead or complexity of working with the reflection API.

    The downside is that this code is really horrible! For me, it generates a warning, and that's a good thing in general. But since it's working around a problem that is otherwise thoroughly impractical, adding a

    @SuppressWarnings("static-access")
    

    at an appropriate (minimal!) enclosing point will shut the compiler up.