使用varargs的Java反射调用方法

时间:2013-11-22 03:10:33

标签: java reflection methods invoke variadic-functions

我遇到反射问题,要计算用户传递的参数数量,并将参数长度与预期计数进行比较。如果满足此要求,则继续使用方法调用者的Object[] { incommingArguments }(varargs)参数执行该方法。

我的compute()课程中有一个名为LogicGates的方法。该方法需要2到3个参数。第一个参数是门,接下来的1或2是输入,具体取决于门的输入。

目前,该方法带有签名:

compute(gate:GATE,a:boolean,b:boolean):boolean

正确执行,但如果我使用

compute(gate:GATE,<VARARGS>:boolean):boolean

签名然后我的代码中断了。我正在使用我在这里找到的varargs逻辑:StackOverflow: Invoke method with an array parameter using reflection

在我的问题的最后,两个方法都可以在LogicGates.java的底部找到。

输出

 A | B | AND     A | B | OR     A | B | NAND     A | B | NOR     A | B | XOR     A | B | XNOR     A | B | XNOR_NAND     A | B | XNOR_NOR     A | B | IF_THEN     A | B | THEN_IF    
---+---+-----   ---+---+----   ---+---+------   ---+---+-----   ---+---+-----   ---+---+------   ---+---+-----------   ---+---+----------   ---+---+---------   ---+---+---------   
 T | T | T       T | T | T      T | T | F        T | T | F       T | T | F       T | T | T        T | T | T             T | T | T            T | T | T           T | T | T          
 T | F | F       T | F | T      T | F | T        T | F | F       T | F | T       T | F | F        T | F | F             T | F | F            T | F | F           T | F | T          
 F | T | F       F | T | T      F | T | T        F | T | F       F | T | T       F | T | F        F | T | F             F | T | F            F | T | T           F | T | F          
 F | F | F       F | F | F      F | F | T        F | F | T       F | F | F       F | F | T        F | F | T             F | F | T            F | F | T           F | F | T          

GateTest.java

public class GateTest {
    public static void main(String[] args) {
        StringBuffer[] rows = newStringBufferArray(6, "");

        for (LogicGates.GATE g : LogicGates.GATE.values()) {
            if (g.operands == 2)
                rows = fillTable(g, rows, repeat(' ', 3));
        }

        for (StringBuffer row : rows) {
            System.out.println(row);
        }
    }

    private static final StringBuffer[] fillTable(final LogicGates.GATE gate,
            StringBuffer[] buffer, String delimiter) {
        int l = buffer.length - 1;
        String name = gate.name();
        String pad = repeat('-', name.length() + 1);

        buffer[0].append(String.format(" A | B | %s %s", name, delimiter));
        buffer[1].append(String.format("---+---+-%s%s", pad, delimiter));

        for (byte b = 3; b >= 0; --b)
            buffer[l - b].append(fillRow(gate, intToBool(b >> 1),
                    intToBool(b & 1), delimiter));

        return buffer;
    }

    private static final String fillRow(final LogicGates.GATE gate, boolean a,
            boolean b, String delimiter) {
        return String.format(" %c | %c | %c%s %s", boolToChar(a),
                boolToChar(b),
                boolToChar(LogicGates.compute(gate, a, b)),
                repeat(' ', gate.name().length() - 1), delimiter);
    }

    public static final StringBuffer[] newStringBufferArray(int size,
            String initialValue) {
        if (initialValue == null)
            initialValue = "";

        StringBuffer[] bufferArr = new StringBuffer[size];

        for (int i = 0; i < size; i++)
            bufferArr[i] = new StringBuffer(initialValue);

        return bufferArr;
    }

    private static final String repeat(char ch, int count) {
        StringBuilder sb = new StringBuilder();

        while (sb.length() < count)
            sb.append(ch);

        return sb.toString();
    }

    private static final char boolToChar(final boolean bool) {
        return bool ? 'T' : 'F';
    }

    private static final boolean intToBool(final int input) {
        return intToBool((byte) input);
    }

    private static final boolean intToBool(final byte input) {
        if (input < 0 || input > 1)
            throw new IllegalArgumentException("Input must be 0 or 1");

        return input == 1;
    }
}

LogicGates.java

import java.lang.reflect.Method;
import java.util.Arrays;

@SuppressWarnings("unused")
public final class LogicGates {
    public static enum GATE {
        NOT("not", "Negation", 1), // .
        AND("and", "Logical conjunction", 2), // .
        OR("or", "Logical disjunction", 2), // .
        NAND("nand", "Logical NAND", 2), // .
        NOR("nor", "Logical NOR", 2), // .
        XOR("xor", "Exclusive disjunction", 2), // .
        XNOR("xnor", "Logical biconditional", 2), // .
        XNOR_NAND("xnorNand", "XNOR using only NAND gates.", 2), // .
        XNOR_NOR("xnorNor", "XNOR using only NOR gates.", 2), // .
        IF_THEN("ifThen", "Material implication.", 2), // .
        THEN_IF("thenIf", "Converse implication.", 2); // .

        private String methodName, description;
        int operands;

        private GATE(String methodName, String description, int operands) {
            this.methodName = methodName;
            this.description = description;
            this.operands = operands;
        }

        protected String methodName() {
            return methodName;
        }

        protected int operands() {
            return operands;
        }
    }

    private LogicGates() {
        throw new AssertionError();
    }

    private static final boolean not(boolean a) {
        return !a;
    }

    private static final boolean and(final boolean a, final boolean b) {
        return a && b;
    }

    private static final boolean or(final boolean a, final boolean b) {
        return a || b;
    }

    private static final boolean nand(final boolean a, final boolean b) {
        return not(and(a, b));
    }

    private static final boolean nor(final boolean a, final boolean b) {
        return not(or(a, b));
    }

    private static final boolean xor(final boolean a, final boolean b) {
        return or(and(a, not(b)), and(not(a), b));
    }

    private static final boolean xnor(final boolean a, final boolean b) {
        return or(and(a, b), nor(a, b));
    }

    private static final boolean xnorNand(final boolean a, final boolean b) {
        return nand(nand(nand(a, nand(a, b)), nand(b, nand(a, b))),
                nand(nand(a, nand(a, b)), nand(b, nand(a, b))));
    }

    private static final boolean xnorNor(final boolean a, final boolean b) {
        return nor(nor(a, nor(a, b)), nor(b, nor(a, b)));
    }

    private static final boolean ifThen(final boolean a, final boolean b) {
        return or(and(a, b), not(a));
    }

    private static final boolean thenIf(final boolean a, final boolean b) {
        return or(a, nor(a, b));
    }

    public static final boolean compute(GATE gate, boolean... values) {
        boolean result = false;

        if (values.length != gate.operands())
            throw new IllegalArgumentException(String.format(
                    "%s gate requires %d inputs.", gate.name(), gate.operands));

        try {
            Class<?> c = Class.forName(LogicGates.class.getName());
            Method method = null;

            if (gate.operands() == 2)
                method = c.getDeclaredMethod(gate.methodName(), boolean.class,
                        boolean.class);
            else if (gate.operands() == 1) {
                method = c.getDeclaredMethod(gate.methodName(), boolean.class);
            } else {
                method = null;
            }

            boolean[] args = Arrays.copyOfRange(values, 0, values.length);
            result = (boolean) method.invoke(c, new Object[] { args });
        } catch (Exception e) {
            System.out.println(e.getMessage() + " " + e.getCause());
        }

        return result;
    }

    public static final boolean compute(GATE gate, boolean a, boolean b) {
        boolean result = false;

        try {
            Class<?> c = Class.forName(LogicGates.class.getName());
            Method method = null;

            if (gate.operands() == 2)
                method = c.getDeclaredMethod(gate.methodName(), boolean.class,
                        boolean.class);
            else if (gate.operands() == 1) {
                method = c.getDeclaredMethod(gate.methodName(), boolean.class);
            } else {
                method = null;
            }

            result = (boolean) method.invoke(c, a, b);
        } catch (Exception e) {
            System.out.println(e.getMessage() + " " + e.getCause());
        }

        return result;
    }
}

2 个答案:

答案 0 :(得分:0)

在Java 7中,使用invokeWithArguments方法。

编辑:当然,这意味着使用Java 7 MethodHandle类代替旧的Java 1.1 Method类。

答案 1 :(得分:0)

好吧,在我坐下来思考一下之后,我想出了一个解决方案:

<强>输出

>> Invoking SimpleGate.not(false)
>> Invoking SimpleGate.and(true,true)
>> Invoking SimpleGate.or(true,false)
>> Invoking SimpleGate$AdvancedGate.xor(true,false)
PASS

<强> ReflectTest.java

public class ReflectTest {
    private enum Gate {
        NOT(SimpleGate.class),
        AND(SimpleGate.class),
        OR(SimpleGate.class),
        XOR(SimpleGate.AdvancedGate.class);

        private Class<?> clazz;

        private Gate(Class<?> clazz) { this.clazz = clazz; }

        public Class<?> clazz() { return clazz; }
    }

    public static boolean compute(Gate gate, Boolean... input) {
        return (Boolean) Reflect.call(gate.clazz(),
                gate.name().toLowerCase(), (Object[]) input);
    }

    public static void main(String[] args) {
        Boolean not = compute(Gate.NOT, false);
        Boolean and = compute(Gate.AND, true, true);
        Boolean or = compute(Gate.OR, true, false);
        Boolean xor = compute(Gate.XOR, true, false);

        if (not && and && or && xor)
            System.out.println("PASS");
        else
            System.out.println("FAIL");
    }
}

<强> Reflect.java

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public abstract class Reflect {
    public static final Object call(Class<?> clazz, String methodName, Object... varArgs) {
        try {
            Object invokee = null;
            String className = clazz.getName();
            int argc = varArgs.length;
            Class<?>[] classList = new Class[argc];
            StringBuffer varArgsStr = new StringBuffer();

            for (int i = 0; i < argc; i++) {
                Object argv = varArgs[i];
                classList[i] = argv.getClass();
                varArgsStr.append(argv.toString());

                if (i < argc - 1) varArgsStr.append(',');
            }
            System.out.printf(">> Invoking %s.%s(%s)\n", className,methodName, varArgsStr);

            Class<?> target = Class.forName(className);
            Method method = target.getDeclaredMethod(methodName, classList);
            int childIndex = className.indexOf('$');

            if (childIndex > -1) {
                String wrappingClassName = className.substring(0, childIndex);
                Class<?> wrapper = Class.forName(wrappingClassName);
                Object wrapperInstance = wrapper.newInstance();
                Constructor<?> con = target.getDeclaredConstructor(wrapper);

                invokee = con.newInstance(wrapperInstance);
            } else {
                boolean isStatic = Modifier.isStatic(method.getModifiers());

                invokee = isStatic ? target : target.newInstance();
            }

            return method.invoke(invokee, varArgs);

        } catch(Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

SimpleGate.java&amp; SimpleGate $ AdvancedGate.java

public class SimpleGate {
    public Boolean not(Boolean a) { return !a; }

    public static Boolean and(Boolean a, Boolean b) { return a && b; }

    public static Boolean or(Boolean a, Boolean b) { return a || b; }

    public class AdvancedGate {
        public Boolean xor(Boolean a, Boolean b) {
            return or(and(not(a),b),and(a,not(b)));
        }
    }
}