如何从实现接口的泛型类返回接口?

www*_*www 7 java generics

我想创建一个方法来接受T实现任何接口的任何类I

然后对类做一些事情并返回实现的接口I

这是我尝试过的:

class MyLibrary {
    
    public static <I, T extends I> I registerImplementation(Class<T> classImpl) {
        I interfaceImpl = (I) classImpl.newInstance();
        return interfaceImpl;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我创建一个接口和一个实现该接口的类:

interface UserInterface {
    void doSomethingDefined();
}

class UserClass_v1_10_R2 implements UserInterface {

    @Override
    public void doSomethingDefined() {
        System.out.println("What this does is well-defined");
    }

    public void doVersionSpecificStuff() {
        System.out.println("This is not in the interface, so don't really depend on this");
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我调用方法引用时UserClass,它返回相同的类类型T而不是接口类型I,从而允许调用所有未在接口中声明的类方法。

即在下面的语句中,即使registerImplementation()声明为返回对 的引用UserInterface,编译器仍将引用视为指向 的实例UserClass_v1_10_R2,从而允许访问不在接口中的实现方法。

MyLibrary.registerImplementation(UserClass_v1_10_R2.class).doVersionSpecificStuff();
Run Code Online (Sandbox Code Playgroud)

将此与所谓的相同

UserInterface uiObj = MyLibrary.registerImplementation(UserClass_v1_10_R2.class);

uiObj.doVersionSpecificStuff(); // This does not compile
Run Code Online (Sandbox Code Playgroud)

Eug*_*ene 1

这就是编译器推断类型的方式。如果您使用特殊(未记录)标志进行编译:

javac --debug=verboseResolution=all  ...
Run Code Online (Sandbox Code Playgroud)

你会看到:

  Note: Deferred instantiation of method <I,T>registerImplementation(Class<T>)
  MyLibrary.registerImplementation(UserClass_v1_10_R2.class).doVersionSpecificStuff();
                                    ^
  instantiated signature: (Class<UserClass_v1_10_R2>)UserClass_v1_10_R2
Run Code Online (Sandbox Code Playgroud)

查看实例化的签名:(Class<UserClass_v1_10_R2>)UserClass_v1_10_R2

因此,您需要添加另一个参数来获取接口:

public static <I, T extends I> I registerImplementation(Class<I> interfaceClass, Class<T> implClass) {
    // do whatever checks you want if this is an interface or if a constructor can be called....
    I interfaceImpl = null;
    try {
        interfaceImpl = interfaceClass.cast(implClass.newInstance());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return interfaceImpl;
}
Run Code Online (Sandbox Code Playgroud)

当然,如果您有多个接口,这会引发问题,但这是您需要考虑的事情。