0

我想创建一些实用程序方法,并且我希望它能够在不同的对象上工作,只要它们可以提供一个可读/写的 Integer 属性。

我知道“标准”方式是:

  1. 声明一些IProvidesAccessToInteger具有setInteger和的接口getInteger
  2. 宣布MyUtility.doSomethingWonderful(IProvidesAccessToInteger obj)
  3. 拨打电话obj.setIntegerobj.getInteger

但这有一个非常强烈的缺点,即它需要我想与之合作的所有这些类的合作,MyUtility不仅如此,而且即使某些类想要合作MyUtility,仍然只能.doSomethingWonderful()对这些类的一个预定领域进行合作。

我正在寻找一些语法,它允许以某种MyUtility.doSomethingWonderful(T obj, Method<Integer> getter, Method<Integer,Integer> setter)方式使用泛型来指定obj具有设置和设置 Integer 的两个方法的要求,并有某种方法可以在obj.

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

更新:正如我提到的反射,我想澄清一下,我知道可以使用反射来完成接近的事情。

但是,由于我不需要在运行时解析实际接口,我希望 JAVA 有某种方式来指定某种“接口实现映射”,这样如果我的要求是一个具有两种方法的对象,int ?()void ?(int)可以指定类似的东西.doSomethingWonderful(?<int getter(),void setter(int)> obj),用某个具有的 object1 调用一次,int getInt()然后void setInt(int)用另一个具有的 object2调用一次,int getIntValue()void setIntValue(int)通过在调用中指定object满足 by 的要求getIntegergetInt满足 by 的要求setIntegersetInt依此类推。可能使用类似 `.doSomethingWonderful((?)object1) 的调用语法

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

也许正确的名称应该是匿名接口。

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

4

3 回答 3

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

我假设您使用的是 anint而不是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);
}
于 2013-10-31T08:53:04.120 回答
1

你的 getter 和 setter 是反射的典范。但这会带来很大的风险并失去性能。面向接口的编程是处理这种情况的非常常见的“标准”。

于 2013-10-31T09:01:52.737 回答
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);
于 2013-10-31T13:00:18.867 回答