[更新]:我最初的例子没有反射(reflect)出我的问题。更新了示例,希望现在更好。
Java 泛型和重载不能很好地结合在一起。
public interface Request<E> {
E getValue();
}
我有一个通用的参数化 Request 接口(interface),如上,我想写一个 DataStore 类来保存请求携带的负载。不同的负载类型保存逻辑不同。
我真正想要的是类似的东西
public interface DataStore {
void save(Request<E1> r);
void save(Request<E2> r);
}
但这当然是违法的。
如果我想保持类型安全,DataStore 必须为我想处理的每种类型声明不同的方法,例如
public interface DataStore {
// here E1 is the actual type I want to handle, not a generic parameter
public void saveE1(Request<E1> e);
public void saveE2(Request<E2> e);
}
或者牺牲类型安全
public class DataStore {
public void save(Request e) {
Object value = e.getValue();
if (value instanceof ReqE1Impl) {
// do something
} else if (value instanceof ReqE2Impl) {
// do something else
}
}
}
两种方式都很糟糕!有没有更好的办法?
最佳答案
更好的方法是让对象知道如何保存自己。如果您仍然想使用 DataStore,您可以这样做:
interface YourInterface {
void save();
}
interface Request<E extends YourInterface> {
E getValue();
}
class DataStore<E extends YourInterface> {
public void save(Request<E> r) {
r.getValue().save();
}
}
您只需确保您的对象然后每个都实现该接口(interface)
和中提琴,泛型和多态性可以很好地相互配合。
注意:您的(修改后的)问题的编写方式,您没有使用多态性。您正在使用重载。方法重载在编译时决定,而方法多态性在运行时决定。这就是您遇到这些困难的部分原因。
如果你真的不想要上面那种由对象完成所有 self 保存工作的设计,那么也许你可以做这样的事情(作为一个非常弱的例子):
interface YourInterface {
String serialize();
}
interface Request<E extends YourInterface> {
E getValue();
}
class DataStore<E extends YourInterface> {
public void save(Request<E> r) {
String value = r.getValue().serialize();
// Now do something with value to save to a datastore
}
}
上面是一个薄弱的例子,但主要思想是对象知道如何执行对象之间不同的序列化部分,然后 DataStore 可以执行所有对象共有的工作。
是的,您是对的(用错了术语)——泛型在重载方面表现不佳。但是它们确实可以很好地处理多态性。无论如何,多态性通常是比重载更好的工具。
关于Java 通用问题 : Any better way?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/800731/