为了账号安全,请及时绑定邮箱和手机立即绑定

未知对象的调用方法

未知对象的调用方法

梦里花落0921 2021-10-28 14:51:16
我有两个 ArrayLists - ArrayList1 和 ArrayList2。它们中的每一个都填充了对象 - 分别是 Object1 和 Object2。这两个对象都有方法“getText”。对象 1:public String getText() { return "1";}对象 2:public String getText() { return "2";}在某些时候,我想使用相同的方法(只是使用不同的参数)遍历这些列表中的每一个。loopThroughList(1)loopThroughList(2)如果我想调用一个方法,但我不知道它是哪个对象,语法是什么?这是我到目前为止的代码:for (Object o : lists.getList(listNumber)) {    System.out.println(o.getText());}它说无法解析方法 getText。我用谷歌搜索并找到了另一个解决方案:for (Object o : lists.getList(listNumber)) {    System.out.println(o.getClass().getMethod("getText"));}但这给了我NoSuchMethodException错误。即使 'getText' 方法是公开的。编辑:为了获得正确的列表,我正在调用返回 ArrayList1 或 ArrayList2(取决于提供的参数)的不同对象(列表)的方法“getList”。class Listspublic getList(list) {    if (list == 1) {        return ArrayList1;    }    else if (list == 2) {        return ArrayList2;    }}
查看完整描述

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 个不同的类来实现您想要调用的相同方法怎么办?


查看完整回答
反对 回复 2021-10-28
?
慕容3067478

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());

    }

}


查看完整回答
反对 回复 2021-10-28
  • 3 回答
  • 0 关注
  • 168 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信