Прежде всего, я прочитал полезный ответ erickson на "Почему я не могу определить статический метод в интерфейсе Java?" . Этот вопрос касается не "почему", а "как тогда?".
Изменить: мой оригинальный пример был некорректным, но я оставлю его ниже.
Хотя я теперь убежден, что в большинстве случаев то, что я хочу сделать, это слишком много, есть один сценарий, где это может понадобиться:
Я снова возьму пример ParametricFunction
. Теперь возьмем сложную функцию, например функции Бесселя, где соответствующая таблица соответствия. Это должно быть инициализировано, поэтому два параметра передают параметры непосредственно конструктору или предоставляют 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)
, но я упомянул о причине, почему бы и нет.
(Edit: OK, здесь будет реализован абстрактный класс, реализующий интерфейс)
Теперь предположим, что ParametricFunction
допускает только определенные параметры, например. положительные целые числа. Как проверить степень доступности параметров, переданных конструктору? Вероятность выброса IllegalArgument
была бы возможна, но checkParametersValidity(double[] parameters)
кажется намного более удобным. Но проверка параметров должна быть выполнена до построения, поэтому он должен быть статическим методом. И то, где я действительно хотел бы знать способ убедиться, что каждый класс, реализующий интерфейс ParametricFunction
, определяет этот статический метод.
Я знаю, что этот пример является довольно искусственным, и причина не просто используя init
метода через интерфейс спорно, я все же хотел бы знать ответ. Считайте это академическим вопросом, если вам это не нравится.
(исходный пример)
Поэтому в основном я хочу, чтобы один интерфейс обеспечивал как обычные методы, так и, например, a getSimilarObject
. Пример (составленный)
public interface ParametricFunction {
/** @return f(x) using the parameters */
static abstract public double getValue(double x, double[] parameters);
/** @return The function 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, что является самым близким к этому?
Идея этого заключается в размещении нескольких ParametricFunction
в пакете и использовании Reflection, чтобы перечислить их все, что позволяет пользователю выбирать, например. какой из них можно построить. Очевидно, что можно было бы предоставить класс загрузчика, содержащий массив доступных ParametricFunction
s, но каждый раз, когда будет реализован новый, нужно также запомнить его там.
edit: пример для вызова
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});
.