Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在运行时确定正确的方法签名_Java_Reflection - Fatal编程技术网

Java 在运行时确定正确的方法签名

Java 在运行时确定正确的方法签名,java,reflection,Java,Reflection,我正在使用以下类org.apache.poi.hssf.usermodel.HSSFCell,以及以下方法列表: void setCellValue(boolean value) void setCellValue(java.util.Calendar value) void setCellValue(java.util.Date value) void setCellValue(double value) void setCellValue(HSSFRichTextString val

我正在使用以下类
org.apache.poi.hssf.usermodel.HSSFCell
,以及以下方法列表:

void setCellValue(boolean value)

void setCellValue(java.util.Calendar value)

void setCellValue(java.util.Date value)

void setCellValue(double value)

void setCellValue(HSSFRichTextString value)

void setCellValue(java.util.Calendar value)

void setCellValue(HSSFRichTextString value)
请注意,没有对象作为方法参数的方法

现在,我无法在编译期间确定我的值类类型。我只能在运行时确定我的值类类型。因此,如果在编译期间不知道方法签名,如何确定要调用的正确方法

我的代码如下:

final int rowCount = tableModel.getRowCount();
for (int i = 0; i < rowCount; i++) {
    final HSSFRow row = sheet.createRow(i + 1);
    for (int j = 0; j < columnCount; j++) {
        final Object object = tableModel.getValueAt(i, j);
        final Class myClass = tableModel.getColumnClass(j);
        // How to perform casting during compiled time, and invoke
        // the setCellValue with correct signature?
        if (object != null) {
            row.createCell(j).setCellValue(??); // Does not accept Object!
        }
    }
}
final int rowCount=tableModel.getRowCount();
对于(int i=0;i

如果…用
instanceof
解决我的问题,可能会很难看。但是,如果我不想看到丑陋的if…else,那么有没有更好的方法呢?

我认为
instanceof
是一条出路。如果您认为这会使代码变得丑陋,请将表达式的
实例提取到辅助方法中:

public void setCellValue(HSSFCell cell, Object value) {
    if (null == cell)
        throw new IllegalArgumentException("cell");
    if (null == value)
        throw new IllegalArgumentException("value");
    if (value instanceof Double)
        cell.setCellValue((Double)value); // auto-boxing will handle this
    else if (value instanceof Boolean) {
        cell.setCellValue((Boolean)value); // auto-boxing will handle this
    } else if (value instanceof Calendar) {
        cell.setCellValue((Calendar)value);
    } else if ...
        .....
    } else {
        throw new UnsupportedTypeException("Object of class " + Value.class.getName() + " not supported.");
    }
}
或者,您可以使用反射。即使使用反射,我认为您仍然必须对基本类型进行一些自定义,因为自动装箱不适用于
getMethod()

public void invokeSetCellValue(HSSFCell cell, Object obj) {
    try {
        Class<?> clazz = obj.getClass();
        if (obj instanceof Double) {
            clazz = double.class;
        } else if (obj instanceof Boolean) {
            clazz = boolean.class;
        }
        Method m = HSSFCell.class.getMethod("setCellValue", clazz);
        m.invoke(cell, obj);
    } catch (SecurityException e) {
    } catch (NoSuchMethodException e) {
    } catch (IllegalArgumentException e) {
    } catch (IllegalAccessException e) {
    } catch (InvocationTargetException e) {
    }

}
public void invokeSetCellValue(HSSFCell单元格,对象obj){
试一试{
Class clazz=obj.getClass();
if(双精度的obj实例){
clazz=双级;
}else if(obj instanceof Boolean){
clazz=boolean.class;
}
方法m=HSSFCell.class.getMethod(“setCellValue”,clazz);
m、 调用(cell,obj);
}捕获(安全异常e){
}捕获(无此方法例外){
}捕获(IllegalArgumentException e){
}捕获(非法访问例外e){
}捕获(调用TargetException e){
}
}

处理此问题的一种方法是在运行时将方法列表加载到
映射
中,然后对于每个调用,使用
映射
。也就是说,类似这样的代码(简化了此代码并省略了错误检查):

但如果没有这种优化,并且具有完全的通用性,下面是我的示例:

import java.lang.reflect.*;
import java.util.*;

public class Test {
  private final Map<Object, Method> parameterTypeMap = new HashMap<Object, Method>();

  private final Object[] tests = {Double.valueOf(3.1415),
                                  Boolean.TRUE,
                                  new Date(),
                                  new GregorianCalendar(),
                                  new HashMap<Object, Object>()};

  public Test() {
    Method[] methods = Setters.class.getMethods();
    for (Method method : methods) {
      if (method.getName().equals("setCellValue")) {
        Class<?>[] clazzes = method.getParameterTypes();
        if (clazzes.length != 1) {
          continue;
        }
        if (clazzes[0].isPrimitive()) {
          handlePrimitive(method, clazzes[0]);
        }
        parameterTypeMap.put(clazzes[0], method);
      }
    }
  }

  // See http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isPrimitive()
  private void handlePrimitive(Method method, Class<?> clazz) {
    if (clazz == Boolean.TYPE) {
      parameterTypeMap.put(Boolean.class, method);
    } else if (clazz == Double.TYPE) {
      parameterTypeMap.put(Double.class, method);
    } // ... and so on for the other six primitive types (void doesn't matter)
  }

  public void doTests(Setters setter) {
    for (Object test : tests) {
      Method method = findMethodToInvoke(test);
      if (method == null) {
        System.out.println("Nothing found for " + test.getClass());
        continue;
      }

      try {
        method.invoke(setter, test);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  private Method findMethodToInvoke(Object test) {
    Method method = parameterTypeMap.get(test.getClass());
    if (method != null) {
      return method;
    }

    // Look for superclasses
    Class<?> x = test.getClass().getSuperclass();
    while (x != null && x != Object.class) {
      method = parameterTypeMap.get(x);
      if (method != null) {
        return method;
      }
      x = x.getSuperclass();
    }

    // Look for interfaces
    for (Class<?> i : test.getClass().getInterfaces()) {
      method = parameterTypeMap.get(i);
      if (method != null) {
        return method;
      }
    }
    return null;
  }

  public static void main(String[] args) {
    Test test = new Test();
    test.doTests(new Setters());
  }
}

class Setters {
  public void setCellValue(boolean value) {
    System.out.println("boolean " + value);
  }

  public void setCellValue(double value) {
    System.out.println("double " + value);
  }

  public void setCellValue(Calendar value) {
    System.out.println("Calendar " + value);
  }

  public void setCellValue(Date value) {
    System.out.println("Date " + value);
  }

  public void setCellValue(Map<?, ?> value) {
    System.out.println("Map " + value);
  }
}
import java.lang.reflect.*;
导入java.util.*;
公开课考试{
私有最终映射参数typemap=newhashmap();
私有最终对象[]测试={Double.valueOf(3.1415),
Boolean.TRUE,
新日期(),
新的Gregorianalendar(),
新HashMap()};
公开考试(){
方法[]方法=Setters.class.getMethods();
用于(方法:方法){
if(method.getName().equals(“setCellValue”)){
类[]clazzes=method.getParameterTypes();
如果(clazzes.length!=1){
继续;
}
if(类[0].isPrimitive()){
handlePrimitive(方法,类别[0]);
}
parameterTypeMap.put(clazzes[0],方法);
}
}
}
//看http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isPrimitive()
私有void handlePrimitive(方法,类clazz){
if(clazz==Boolean.TYPE){
parameterTypeMap.put(Boolean.class,method);
}else if(clazz==Double.TYPE){
parameterTypeMap.put(Double.class,method);
}//…等其他六种基本类型(void不重要)
}
公共无效点测试(设置器设置器){
用于(对象测试:测试){
方法=findMethodToInvoke(试验);
if(方法==null){
System.out.println(“没有为“+test.getClass()找到任何内容”);
继续;
}
试一试{
调用(setter、test);
}捕获(例外e){
e、 printStackTrace();
}
}
}
私有方法findMethodToInvoke(对象测试){
Method=parameterTypeMap.get(test.getClass());
if(方法!=null){
返回法;
}
//寻找超类
类x=test.getClass().getSuperclass();
while(x!=null&&x!=Object.class){
方法=parameterTypeMap.get(x);
if(方法!=null){
返回法;
}
x=x.getSuperclass();
}
//寻找接口
对于(类i:test.getClass().getInterfaces()){
方法=parameterTypeMap.get(i);
if(方法!=null){
返回法;
}
}
返回null;
}
公共静态void main(字符串[]args){
测试=新测试();
test.doTests(新Setters());
}
}
排班员{
公共void setCellValue(布尔值){
System.out.println(“布尔”+值);
}
公共void setCellValue(双值){
System.out.println(“双“+值);
}
公共void setCellValue(日历值){
System.out.println(“日历”+值);
}
public void setCellValue(日期值){
系统输出打印项次(“日期”+值);
}
公共void setCellValue(映射值){
System.out.println(“映射”+值);
}
}

如果您没有子类(如果有子类,您仍然可以这样做,但如果有子类,则会更加困难,请告诉我),您可以使用反射:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main
{
    public static void main(final String[] argv)
        throws NoSuchMethodException,
               IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        final Object o;

        if(argv.length == 0)
        {
            o = "Hello";
        }
        else
        {
            o = Integer.valueOf(42);
        }

        callFoo(o);
    }

    private static void callFoo(final Object o) 
        throws NoSuchMethodException,
               IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        Method method;

        method = Main.class.getDeclaredMethod("foo", o.getClass());
        method.invoke(null, o);
    }

    private static void foo(final String val)
    {
        System.out.println("foo(String) -> " + val);
    }

    private static void foo(final Integer val)
    {
        System.out.println("foo(Integer) -> " + val);
    }
}
缺点是,如果您试图调用一个不存在的方法,编译器不会告诉您

上面代码中的异常处理完全是废话,但我想把重点放在反射部分


从具有编译时类型安全性的角度来看,使用的实例更好。如果添加了新方法,反射将不必更新。

非常可怕。为了完整起见,你能发布一个代码片段吗
import java.lang.reflect.*;
import java.util.*;

public class Test {
  private final Map<Object, Method> parameterTypeMap = new HashMap<Object, Method>();

  private final Object[] tests = {Double.valueOf(3.1415),
                                  Boolean.TRUE,
                                  new Date(),
                                  new GregorianCalendar(),
                                  new HashMap<Object, Object>()};

  public Test() {
    Method[] methods = Setters.class.getMethods();
    for (Method method : methods) {
      if (method.getName().equals("setCellValue")) {
        Class<?>[] clazzes = method.getParameterTypes();
        if (clazzes.length != 1) {
          continue;
        }
        if (clazzes[0].isPrimitive()) {
          handlePrimitive(method, clazzes[0]);
        }
        parameterTypeMap.put(clazzes[0], method);
      }
    }
  }

  // See http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isPrimitive()
  private void handlePrimitive(Method method, Class<?> clazz) {
    if (clazz == Boolean.TYPE) {
      parameterTypeMap.put(Boolean.class, method);
    } else if (clazz == Double.TYPE) {
      parameterTypeMap.put(Double.class, method);
    } // ... and so on for the other six primitive types (void doesn't matter)
  }

  public void doTests(Setters setter) {
    for (Object test : tests) {
      Method method = findMethodToInvoke(test);
      if (method == null) {
        System.out.println("Nothing found for " + test.getClass());
        continue;
      }

      try {
        method.invoke(setter, test);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  private Method findMethodToInvoke(Object test) {
    Method method = parameterTypeMap.get(test.getClass());
    if (method != null) {
      return method;
    }

    // Look for superclasses
    Class<?> x = test.getClass().getSuperclass();
    while (x != null && x != Object.class) {
      method = parameterTypeMap.get(x);
      if (method != null) {
        return method;
      }
      x = x.getSuperclass();
    }

    // Look for interfaces
    for (Class<?> i : test.getClass().getInterfaces()) {
      method = parameterTypeMap.get(i);
      if (method != null) {
        return method;
      }
    }
    return null;
  }

  public static void main(String[] args) {
    Test test = new Test();
    test.doTests(new Setters());
  }
}

class Setters {
  public void setCellValue(boolean value) {
    System.out.println("boolean " + value);
  }

  public void setCellValue(double value) {
    System.out.println("double " + value);
  }

  public void setCellValue(Calendar value) {
    System.out.println("Calendar " + value);
  }

  public void setCellValue(Date value) {
    System.out.println("Date " + value);
  }

  public void setCellValue(Map<?, ?> value) {
    System.out.println("Map " + value);
  }
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main
{
    public static void main(final String[] argv)
        throws NoSuchMethodException,
               IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        final Object o;

        if(argv.length == 0)
        {
            o = "Hello";
        }
        else
        {
            o = Integer.valueOf(42);
        }

        callFoo(o);
    }

    private static void callFoo(final Object o) 
        throws NoSuchMethodException,
               IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        Method method;

        method = Main.class.getDeclaredMethod("foo", o.getClass());
        method.invoke(null, o);
    }

    private static void foo(final String val)
    {
        System.out.println("foo(String) -> " + val);
    }

    private static void foo(final Integer val)
    {
        System.out.println("foo(Integer) -> " + val);
    }
}