Reputation: 40128
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.
Upvotes: 97
Views: 5043
Reputation: 2014
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.
Upvotes: 0
Reputation: 1687
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...
}
}
Upvotes: 2
Reputation: 7317
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();
}
Upvotes: 4
Reputation: 10891
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();
}
}
Upvotes: 1
Reputation: 137767
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
net.foo.X
),B
the name you want it to have; that's why a import static
won't work in your exact case),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.
Upvotes: 85
Reputation: 10314
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();
Upvotes: 6
Reputation: 8205
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
Upvotes: 38
Reputation: 81578
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.
Upvotes: 16
Reputation: 8004
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
Upvotes: 37