Java Name Hiding: The Hard Way

JavaName ClashMember Hiding

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

Probably the simplest (not necessarily the easiest) way to manage this would be with a delegate class:

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

and then ...

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

This is somewhat verbose, but very flexible - you can get it to behave any way you want; plus it works in much the same way both with static methods and instantiated objects

More about delegate objects here: http://en.wikipedia.org/wiki/Delegation_pattern

Solution 3 - Java

You can use a static import:

import static net.foo.X.doSomething;

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

Watch out that B and A do not contain methods named doSomething

Solution 4 - Java

The proper way of doing things would be the static import, but in the absolute worst case scenario, you COULD construct an instance of the class using reflection if you know its fully qualified name.

https://stackoverflow.com/questions/3671649/java-newinstance-of-class-that-has-no-default-constructor

And then invoke the method on the instance.

Or, just invoke the method itself with reflection: https://stackoverflow.com/questions/2467544/invoking-a-static-method-using-reflection

Class<?> clazz = Class.forName("net.foo.X");
Method method = clazz.getMethod("doSomething");
Object o = method.invoke(null);

Of course, these are obviously last resorts.

Solution 5 - Java

Not really THE answer but you could create an instance of X and call the static method on it. That would be a way (dirty I admit) to call your method.

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

Solution 6 - Java

There's no need to do any cast or suppress any strange warnings or create any redundant instance. Just a trick using the fact that you can call parent class static methods via the sub-class. (Similar to my hackish solution here.)

Just create a class like this

public final class XX extends X {
	private XX(){
	}
}

(The private constructor in this final class makes sure no one can accidentally create an instance of this class.)

Then you're free to call X.doSomething() via it:

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

Solution 7 - Java

What if you try getting the gobalnamespace given all the files are in the same folder. (http://www.beanshell.org/javadoc/bsh/class-use/NameSpace.html)

    package com.bar;
      class B extends A {

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

Solution 8 - Java

This is one of the reasons that composition is preferable to inheritance.

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

Solution 9 - Java

I would use the Strategy pattern.

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

Now you have also decoupled your dependency, so your unit tests will be easier to write.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiongexicideView Question on Stackoverflow
Solution 1 - JavaDonal FellowsView Answer on Stackoverflow
Solution 2 - JavablgtView Answer on Stackoverflow
Solution 3 - JavaAbsurd-MindView Answer on Stackoverflow
Solution 4 - JavaEpicPandaForceView Answer on Stackoverflow
Solution 5 - JavaMichael LaffargueView Answer on Stackoverflow
Solution 6 - Javabillc.cnView Answer on Stackoverflow
Solution 7 - JavaVectoriaView Answer on Stackoverflow
Solution 8 - JavaemoryView Answer on Stackoverflow
Solution 9 - JavaErik MadsenView Answer on Stackoverflow