Java multiple interfaces and reflection

2019-07-11 21:44发布

问题:

I have a class called X that implements multiple (e.g. 3) interfaces, call them A, B and C.

I create another interface AB that extends interface A and B.

How can I use reflection to create an instance of X that is assignable to interface AB?

I keep getting ClassCast exceptions with this code:

package test.messages;

public interface A
{
    void methodA();
}

package test.messages;

public interface B
{
    void methodB();
}

package test.messages;

public interface C
{
    void methodC();
}

package test.messages;

public interface AB extends A, B
{

}

package test.messages;

public class X implements A, B, C
{
    @Override
    public void methodC()
    {
        System.out.println("C");
    }

    @Override
    public void methodB()
    {
        System.out.println("B");
    }

    @Override
    public void methodA()
    {
        System.out.println("A");
    }
}

Then in a completely different class:

AB api = (AB)Class.forName("test.messages.X").newInstance();

System.out.println(api);

Now when I try with just one interface, say A, it works fine.

Is there anyway to get it to work with the combined interface AB?

回答1:

What you really want is AND type -- A&B. This is generally not supported in Java. However, we could create a wrapper class that contains a value that is both type A and type B. (It seems that every problem can be solved by a wrapper:)

public class AB<T extends A&B>
{
    public final T v;

    ... 
        v = (T)Class.forName("test.messages.X").newInstance();
}

Instead of using type A&B, we use AB<?> everywhere it's needed. We'll operate on its field v, which is both A and B.

void foo(AB<?> ab)
{
    ab.v.methodOfA();
    ab.v.methodOfB();
}

Or you could make AB a subtype of A and B too.

public class AB<T extends A&B> implements A, B
{
    public final T v;

    @Override // A
    public int methodOfA(){ return v.methodOfA(); }

See more at https://stackoverflow.com/a/32659085/2158288



回答2:

The is-a relationship doesn't work that way. The fact that AB implements A and B and X implements A and B doesn't make X assignable to AB.

Even if you could think that AB is compatible with any type that implements A and B that's not the case as AB is a different type and the hierarchy tree in Java is fixed with the definition of the classes themselves.

Think about the Liskov substitution principle: if you add a method to AB then X is not a valid candidate anymore since it wouldn't contain the method declared in AB.

You would need a programming language that supports a structural type system to do it.



回答3:

You can't do that because in the inheritance tree X does not implement AB. If A,B,C are all interfaces a easy way to fix the problem is to say that X implements AB,C which that means it can be cast as A, as B, as C and as AB.