java.reflection.Method.invoke(…)不重新转换参数

java.reflection.Method.invoke(…)不重新转换参数,java,swing,reflection,Java,Swing,Reflection,我正在试用Java反射API。我只是将任何给定类的方法对象提取到JComboBox中,并在其itemSelected上为参数(当然还有调用对象)创建一个接口 这工作正常,没有问题 但是在invokeButton的操作中,我试图使用给定的参数来invke所选的方法 最初它说参数计数不同。我的一位朋友告诉我,paramVals数组引用了实际值,这可能会导致问题,也可能是由于作用域的缘故。然后我开始创建类Object的新对象,然后给它们赋值。这对param count有效。但现在的问题是参数的类型转换

我正在试用Java反射API。我只是将任何给定类的方法对象提取到JComboBox中,并在其itemSelected上为参数(当然还有调用对象)创建一个接口

这工作正常,没有问题

但是在invokeButton的操作中,我试图使用给定的参数来invke所选的方法

最初它说参数计数不同。我的一位朋友告诉我,paramVals数组引用了实际值,这可能会导致问题,也可能是由于作用域的缘故。然后我开始创建类Object的新对象,然后给它们赋值。这对param count有效。但现在的问题是参数的类型转换不正确。甚至字符串类型转换为对象(因为它必须是对象数组)也不会被转换回字符串

文档说invoke方法将自己强制转换它们,如果强制转换失败,将抛出IllegalArgumentException

我不明白是什么导致调用invoke方法失败

以下是框架的代码:

package nttraining.abhay.reflectiondemo;
//imports go here

public class ReflectionFrame 
    extends JFrame
    implements ActionListener, ItemListener{

    JComboBox methods;
    JButton invokeButton;

    public ReflectionFrame(String title) throws HeadlessException {
        super(title);
        //Layout components

        //adding methods of class String to a combo
        Class<String> c = String.class;
        Method ml[] = c.getMethods();
        for(Method m : ml){
            methods.addItem(m);
        }

        invokeButton.addActionListener(this);
        methods.addItemListener(this);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource().equals(invokeButton)){
            Method selected = (Method) methods.getSelectedItem();
            Class paramtypes[] = selected.getParameterTypes();
            Object paramVals[] = new Object[paramtypes.length];
            System.out.println("Method : " + selected.toString());
            for(int i=0; i<paramtypes.length; i++){
                Object obj = new Object();
                obj = paramtypes[i].cast(params[i].getText());
                paramVals[i] = obj;
                System.out.println("Added " + paramtypes[i].cast(params[i].getText()).toString() + " to params");
            }
            try {
                result.setText(selected.invoke(object.getText(), params).toString());

            } catch (Exception ex) {
                System.out.println(ex.getClass().getName() + ": " + ex.getMessage());
            }
        }
    }

    @Override
    public void itemStateChanged(ItemEvent e) {
        Method selected = (Method) methods.getSelectedItem();
        if(selected==null)
            return;
        Class paramtypes[] = selected.getParameterTypes();
        int paramCount = paramtypes.length;
        object = new JTextField();
        paramNames = new JLabel[paramCount];
        params = new JTextField[paramCount];
        panel.removeAll();
        panel.setLayout(new GridLayout(paramCount+1, 2));
        panel.add(new JLabel("Calling object"));
        panel.add(object);
        for(int i=0; i<paramCount; i++){
            paramNames[i] = (JLabel) panel.add(new JLabel(paramtypes[i].getName()));
            params[i] = (JTextField) panel.add(new JTextField());
        }
        invalidate();
        validate();
    }

}
包nttraining.abhay.reflectiondemo;
//进口到这里
公共类反射框架
扩展JFrame
实现ActionListener、ItemListener{
JComboBox方法;
JButton调用ebutton;
公共ReflectionFrame(字符串标题)抛出HeadlessException{
超级(标题);
//布局组件
//向组合添加类字符串的方法
c类=String.Class;
方法ml[]=c.getMethods();
用于(方法m:ml){
方法:addItem(m);
}
invokeButton.addActionListener(这个);
方法:addItemListener(this);
}
@凌驾
已执行的公共无效操作(操作事件e){
if(例如getSource().equals(invokeButton)){
所选方法=(方法)方法。getSelectedItem();
类paramtypes[]=selected.getParameterTypes();
Object paramVals[]=新对象[paramtypes.length];
System.out.println(“方法:+selected.toString());

对于(int i=0;i我发现的问题如下:
obj=paramtypes[i].cast(params[i].getText());

cast
不转换对象,它只验证给定对象属于某个类。由于您总是提供一个
String.class
作为参数(通过
.getText()
),因此对于字符串类型参数以外的任何参数,此操作都将失败。即使Integer.class到primitive int也将失败

下面是一段代码,演示了
cast
问题

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

public class Q21642768 {

public static void main(String[] args) {

    try {
        // Calls String.indexOf(str, fromIndex) via reflection.
        callStringMethod("Hello reflection world", "reflection", 1);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void callStringMethod(String s, String subString, int startIndex) throws Exception {

    Class<String> c = String.class;
    Method ma[] = c.getMethods();
    Method indexOfSub = null;
    Class<?>[] indexOfSubPTypes = null;
    List<Method> stringMethods = new ArrayList<Method>();
    List<Type[]> stringMethodsPTypes = new ArrayList<Type[]>();
    for (Method m: ma) {
        stringMethods.add(m);
        System.out.print(m.getName() + ": ");
        Class<?>[] mptypes = m.getParameterTypes();
        stringMethodsPTypes.add(mptypes);
        boolean first = true;
        for (Type t : mptypes) {
            if (first) {
                first = false;
            } else {
                System.out.print(", ");
            }
            System.out.print(t.toString());
        }
        if ("indexOf".equals(m.getName()) 
                && mptypes.length == 2 
                && mptypes[0].equals(String.class)
                && mptypes[1].equals(int.class)) {
            indexOfSub = m;
            indexOfSubPTypes = mptypes;
            System.out.println(" <-- ");
        } else {
            System.out.println();
        }
    }
    if (indexOfSub == null) {
        System.out.println("target method not found");
        return;
    }
    Object[] pValues = new Object[2];
    pValues[0] = indexOfSubPTypes[0].cast(subString);
    // Fails:
    // pValues[1] = indexOfSubPTypes[1].cast(startIndex);
    // pValues[1] = indexOfSubPTypes[1].cast(startIndex + "");
    pValues[1] = startIndex;

    Object result = indexOfSub.invoke(s, pValues);
    System.out.println("Result: " + result);
}

}
import java.lang.reflect.Method;
导入java.lang.reflect.Type;
导入java.util.ArrayList;
导入java.util.List;
公开课Q21642768{
公共静态void main(字符串[]args){
试一试{
//通过反射调用String.indexOf(str,fromIndex)。
callStringMethod(“你好,反射世界”,“反射”,1);
}捕获(例外e){
e、 printStackTrace();
}
}
公共静态void callStringMethod(字符串s、字符串子字符串、int-startIndex)引发异常{
c类=String.Class;
方法ma[]=c.getMethods();
方法indexOfSub=null;
类[]indexOfSubPTypes=null;
List stringMethods=new ArrayList();
List stringMethodsPTypes=new ArrayList();
用于(方法m:ma){
方法。添加(m);
System.out.print(m.getName()+“:”);
类[]mptypes=m.getParameterTypes();
StringMethodsTypes.add(mptypes);
布尔值优先=真;
对于(t型:mptypes){
如果(第一){
第一个=假;
}否则{
系统输出打印(“,”);
}
System.out.print(t.toString());
}
if(“indexOf”.equals(m.getName())
&&mptypes.length==2
&&mptypes[0]。等于(String.class)
&&mptypes[1]。等于(int.class)){
indexOfSub=m;
indexOfSubPTypes=mptypes;

System.out.println(“问题在于所有参数值都是字符串对象,因为它们是通过JTextField.getText()获得的。字符串是这些值的运行时类型,而方法参数的类型通常是不同的,这才是重要的

要成功调用该方法,首先需要将每个值转换为paramTypes数组中指定的正确类型。cast()和invoke()都不需要这意味着你必须找到一种从字符串转换的方法,基本上是从字符串值反序列化到一个适当类的对象,这可能并不总是可能的,也不太复杂。在这一点上,我认为你可以开始想象你正在尝试做的事情的复杂性。这离记住,每个参数值通常不是一个简单的值,而是一个完整的对象图,这就是复杂性所在

例如,如果一个方法参数的类型是一个接口,那么您如何知道实例化哪个具体的实现?如果您确实找到一个具体的类来实现它-这可能并不总是可能的-那么您将如何创建该类的实例?这里您将进入一个由Java序列化框架覆盖的域这些框架中有相当多是开源的,你可能想看看其中的一些,你会发现这样的fraleworks的综合列表

几年前,我在一个相关的项目中工作,我必须提供一个Swing GUI,让最终用户能够创建任意类型的对象,作为规则引擎的输入。我想到的是一个具有多个根的JTree,与一个属性表(即一个具有2列的JTable)相关联,其中树叶要么是简单类型,要么是简单类型(原语、原语包装、日期等)或对象引用。每个引用将指向特定的树根