我有一个方法,大约有十行代码。我想创建更多的方法来做完全相同的事情,除了一个会改变一行代码的小计算。这是一个传递函数指针来替换这一行的完美应用程序,但是Java没有函数指针。我最好的选择是什么?
当前回答
您需要创建一个接口,该接口提供您希望传递的函数。例如:
/**
* A simple interface to wrap up a function of one argument.
*
* @author rcreswick
*
*/
public interface Function1<S, T> {
/**
* Evaluates this function on it's arguments.
*
* @param a The first argument.
* @return The result.
*/
public S eval(T a);
}
然后,当你需要传递一个函数时,你可以实现这个接口:
List<Integer> result = CollectionUtilities.map(list,
new Function1<Integer, Integer>() {
@Override
public Integer eval(Integer a) {
return a * a;
}
});
最后,map函数使用Function1中传递的参数,如下所示:
public static <K,R,S,T> Map<K, R> zipWith(Function2<R,S,T> fn,
Map<K, S> m1, Map<K, T> m2, Map<K, R> results){
Set<K> keySet = new HashSet<K>();
keySet.addAll(m1.keySet());
keySet.addAll(m2.keySet());
results.clear();
for (K key : keySet) {
results.put(key, fn.eval(m1.get(key), m2.get(key)));
}
return results;
}
如果您不需要传递参数,您通常可以使用Runnable而不是自己的接口,或者您可以使用各种其他技术使参数计数不那么“固定”,但这通常是与类型安全的权衡。(或者你可以重写你的函数对象的构造函数,以这种方式传递参数。有很多方法,其中一些在特定情况下效果更好。)
其他回答
你也可以这样做(在一些罕见的情况下是有意义的)。问题(这是一个大问题)是您失去了使用类/接口的所有类型安全性,并且您必须处理方法不存在的情况。
它确实有一个“好处”,即您可以忽略访问限制并调用私有方法(示例中没有显示,但您可以调用编译器通常不允许您调用的方法)。
同样,这在很少的情况下是有意义的,但在那些情况下,这是一个很好的工具。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Main
{
public static void main(final String[] argv)
throws NoSuchMethodException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
final String methodName;
final Method method;
final Main main;
main = new Main();
if(argv.length == 0)
{
methodName = "foo";
}
else
{
methodName = "bar";
}
method = Main.class.getDeclaredMethod(methodName, int.class);
main.car(method, 42);
}
private void foo(final int x)
{
System.out.println("foo: " + x);
}
private void bar(final int x)
{
System.out.println("bar: " + x);
}
private void car(final Method method,
final int val)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
method.invoke(this, val);
}
}
好吧,这个帖子已经足够老了,所以我的回答很可能对这个问题没有帮助。但是因为这个帖子帮助我找到了我的解决方案,我还是把它放在这里。
我需要使用一个具有已知输入和已知输出(都是double)的变量静态方法。因此,知道了方法包和名称后,我可以这样工作:
java.lang.reflect.Method Function = Class.forName(String classPath).getMethod(String method, Class[] params);
对于接受一个double作为参数的函数。
在具体情况下,我用
java.lang.reflect.Method Function = Class.forName("be.qan.NN.ActivationFunctions").getMethod("sigmoid", double.class);
并在以后更复杂的情况下调用它
return (java.lang.Double)this.Function.invoke(null, args);
java.lang.Object[] args = new java.lang.Object[] {activity};
someOtherFunction() + 234 + (java.lang.Double)Function.invoke(null, args);
activity是任意的双精度值。我正在考虑可能做得更抽象和一般化一点,就像SoftwareMonkey所做的那样,但目前我对它的方式很满意。三行代码,没有必要的类和接口,还不错。
如果你只有一个不同的行,你可以添加一个参数,比如一个标志和一个If (flag)语句,它调用一行或另一行。
谷歌Guava库正在变得非常流行,它有一个通用的Function和Predicate对象,它们已经在API的许多部分中使用了这些对象。
我觉得这是个策略模式。查看fluffycat.com Java模式。
推荐文章
- 如何添加JTable在JPanel与空布局?
- Statement和PreparedStatement的区别
- 为什么不能在Java中扩展注释?
- 在Java中使用UUID的最重要位的碰撞可能性
- 转换列表的最佳方法:map还是foreach?
- 如何分割逗号分隔的字符串?
- Java字符串—查看字符串是否只包含数字而不包含字母
- Mockito.any()传递带有泛型的接口
- 在IntelliJ 10.5中运行测试时,出现“NoSuchMethodError: org.hamcrest. matcher . descripbemismatch”
- 使用String.split()和多个分隔符
- Java数组有最大大小吗?
- 在Android中将字符串转换为Uri
- 从JSON生成Java类?
- 为什么java.util.Set没有get(int index)?
- Swing和AWT的区别是什么?