简体   繁体   English

在Java中将对象方法指定为参数

[英]specifying an object method as a parameter in java

I want to create some utility method and I want it to be able to work on different objects as long as they can provide an Integer property that is read/write. 我想创建一些实用程序方法,并且我希望它能够在不同的对象上工作,只要它们可以提供可读写的Integer属性即可。

I know the "Standard" way would be to: 我知道“标准”方式是:

  1. declare some interface IProvidesAccessToInteger that has setInteger and getInteger . 声明一些具有setIntegergetInteger接口IProvidesAccessToInteger
  2. declare MyUtility.doSomethingWonderful(IProvidesAccessToInteger obj) 声明MyUtility.doSomethingWonderful(IProvidesAccessToInteger obj)
  3. make calls to obj.setInteger and obj.getInteger . 调用obj.setIntegerobj.getInteger

But this has a very strong downside that it requires the cooperation of all those classes that I want MyUtility to work with and not only that but even if some class wants to cooperate MyUtility would still only be able to .doSomethingWonderful() to just a single predetermined field of that classes. 但这有一个很大的缺点,那就是需要我希望与MyUtility一起工作的所有这些类的合作,不仅如此,即使某些类想要合作, MyUtility仍然只能将.doSomethingWonderful()为一个该类的预定字段。

I am looking for some syntax that would allow for something like MyUtility.doSomethingWonderful(T obj, Method<Integer> getter, Method<Integer,Integer> setter) maybe using generics somehow to specify the requirement that obj has two methods that get set and set an Integer and have some way to call them on the instance of obj . 我正在寻找一些允许MyUtility.doSomethingWonderful(T obj, Method<Integer> getter, Method<Integer,Integer> setter)类的语法,也许以某种方式使用泛型来指定obj具有两个要设置的方法的要求,设置一个Integer并有某种方法可以在obj实例上调用它们。

It might also be interesting to do something similar with static methods that do not need an object. 对不需要对象的静态方法执行类似的操作可能也很有趣。

UPDATE: As I was pointed to reflection, I want to clarify that I know close things can be done using reflection. 更新:正如我指向反射时,我想澄清一下,我知道可以使用反射完成近距离的事情。

However since I don't need to resolve the actual interface in runtime I had the hope that JAVA has some way to specify sort of an "Interface fulfilment map" such that If my requirement would be an object that has two methods int ?() and void ?(int) I could specify something like .doSomethingWonderful(?<int getter(),void setter(int)> obj) and call it once with some object1 that has int getInt() and void setInt(int) and once with some other object2 that has int getIntValue() and void setIntValue(int) by specifying in the calls that object fulfills the requirements for getInteger by getInt and fulfills the requirements for setInteger by setInt and so on. 但是,由于我不需要在运行时解析实际的接口,所以我希望JAVA有某种方法可以指定某种类型的“接口实现图”,使得如果我的要求是具有两个方法int ?()的对象,和void ?(int)我可以指定类似.doSomethingWonderful(?<int getter(),void setter(int)> obj)并使用一些具有int getInt()void setInt(int) object1进行一次调用与其他一些具有int getIntValue()void setIntValue(int)的object2一样,方法是在调用中指定该object满足getIntgetInteger的要求,并满足setIntsetInteger的要求,依此类推。 maybe with a call syntax like `.doSomethingWonderful((?)object1) 可能带有`.doSomethingWonderful((?)object1)这样的调用语法

At least in theory I think it should be possible to do all at compile time and not require any runtime reflection. 至少从理论上讲,我认为应该可以在编译时完成所有操作,而不需要任何运行时反射。

maybe the right name for this would by an anonymous interface. 也许通过匿名接口为此名称正确。

that said, I accept that a runtime solution via reflection might also be a solution. 也就是说,我接受通过反射的运行时解决方案也可能是一种解决方案。

You cannot do this with generics. 您不能使用泛型执行此操作。

You can do this with reflection. 您可以通过反射来做到这一点。 Using a utility such as BeanUtils would of course be easier, but you can write it by hand too. 使用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);
}

I have assumed that you are using an int rather than an Integer , you will need to change the code slightly in the latter case. 我假设您使用的是int而不是Integer ,在后一种情况下,您将需要稍微更改代码。

You can see that it throws a massive number of exceptions, I would recommend wrapping them all in a custom exception type to simplify client code. 您会看到它抛出了大量异常,我建议将它们包装在自定义异常类型中,以简化客户端代码。

EDIT 编辑

Op wants the break down the method into three overloaded methods: 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);
}

Your getter and setter are pretty Paradigm of reflection. 你的getter和setter是反射的典范。 But that would be import much risk and lose performance. 但这将带来很多风险,并会导致性能下降。 Interface Oriented Programming are pretty common "standard" to handle this scenario. 面向接口的编程是处理这种情况的非常常见的“标准”。

The thing closest to your description will come with Java 8. You still need interfaces but the caller does not need to care about them and even better, there are plenty of default interfaces for typical tasks. 与您的描述最接近的东西将随Java 8一起提供。您仍然需要接口,但调用者不需要关心它们,甚至更好的是,对于典型的任务,有很多默认接口。 For example, you can define a method like this: 例如,您可以定义如下方法:

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

and use it like that to access different properties of an object: 并像这样使用它来访问对象的不同属性:

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

or with static methods: 或使用静态方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM