2013-11-22 94 views
0

我遇到反射問題以計算用戶傳遞了多少個參數,並將參數的長度與預期計數進行比較。如果滿足此要求,則繼續執行方法調用程序的Object[] { incommingArguments }(可變參數)參數。使用可變參數的Java反射調用方法

我在我的LogicGates類中有一個名爲compute()的方法。該方法需要2到3個參數。第一個參數是門,下一個1或2是輸入,取決於門的輸入。

目前,帶有簽名的方法:

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

正確執行,但如果我用

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

簽名,然後我的代碼中斷。我正在使用我在這裏找到的可變參數的邏輯: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; 
    } 
} 
+0

不變量參數得到的待遇作爲一個數組? – MadProgrammer

+1

它們應該被自動轉換爲Object [],這是Sun(現在的Oracle)告訴我的向後兼容性。 –

+1

「代碼中斷」是什麼意思? – chrylis

回答

0

在Java 7中,使用invokeWithArguments方法。

編輯:當然,這意味着使用Java 7 MethodHandle類代替舊的Java 1.1 Method類。

+0

我會檢查這一點,雖然我只用'invoke()'得到了這個工作。謝謝。 –

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 & 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))); 
     } 
    } 
} 
相關問題