0

Suppose I am using a third party project with a Class A in it. And Class A is used everywhere. Inside Class A, I am not happy with Method M1. Firstly, I don't wanna change Class A, secondly, I need A.M1() know about something in the context. (M1 will be called by other) My design would be:

public MyClass {
    ContextInfo ci;

    public class B extends A {
    //@Override M1() {use ci}
    }

    //Somehow I have a stack of A, 
    //and I know this is the only places A objects will be in

    Stack<A> s = getStack();
    //Now I wanna replace the top of the stack. or I can convert all As to Bs in the stack
    A a = s.pop();
    B b = (B) a;              //here it fails
    s.push(b);
}

Since I am downcasting, I have run time casting error. Is there a way for the compiler or JVM to realize that B can only do what A is allowed to do (not strictly a subtype) so that this should not be a problem? Or some other ideas to solve the problem?

huoenter
  • 512
  • 3
  • 16
  • 3
    Cast does not change the class of an object. You can only cast to B if the object in question is already a B (though perhaps in A's clothing). – Hot Licks Feb 18 '14 at 20:03
  • 3
    If the downcast fails, that means that the last thing you `push`ed onto the stack was **not** a `B`. So the problem must be somewhere else in your code. – ajb Feb 18 '14 at 20:06
  • I don't think what you are trying to do is possible. You'll have to find where `A`s are being inserted into the stack and replace them with `B`s, if able. A cannot be downcast to B as has already been said. – M7Jacks Feb 18 '14 at 20:10
  • A different approach might be achievable using [jboss byteman](http://www.jboss.org/byteman). – Alain Pannetier Feb 19 '14 at 03:45

1 Answers1

0

The simple answer is "no". Casting only succeeds if the object is an instance of the type being cast to, either directly or through inheritance. Make B a subclass of A and you'll be able to use it (almost) anywhere A can be used. If it isn't, you can't.

There are many good reasons for this restriction, including security.

If you really want to redefine A, it's possible to do so to some degree if you have access to the classpath. Put your new A earlier in the classpath, and it will be found first. Of course anything that breaks as a result of doing so is Entirely Your Own Fault, and there will be cases where that breakage will (not may) surprise you -- you won't be able to intermix instances of A from the two different sources. (Having more than one classloader in use, for example, may paint you into that corner.) And anyone you show that solution to may run screaming.

But this is almost certainly an "x/y question". You've jumped to a solution rather than discussing the problem with us. It's almost certainly the wrong solution for the problem. I'd suggest you take a step back, figure out what it is you're trying to achieve by abusing the class system, then ask us for advice on how to do it legitimately.

keshlam
  • 7,931
  • 2
  • 19
  • 33
  • Thanks for your long answer. I solved the problem by changing the source code of Class A though I am reluctant to. Tweaking the class path is a good suggestion which we agree that it can be brittle for doing so. I guess substituting the class at the loading stage would be the only solution for either dynamic/static typing languages when the source code is not available. – huoenter Feb 18 '14 at 23:25