Прежде всего, я прочитал полезный ответ Эриксона на «Почему я не могу определить статический метод в интерфейсе 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)
, но я упомянул причину, почему нет.
(Правка: ОК, здесь подойдет абстрактный класс, реализующий интерфейс)
Теперь давайте предположим, что ParametricFunction
допускает только определенные параметры, например, целые положительные числа. Как проверить правильность параметров, переданных конструктору? Бросать исключение IllegalArgument
было бы возможно, но 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, что ближе к этому?
Идея, лежащая в основе этого, состоит в том, чтобы поместить несколько 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});
.