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);
}
}