【发布时间】:2011-02-10 23:18:19
【问题描述】:
首先,我阅读了埃里克森对"Why can’t I define a static method in a Java interface?" 的有用回复。这个问题不是关于“为什么”,而是关于“那么如何?”。
编辑:我原来的例子是不合适的,但我会把它留在下面。
虽然我现在确信在大多数情况下我想要做的是矫枉过正,但有一种情况可能需要它:
我将再次以ParametricFunction 为例。现在让我们采用一个复杂的函数,例如Bessel functions,其中适合使用查找表。这必须初始化,因此这两个选项是将参数直接传递给构造函数或提供init(double[] parameters)。后者的缺点是 getValue(double x) 必须在每次调用时检查初始化(或者 ArrayIndexOutOfBoundsException 必须被视为初始化检查),因此对于时间要求严格的应用程序,我更喜欢构造函数方法:
interface ParametricFunction {
public double getValue(double x);
}
class BesselFunction implements ParametricFunction {
public BesselFunction(double[] parameters) { ... }
public double getValue(double x) { ... }
}
这涉及到另一个问题,接口中的构造函数是不可能的。那里有什么好的解决方案?我当然可以使用init(double[] parameters) 方法,但我提到了我不这样做的原因。
(编辑:好的,这里有一个实现接口的抽象类)
现在让我们假设 ParametricFunction 只允许某些参数,例如正整数。如何检查传递给构造函数的参数的有效性?抛出IllegalArgument-exception 是可能的,但checkParametersValidity(double[] parameters) 似乎更方便。但是需要在构造之前检查参数,所以它必须是静态方法。这就是我真的很想知道一种方法来确保实现ParametricFunction 接口的每个类都定义了这个静态方法。
我知道这个例子是相当人为的,而不是简单地通过接口使用init 方法的原因是有争议的,我仍然想知道答案。如果您不喜欢它,请将其视为学术问题。
(原始示例)
所以基本上我想要一个接口来提供常用方法,例如getSimilarObject 方法。对于(编造的)例子
public interface ParametricFunction {
/** @return f(x) using the parameters */
static abstract public double getValue(double x, double[] parameters);
/** @return The function's name */
static abstract public String getName();
/** @return Whether the parameters are valid [added on edit] */
static abstract public boolean checkParameters(double[] parameters);
}
然后
public class Parabola implements ParametricFunction {
/** @return f(x) = parameters[0] * x² + parameters[1] * x + parameters[2] */
static public double getValue(double x, double[] parameters) {
return ( parameters[2] + x*(parameters[1] + x*parameters[0]));
}
static public String getName() { return "Parabola"; }
// edit:
static public boolean checkParameters(double[] parameters) {
return (parameters.length==3);
}
}
既然当前的 Java 标准不允许这样做,那么最接近这个的是什么?
这背后的想法是将几个ParametricFunctions 放在一个包中并使用反射将它们全部列出,允许用户选择例如绘制哪一个。显然,可以提供一个包含可用ParametricFunctions 数组的加载器类,但是每次实现一个新的时,都必须记住在其中添加它。
编辑:调用它的一个例子是
public double evaluate(String fnName, double x, double parameters) throws (a lot) {
Class<ParametricFunction> c = (Class<ParametricFunction>) ClassLoader.getSystemClassLoader().loadClass(fnName);
Method m = c.getMethod("getValue", x, parameters);
return ((double) m.invoke(null));
}
并致电evaluate("Parabola", 1, new double[]{1,2,0});。
【问题讨论】:
-
为什么 getValue 必须是静态的?如果 getValue 不是静态的,您将能够完全按照您的意愿行事。
-
然后我必须创建一个类的实例。如果我错了,请纠正我,但关于它的目的似乎在这里没有用。
-
你的设计有问题。这不是OO。 parameters[] 应该是 Parabola 类的实例字段,在构造函数中设置和检查,并在 getValue() 类中使用。
-
我真的没有看到实例化这些类的问题,这是最简单的解决方案。如果您希望能够将新的 ParametricFunction 实现动态部署到您的应用程序,您可以在已部署 jar 的清单文件中指明兼容的类。您当然需要一些代码来启用此机制。另一方面,我看不出静态接口方法在这里有什么帮助。
-
@Michael:但现在假设我想将数据点拟合到用户选择的函数,现在我所要做的就是调用
fit(fnName, double[] x, double y[]),Fitter 会找到参数。我知道这不是 OO,但这里有什么优势?好吧,现在问题来了,为什么要把参数放在提供静态拟合功能的Fitter中……好吧,你说服了我,我得重新考虑设计。
标签: java interface static abstract