使用其通用参数扩展接口的方法签名实现接口
Implement an interface with a method signature whose generic parameters extend an interface
下面是我正在尝试完成的示例。我正在尝试创建实现 GenericRunner
的 LibraryRunner
。但是,我收到 IDE 警告,指出 LibraryRunner
未实现 GenericRunner
接口中的方法。这是有道理的,方法签名不匹配,但是如何在仍然使用扩展 GenericCalculator
的 LibraryCalculator
的同时使方法签名匹配?
public class LibraryRunner implements GenericRunner {
@Override
public <T> T run(LibraryCalculator<T> calculator) {
return T;
}
}
public interface GenericRunner {
<T, A> T run(GenericCalculator<T, A> calculator);
}
public interface LibraryCalculator<T> extends GenericCalculator<T, LibraryAlgorithm> {
T calc(LibraryAlgorithm algorithm) throws LibraryException;
}
public interface GenericCalculator<T, A> {
T calc(A algorithm) throws Exception;
}
public class LibraryException extends Exception {
}
当您重写或实现一个方法时,您始终需要满足被重写方法的条件,例如您仍然应该能够调用带有参数 GenericCalculator 的 LibraryRunner.run。否则这样写是没有意义的:
LibraryRunner libRunner = new LibraryRunner();
GenericRunner genRunner = libRunner;
genRunner.run(new GenericCalculator<>());
覆盖异常确实有效,因为当您调用 GenericCalculator.calc
时您期望任何异常并调用 LibraryCalculator.calc
将其缩小到仅 LibraryException
.
您可以查看覆盖方法作为承诺的更多信息。
接口的定义方式,即使 LibraryCalculator
是 GenericCalculator
的子类型,您也无法覆盖该方法并更改其签名。另一个答案解释了原因。
解决这个问题的一种方法是用计算器类型参数化 GenericRunner
接口:
public interface GenericRunner<T, A, C extends GenericCalculator<T, A>> {
T run(C calculator);
}
public class LibraryRunner<T> implements GenericRunner<T, LibraryAlgorithm, LibraryCalculator<T>> {
@Override
public T run(LibraryCalculator<T> calculator) {
...
}
}
但请注意,您不能在 LibraryRunner
方法中 return 一个 Object
,因为它不匹配 T
。如果你想 return 像 Object
这样的特定类型(这违背了通用 LibraryCalculator
的目的),你必须明确指定它:
public class LibraryRunner implements GenericRunner<Object, LibraryAlgorithm, LibraryCalculator<Object>> {
@Override
public Object run(LibraryCalculator<Object> calculator) {
return new Object();
}
}
如果这不是您想要的,则由 LibraryRunner
的用户决定 T
应该绑定到哪种类型。
下面是我正在尝试完成的示例。我正在尝试创建实现 GenericRunner
的 LibraryRunner
。但是,我收到 IDE 警告,指出 LibraryRunner
未实现 GenericRunner
接口中的方法。这是有道理的,方法签名不匹配,但是如何在仍然使用扩展 GenericCalculator
的 LibraryCalculator
的同时使方法签名匹配?
public class LibraryRunner implements GenericRunner {
@Override
public <T> T run(LibraryCalculator<T> calculator) {
return T;
}
}
public interface GenericRunner {
<T, A> T run(GenericCalculator<T, A> calculator);
}
public interface LibraryCalculator<T> extends GenericCalculator<T, LibraryAlgorithm> {
T calc(LibraryAlgorithm algorithm) throws LibraryException;
}
public interface GenericCalculator<T, A> {
T calc(A algorithm) throws Exception;
}
public class LibraryException extends Exception {
}
当您重写或实现一个方法时,您始终需要满足被重写方法的条件,例如您仍然应该能够调用带有参数 GenericCalculator 的 LibraryRunner.run。否则这样写是没有意义的:
LibraryRunner libRunner = new LibraryRunner();
GenericRunner genRunner = libRunner;
genRunner.run(new GenericCalculator<>());
覆盖异常确实有效,因为当您调用 GenericCalculator.calc
时您期望任何异常并调用 LibraryCalculator.calc
将其缩小到仅 LibraryException
.
您可以查看覆盖方法作为承诺的更多信息。
接口的定义方式,即使 LibraryCalculator
是 GenericCalculator
的子类型,您也无法覆盖该方法并更改其签名。另一个答案解释了原因。
解决这个问题的一种方法是用计算器类型参数化 GenericRunner
接口:
public interface GenericRunner<T, A, C extends GenericCalculator<T, A>> {
T run(C calculator);
}
public class LibraryRunner<T> implements GenericRunner<T, LibraryAlgorithm, LibraryCalculator<T>> {
@Override
public T run(LibraryCalculator<T> calculator) {
...
}
}
但请注意,您不能在 LibraryRunner
方法中 return 一个 Object
,因为它不匹配 T
。如果你想 return 像 Object
这样的特定类型(这违背了通用 LibraryCalculator
的目的),你必须明确指定它:
public class LibraryRunner implements GenericRunner<Object, LibraryAlgorithm, LibraryCalculator<Object>> {
@Override
public Object run(LibraryCalculator<Object> calculator) {
return new Object();
}
}
如果这不是您想要的,则由 LibraryRunner
的用户决定 T
应该绑定到哪种类型。