3 回答
TA贡献1821条经验 获得超4个赞
只是为这个答案添加更多内容,并让您对此有更多思考(将尝试以简单、非正式的方式进行)。使用接口是进行此类操作的正确方法。但是,我想站在“坏主意”上:
for (Object o : lists.getList(listNumber)) {
System.out.println(o.getClass().getMethod("getText"));
}
您在这里所做的是使用一种称为Reflection的机制:
反射是 Java 编程语言中的一个特性。它允许正在执行的 Java 程序检查或“内省”自身,并操纵程序的内部属性。例如,Java 类可以获取其所有成员的名称并显示它们。
您实际尝试的是使用该机制,通过Class您的类的反射对象实例检索该方法(听起来很奇怪,不是吗?)。
从这个角度来看,您需要考虑的是,如果您想调用您的方法,从某种意义上说,您现在拥有一个元类实例来操作您的对象。把它想象成一个比你的对象高一步的对象(类似于梦中的梦,在Inception 中)。从这个意义上说,您需要检索该方法,然后以不同的(类似元的)方式调用它:
java.lang.reflect.Method m = o.getClass().getMethod("getText");
m.invoke(o);
使用该逻辑,您可以遍历对象列表,检查方法是否存在,然后调用您的方法。
这是一个坏主意,坏主意。
为什么?嗯,答案依赖于反射本身:反射与运行时直接相关——即当程序执行时,实际上在运行时做所有事情,绕过编译世界。
换句话说,通过这样做,您绕过了 Java 的编译错误机制,允许在运行时发生此类错误。这会导致程序在执行时的行为不稳定——除了使用反射的性能开销外,这里不会分析。
旁注:虽然使用反射需要使用 Checked Exception 处理,但这样做仍然不是一个好主意 - 因为您实际上试图避开一个糟糕的解决方案。
另一方面,您可以通过类和接口遵循 Java 的继承机制 - 使用您的方法定义一个接口(让我们调用它Textable),确保您的类实现它,然后将其用作列表声明中的基对象(@alexrolea 已经在他的回答中实现了这一点,@OldCurmudgeon 也是如此)。
这样,您的程序仍然会在运行时做出方法调用决策(通过一种称为后期绑定的机制),但您不会绕过 Java 的编译错误机制。想一想:如果定义 Textable 实现而不提供类会发生什么 - 编译错误!如果您将非 Textable 对象设置到Textables列表中会怎样?你猜怎么着!再次编译错误。而这样的例子不胜枚举....
一般情况下,如果可以,请避免使用反射。反射在某些情况下很有用,您需要以这种元方式处理您的程序,并且没有其他方法可以制作这样的东西。然而事实并非如此。
更新:正如一些答案所建议的那样,您可以使用instanceof检查是否有包含您的方法的特定 Class 对象实例,然后分别调用。虽然这看起来是一个简单的解决方案,但它在扩展方面却很糟糕:如果您有 1000 个不同的类来实现您想要调用的相同方法怎么办?
TA贡献1773条经验 获得超3个赞
这太可怕了。你能详细说明你具体想做什么吗?Java 的设计是强类型的,而您正试图绕过它。为什么?使用之前建议的特定类或接口,而不是 Object。如果这是不可能的,并且您必须使用对象列表,请使用 instanceof 和强制转换,例如:
for (Object o : lists.getList(listNumber)) {
if (o instanceof Object1) {
Object1 o1 = (Object1) o;
System.out.println(o1.getText());
} else if (o instanceof Object2) {
Object2 o2 = (Object2) o;
System.out.println(o2.getText());
}
}
添加回答
举报