简体   繁体   中英

Use a static type only obtainable at runtime

Let's say I have a situation as follows:

A class X has a field s of type S .

S is extended by two classes A and B both implementing some same methods/fields that we all know should then be implemented in S but, unfortunately, this is not the case.

Now I want to do something like this:

"A or B" downcast_field;
if(s instanceof A)
    downcast_field = (A)s;
else if (s instanceof B)
     downcast_field = (B)s;

//do something common for the two cases but that need methods implemented both in A and B

The problem is then having in advance a static type (out of the IFs ) that allows me to call such methods.

I guess that due to bad design this is actually impossible and I have to write twice the same code, which is ugly, but perhaps there is a solution that I am not seeing right now.

If you can change A and B , then you can add the same interface to both. That would allow you to give this type to downcast_field and invoke methods.

If you can't change A and B , then you have two options:

  • You can write A2 and B2 . Copy the code from A and B into the new types. That allows you to modify the code (unless you can't control the creation of those types). Alternatively, you could also now create S2 which extends S and put the common code in there and then extend A2 / B2 from that.

  • Create an interface and then two implementations which just delegate the calls to the real type.

    In this solution, you can

     Wrapper downcast_field; if(s instanceof A) downcast_field = new AWrapper( (A)s ); else if (s instanceof B) downcast_field = new BWrapper( (B)s ); downcast_field.foo(); 

    You can make the two wrappers extend the same type and move common code there.

As far as i understand your situation is the following ?

public class S {
}

public class A extends S {

    public void doSomething() {
        System.out.println("A is doing something ...");
    }
}

public class B extends S {

    public void doSomething() {
        System.out.println("B is doing something ...");
    }
}

actually i think this design is rather bad. if you have a chance to clean this up you should do this. if this is not an option the following workaround is possible ... introduce an interface declaring the common API and wrap your instances using this interface ...

public interface WrapperInterface {
    void doSomething();
}

then you might use this like so

public class Main {

    public static void main(String[] args) {
        WrapperInterface a=wrap(new A());
        WrapperInterface b=wrap(new B());

        a.doSomething();
        b.doSomething();
    }

    private static WrapperInterface wrap(final S s) {
        WrapperInterface downcast_field=null;
        if (s instanceof A)
            downcast_field = new WrapperInterface() {
                @Override
                public void doSomething() {
                    ((A) s).doSomething();
                }
            };
        else if (s instanceof B) {
            downcast_field = new WrapperInterface() {
                @Override
                public void doSomething() {
                    ((B) s).doSomething();
                }
            };
        }
        return downcast_field;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM