Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 545
gexicide Avatar asked Jul 04 '14 10:07

gexicide


People also ask

What is name hiding in Java?

A field or variable with the same name in subclass and superclass is known as variable hiding or field hiding in Java. When a variable is hidden, you can use super. variableName to access the value from a superclass.

What does hides a field mean in Java?

Within a class, a field that has the same name as a field in the superclass hides the superclass's field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name.


2 Answers

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.

like image 98
Donal Fellows Avatar answered Sep 21 '22 04:09

Donal Fellows


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

like image 34
blgt Avatar answered Sep 21 '22 04:09

blgt