如何调用对象参数而不是Java中实际参数类型的方法?

时间:2019-02-09 07:45:16

标签: java

大家好,我只是想知道如何调用将对象类型作为参数而不是实际参数的方法。假设我有一个类

public class Helper {

    public void showEntity(Message msg)
    {
        System.out.println(msg.sessionID);
    }

}

现在我想调用showEntity方法,但是我只知道有关参数类型名称的信息,即消息,自然地,我将使用Class.forName()。getClass创建此类的对象,然后将创建一个新实例等等。

Class<?> clazz=Class.forName(nameOfParameterType).getClass();
Object obj=clazz.newInstance();

现在出现了一个问题,我将如何通过传入创建的对象类型而不是实际的消息类型来实际调用showEntity方法,因为调用showEntity(obj)会出错并且我不想使用反射来校准此方法,我想通过

Helper helper=new Helper();
helper.showEntity(obj) //gives error 

5 个答案:

答案 0 :(得分:4)

简单的答案是:像(Message) thatObjThatIsAMessage一样进行转换。或者,通过使用反射来调用该方法(这当然只会在这里增加疯狂)。

真正的答案是:您正在钻错非常严重的兔子洞。

您不会调用方法并传递任意参数,因为可以。这样做是因为需要

如果您不知道将什么参数传递给方法,为什么您认为应该首先调用该方法?就像“我不知道拨打911(或您的紧急电话号码)时发生了什么,但是我面前有电话,所以我现在就去做”。

当然:您随后考虑使用反射的事实就增加了这一点。反思和做事byName()是您绝对只有在没有其他选择的情况下才能做的事情!谁说例如您的Message类具有一个无参数的构造函数,以便newInstance()实际上可以解决?如果今天有一个,但是拥有它的人明天删除,该怎么办。您将仅在运行时学习!这并不是要贬低您,而是说老实话:一个不知道如何转换对象的人缺少基本的Java知识。反思完全超出了您在该技能级别上应该面对的范围。

长话短说:立即停止,并确定您确实要做的事情。我向您保证:不要调用没有适当参数的方法!

答案 1 :(得分:2)

我不确定是否丢失了某些内容,但是您可以进行投射。如果您确定类型只能是Message,那应该可以正常工作

helper.showEntity((Message)obj);

我只是出于代码质量的考虑,在调用之前添加某种检查,并在类型不是Message的情况下抛出IllegalArgumentException。

答案 2 :(得分:1)

1)不执行import UIKit func f<T>(t: T) where T: UIView, T: Encodable {} class C<T> where T: UIView, T: Encodable {} ,而是执行clazz.newInstance();以确保捕获任何已检查的异常。

2)永远不要编写这样的代码:clazz.getConstructor().newInstance();
最好的习惯用法是将赋值强制转换为helper.showEntity((Message)obj);以便集中化实例化/广播逻辑及其异常:

newInstance()

3)尽可能鼓励Class<?> clazz = ...; try { Messsage message = (Message) clazz.getConstructor().newInstance(); // do something with message } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | InstantiationException | ClassCastException e) { // handle the exception } 进行反思。
如果该类是在编译时在某个地方定义的,并且由于您期望一个特定的类(Supplier)似乎是这种情况,则应该执行以下操作:

Message

答案 3 :(得分:-1)

helper.showEntity((Message)obj) //gives error-您需要强制转换

可运行版本:

public class SO {


public static class Helper {
    public void showEntity(Message msg) {
        System.out.println(msg.sessionID);
    }
}

public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {

    Class<?> clazz= Class.forName(Message.class.getName());
    Message msg = (Message) clazz.newInstance();
    msg.sessionID = UUID.randomUUID().toString();
    new Helper().showEntity(msg);// here the instance is cast to Message and should work.

}

答案 4 :(得分:-1)

一个选项如下。在这种情况下,您可以传递给showEntity的类型仅限于Message类型及其子类,我认为应该是这种情况,否则您将不知道如何获取该对象的实例以及由于未打开而要调用的方法反射API。不知道要传递什么类型,就需要使用反射API。

public class Helper {

    public void showEntity(String msgImpl) {
        try {
            System.out.println(getMessageInstance(msgImpl).getSessionId());
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private Message getMessageInstance(String msgImpl)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Class<? extends Message> msg = Class.forName(msgImpl).asSubclass(Message.class);
        return msg.newInstance();
    }

    public static void main(String[] args) {
        Helper h = new Helper();
        h.showEntity("com.foo.Message");
    }
}

public class Message {

    public String getSessionId() {
        return "SessionID";
    }
}