将对象方法指定为java中的参数

时间:2013-10-31 08:49:25

标签: java generics methods delegates

我想创建一些实用工具方法,我希望它能够处理不同的对象,只要它们可以提供读/写的Integer属性。

我知道“标准”的方式是:

  1. 声明一些具有IProvidesAccessToIntegersetInteger的接口getInteger
  2. 声明MyUtility.doSomethingWonderful(IProvidesAccessToInteger obj)
  3. 拨打obj.setIntegerobj.getInteger
  4. 但这有一个非常强大的缺点,它需要我希望MyUtility所有那些课程的合作而不仅仅是这样,但即使某个班级想要合作MyUtility仍然只会能够.doSomethingWonderful()到该类的一个预定字段。

    我正在寻找一些允许像MyUtility.doSomethingWonderful(T obj, Method<Integer> getter, Method<Integer,Integer> setter)这样的东西的语法,可能会以某种方式使用泛型来指定obj有两个方法可以设置并设置一个Integer并有一些方法来调用它们位于obj的实例上。

    使用不需要对象的静态方法做类似的事情也可能很有趣。

    更新: 正如我指出的那样,我想澄清一点,我知道可以用反射完成近距离的事情。

    但是由于我不需要在运行时解析实际的接口,我希望JAVA有一些方法来指定“接口实现映射”的排序,这样如果我的需求是一个有两个方法的对象{ {1}}和int ?()我可以指定void ?(int)之类的内容,并使用某个包含.doSomethingWonderful(?<int getter(),void setter(int)> obj)int getInt()的object1调用一次,并使用其他具有{{{1}的其他object2调用一次1}}和void setInt(int)通过在int getIntValue()void setIntValue(int)满足object的要求,并getInteger满足getInt的要求} 等等。也许使用类似`.doSomethingWonderful((?)object1)

    的调用语法

    至少在理论上我认为应该可以在编译时完成所有操作并且不需要任何运行时反射。

    这可能是匿名界面的正确名称。

    说,我接受通过反射的运行时解决方案也可能是一个解决方案。

3 个答案:

答案 0 :(得分:1)

你不能用泛型来做这件事。

你可以用反射做到这一点。使用诸如BeanUtils之类的实用程序当然会更容易,但您也可以手动编写它。

public void doSomethingWonderful(final Object in, final String fieldName) 
        throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    final String upperCased = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    final Method getter = in.getClass().getMethod("get" + upperCased);
    final Method setter = in.getClass().getMethod("set" + upperCased, Integer.TYPE);

    //to invoke getter
    final int val = (int) getter.invoke(in);

    //to invoke setter
    setter.invoke(in, val);
}

我假设您使用的是int而不是Integer,在后一种情况下,您需要稍微更改一下代码。

你可以看到它引发了大量异常,我建议将它们全部包装在自定义异常类型中以简化客户端代码。

修改

Op希望将方法分解为三种重载方法:

public void doSomethingWonderful(final Object in, final String fieldName)
        throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    final String upperCased = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    doSomethingWonderful(in, "get" + upperCased, "set" + upperCased);
}

public void doSomethingWonderful(final Object in, final String getterName, final String setterName)
        throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    final Method getter = in.getClass().getMethod(getterName);
    final Method setter = in.getClass().getMethod(setterName);
    doSomethingWonderful(in, getter, setter);
}

public void doSomethingWonderful(final Object in, final Method getter, final Method setter)
        throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    //to invoke getter
    final int val = (int) getter.invoke(in);

    //to invoke setter
    setter.invoke(in, val);
}

答案 1 :(得分:1)

你的吸气剂和制定者是非常反思的范例。但这将导致很大的风险并失去性能。面向接口的编程是处理这种情况的常用“标准”。

答案 2 :(得分:1)

最接近你描述的东西将附带Java 8.你仍然需要接口,但调用者不需要关心它们,甚至更好,有很多默认接口用于典型的任务。例如,您可以定义如下方法:

static void increment(IntSupplier in, IntConsumer out)
{
  out.accept(in.getAsInt()+1);
}

并使用它来访问对象的不同属性:

class ClassWithInProperties {
  int a, b;

  public int getA() {
    return a;
  }
  public void setA(int a) {
    this.a = a;
  }
  public int getB() {
    return b;
  }
  public void setB(int b) {
    this.b = b;
  }
  @Override
  public String toString() {
    return "a="+a+", b="+b;
  }
}

ClassWithInProperties obj=new ClassWithInProperties();
increment(obj::getA, obj::setA);
increment(obj::getA, obj::setA);
increment(obj::getB, obj::setB);
System.out.println(obj);

或使用静态方法:

public class Test {
    static int DATA = 42;
    static int getData() {
        return DATA;
    }
    static void setData(int i) {
        DATA=i;
    }
}

increment(Test::getData, Test::setData);
System.out.println(DATA);