我有一个方法foo
void foo (String x) { ... }
void foo (Integer x) { ... }
我希望从一个不关心参数的方法中调用它:
void bar (Iterable i) {
...
for (Object x : i) foo(x); // this is the only time i is used
...
}
上面的代码抱怨我没有定义foo(Object)
,当我添加
void foo (Object x) { throw new Exception; }
然后bar(Iterable<String>)
调用而不是foo(String)
并抛出异常。
如何避免对bar(Iterable<String>)
和bar(Iterable<Integer>)
两个文本相同的定义?
我以为我能够摆脱像
这样的东西<T> void bar (Iterable<T> i) {
...
for (T x : i) foo(x); // this is the only time i is used
...
}
然后我收到cannot find foo(T)
错误。
答案 0 :(得分:2)
您面临的问题是重载方法在编译时受到约束。在您的示例中,编译器尝试确定要调用的foo()
方法中的哪一个。但是,示例中最强的静态类型x
是Object,并且没有方法foo(Object)
,因此编译器说它无法调用适当的方法。
如果添加foo(Object)
方法,无论x的实际运行时类型是什么,您都将始终调用foo(Object)
方法。
此问题扩展到使用泛型。由于T
可以是任何类型,因此您必须具有通用方法foo(T)
,否则您的代码将无法编译。但是,如果添加该方法,则无法在不同的参数类型之间识别这些方法,因为只会调用foo(T)
。
解决这个问题的唯一方法是逐个案例检查,并像其他答案一样进行投射。除非参数类型是您定义的类,否则它们都可以实现公共接口。然后你可以做类似的事情:
interface ArgumentType {
void callback(FooClass c);
}
class YourClassA implements ArgumentType {
void callback( FooClass c ) {
c.foo( this );
}
}
对于FooClass
的每个实现类, foo()
仍然必须有ArgumentType
方法,但这样您就可以按类型不可知进行选择。
答案 1 :(得分:1)
以这种方式思考:如果foo
是x
,应该调用哪个版本的Object
?
这就是JVM面临的问题。
如果你想要一个真正的多态方法,那么你需要明确地写一个。然后,这样的方法可以通过内省检查Object
以查看它的实际类类型是什么,并在此之后调用适当的方法。
或,您可以仔细查看foo
的内容。是否只调用Object
定义的方法?如果是这样,只需创建一个执行必需品的void foo(Object x)
方法。
答案 2 :(得分:1)
问题是你试图找到foo(Object x)
而String和Integer都是对象,并不是所有的对象都是String或Integer,而java也不会缩小到正确的类。
我或许会建议创建一个方法:
void foo(Object o){
if ( o instanceof String){
String s = (String) o;
//Deal with s
} else if ( o instanceof Integer){
Integer i = (Integer) o;
//Deal with i
}
}
另外,如果你正在使用泛型,你不应该在bar中传递原始迭代器