97

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.

gexicide
  • 38,535
  • 21
  • 92
  • 152
  • Some quickfix could be this: `public void help(net.foo.X x) { x.doSomething(); }` and call with `help(null);` – Absurd-Mind Jul 04 '14 at 10:35
  • @Absurd-Mind: Well, calling a static method via a non existent object seems even messier than my solution :). I will even receive a compiler warning. But true, this would be another hacky solution in addition to mine. – gexicide Jul 04 '14 at 10:40
  • @JamesB: This would instanciate the wrong X! `net.foo.X` has the method, not `org.A.X`! – gexicide Jul 04 '14 at 10:44
  • 3
    Do you _have_ to inherit from `A`? Inheritance can be so nasty, as you've found… – Donal Fellows Jul 04 '14 at 13:05
  • 2
    `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` +1 for attitude of clean code. But for me it seems like this is a situation you should do a tradeoff. Simply do this, and throw a nice long comment about why you had to do it (probably with a link to this question). – sampathsris Jul 06 '14 at 03:08

9 Answers9

85

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.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • 1
    Why not? You'd just do the right thing and refactor the code. – Gimby Jul 04 '14 at 13:24
  • 1
    Static imports aren't that much clearer than this solution *and* don't work in all cases (you're screwed if there's a `doSomething` method anywhere in your hierarchy), so yep best solution. – Voo Jul 04 '14 at 14:27
  • @Voo I freely admit that I actually went and tried all the options that other people had listed as answers having first reproduced exactly what the original problem was, and I was startled how hard it was to work around. The original question neatly closes off all the other, nicer options. – Donal Fellows Jul 05 '14 at 15:10
  • 1
    Vote up for creativity, I would never do this in production code though. I believe indirection is the answer to this problem (isn't it for all problems ?). – ethanfar Jul 06 '14 at 13:16
  • Thanks Donal for this solution. Actually, this solution highlights the places where a "Type" can be used and a variable cannot be used. So, in a "cast" , the compiler would choose the "Type" even if there is a variable with same name. For more such interesting cases, I would recommend 2 "Java Pitfalls" books: http://books.google.co.in/books/about/Java_Pitfalls.html?id=Lp5QAAAAMAAJ&redir_esc=y http://books.google.co.in/books/about/More_Java_Pitfalls.html?id=fKZQAAAAMAAJ&redir_esc=y – RRM Jul 28 '14 at 08:06
38

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

blgt
  • 8,135
  • 1
  • 25
  • 28
37

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

Absurd-Mind
  • 7,884
  • 5
  • 35
  • 47
  • Doesn't net.foo.X.doSomething have package access only? Meaning you cannot access it from package com.bar – JamesB Jul 04 '14 at 10:47
  • 2
    @JamesB Yes, but then the complete question wouldn't make sense, since the method wouldn't be accessible in any way. I think this is an error while simplifying the example – Absurd-Mind Jul 04 '14 at 10:49
  • @JamesB: My mistake; it is public. Changed it! – gexicide Jul 04 '14 at 10:50
  • 1
    But the original question seems to actively want to use `doSomething` as the name of the method in `B`… – Donal Fellows Jul 04 '14 at 13:16
  • 3
    @DonalFellows: You are right; this solution does not work if my code had to remain as I posted. Fortunately, I can rename the method. However, think of a case where my method overrides another method, then I cannot rename it. In this case, this answer would not solve the problem indeed. But this would be even more coincidentally than my problem already is, so maybe there will never ever be any human that will encounter such a problem with triple name clash :). – gexicide Jul 04 '14 at 13:48
  • 4
    To make it clear for everyone else: This solution does not work as soon as you have `doSomething` anywhere in the inheritance hierarchy (due to how method call targets are resolved). So Knuth help you if you want to call a `toString` method. The solution proposed by Donal is the one that's in Bloch's Java Puzzlers book (I think, haven't looked it up), so we can consider it the authoritative answer really :-) – Voo Jul 04 '14 at 14:30
16

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.

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: 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.

Community
  • 1
  • 1
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • 2
    This answer is by far the biggest overkill until now - thumbs up :) – gexicide Jul 04 '14 at 10:59
  • 3
    You should get a completionist badge for this answer; you provided the answer for that singular poor person who has to use an ancient version of Java and solve this exact problem. – Gimby Jul 04 '14 at 13:24
  • I actually did not think about the fact that `static import` feature was added only in `Java 1.5`. I don't envy people who need to develop for 1.4 or below, I had to once and it was terrible! – EpicPandaForce Jul 04 '14 at 13:27
  • 1
    @Gimby: Well, there is still the `((net.foo.X)null).doSomething()` solution which works in old java. But if type `A` even contains an inner type `net`, *THEN* this is the only answer that remains valid :). – gexicide Jul 04 '14 at 15:09
6

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();
Absurd-Mind
  • 7,884
  • 5
  • 35
  • 47
Michael Laffargue
  • 10,116
  • 6
  • 42
  • 76
  • 3
    Casting `null` to the type and then calling the method on it would be better, since creating an object may have side effects which I do not want. – gexicide Jul 04 '14 at 11:55
  • @gexicide That idea of casting `null` would seem to be one of the cleaner ways to do it. Needs a `@SuppressWarnings("static-access")` to be warning-free… – Donal Fellows Jul 04 '14 at 13:03
  • Thanks for the precision about `null`, but casting `null` has always be a heart breaker to me. – Michael Laffargue Jul 21 '14 at 08:02
4

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();
        }
Community
  • 1
  • 1
billc.cn
  • 7,187
  • 3
  • 39
  • 79
  • Interesting, yet another approach. However, the class with the static method is a final utility class. – gexicide Jul 05 '14 at 18:05
  • Yeah, can't use this trick in that case. Yet another reason why static method is a language fail and Scala's object approach should be taken. – billc.cn Jul 05 '14 at 18:25
  • If you're going to create another class anyway, then using a delegate class as described in blgt answer is probably the best. – LordOfThePigs Jul 05 '14 at 23:30
  • @LordOfThePigs This avoids the extra method call and future refactoring burden though. The new class basically serves as an alias. – billc.cn Jul 06 '14 at 10:44
2

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...

         }
     }
Vectoria
  • 1,627
  • 14
  • 13
  • How does this work? AFAIK `getGlobal()` is not a standard Java method for packages... (I think packages cannot have any methods in Java...) – siegi Jul 11 '14 at 20:25
1

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();
    }
}
emory
  • 10,725
  • 2
  • 30
  • 58
0

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.

Erik Madsen
  • 1,913
  • 3
  • 20
  • 34