Подтвердить что ты не робот

Есть ли способ убедиться, что классы, реализующие интерфейс, реализуют статические методы?

Прежде всего, я прочитал полезный ответ 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});.

4b9b3361

Ответ 1

Вы не можете требовать, чтобы классы реализовали определенные статические методы через интерфейс. Это просто не имеет смысла в Java-терминах. Интерфейсы заставляют присутствие определенных нестатических методов в классах, реализующих интерфейс; что они делают.

Самый простой способ - это определенно иметь класс factory, который создает экземпляры других. Да, это означает, что вы должны помнить о том, чтобы поддерживать этот factory актуальным при добавлении новых экземпляров, но так как первое, что вы делаете, когда делаете новую реализацию, это проверить его (вы проверяете его, да?) вы быстро займетесь этой проблемой!

Ответ 2

Почему бы не попробовать перечислить Java 5? то есть:

public enum ParametricFunctions implements ParametricFunction {
    Parabola() {
        /** @return f(x) = parameters[0] * x² + parameters[1] * x + parameters[2] */
        public double getValue(double x, double[] parameters) {
            return ( parameters[2] + x*(parameters[1] + x*parameters[0]));
        }

        public String getName() { return "Parabola"; }

        public boolean checkParameters(double[] parameters) {
            return (parameters.length==3);
        }
    },

    // other functions as enum members
}

С помощью этого вы можете легко найти статические типы функций и с безопасностью во время компиляции, но все же позволить использовать тип интерфейса в другом месте. Вы также можете поместить метод в тип перечисления, чтобы разрешить поиск функции по имени.


EDIT для проблем с размером файла с помощью способа перечисления.

В этом случае вы можете определить каждую функцию как свой собственный класс, то есть:

public class Parabola implements ParametricFunction {

    /** @return f(x) = parameters[0] * x² + parameters[1] * x + parameters[2] */
    public double getValue(double x, double[] parameters) {
        return ( parameters[2] + x*(parameters[1] + x*parameters[0]));
    }

    public String getName() { return "Parabola"; }

    public boolean checkParameters(double[] parameters) {
        return (parameters.length==3);
    }

}

Затем у вас может быть много отдельных файлов реализации и их компоновка в один, меньший, подобный enum класс, через который эти функции могут быть доступны статически. То есть:

public class ParametricFunctions {  
    public static final ParametricFunction parabola = new Parabola(),
                                           bessel = new BesselFunction(),
                                           // etc
}

Это позволяет одному месту искать функции, при этом реализация сохраняется отдельно. Вы также можете добавить их в статическую коллекцию для поиска имени. Затем вы могли бы поддерживать читаемость в своих функциях, как указано в другом комментарии:

import static ...ParametricFunctions.parabola;
// etc

public void someMethodCallingFit() {
    fit(parabola, xValues, yValues);
}

Ответ 3

Идея этого заключается в несколько ParametricFunction в пакет и использование Отражение в список их всех, позволяя пользователю выбирать например который можно построить.

Это приведет к сбою по более простой причине: отражение не дает возможности перечислить все классы в пакете (поскольку "все классы в пакете" не являются четко определенным набором из-за гибкости механизма загрузчика классов).

Современное решение для такого рода вещей заключается в том, чтобы сделать его частью конфигурации приложения через инфраструктуру внедрения зависимостей.

Очевидно, можно было бы предоставить загрузчик класс, содержащий массив доступный параметр ParametricFunction, но каждый раз, когда новый нужно помнить о добавлении его там, тоже.

Хорошо, с вашей концепцией, каждый раз, когда новый реализуется, каждый вынужден помещать его в один и тот же пакет. Поместив его в файл конфигурации или класс загрузчика (то же самое, на самом деле), вы удалите это ограничение.

Ответ 4

Ваш ответ на свой вопрос может быть еще более упрощен. Сохраните интерфейс ParametricFunction as-is и измените Parabola на одноэлементный, который реализует ParametricFunction:

public class Parabola implements ParametricFunction {
  private static Parabola instance = new Parabola();

  private Parabola() {}

  static public ParametricFunction getInstance() {
    return instance;
  }

  public double getValue(double x, double[] parameters) {
    return ( parameters[2] + x*(parameters[1] + x*parameters[0]));
  }
  public String getName() { return "Parabola"; }
  public boolean checkParameters(double[] parameters) {
    return (parameters.length==3);
  }
}

В самом деле, если нет особой причины, почему Parabola должен быть одноэлементным классом, вы можете избавиться от статического метода и атрибута и сделать конструктор общедоступным.

Цель создания экземпляра Parabola - упростить ваше приложение.

ИЗМЕНИТЬ в ответ на ваш вопрос ниже:

Вы не можете использовать стандартные Java-конструкции, чтобы заставить класс реализовать статический метод с заданной сигнатурой. В Java нет такой вещи, как абстрактный статический метод.

Вы можете проверить, что статический метод реализуется путем написания отдельного инструмента, который выполняется как часть вашей сборки и проверяет либо исходный код, либо скомпилированный код. Но ИМО, это не стоит усилий. Любой отсутствующий getInstance() будет отображаться, если вы скомпилируете код, который вызывает его, или во время выполнения, если вы попытаетесь использовать его с точки зрения отражения. Это, по-моему, должно быть достаточно хорошим.

Кроме того, я не могу придумать убедительной причины, по которой вам нужен класс, чтобы быть одиночным; то есть метод getInstance необходим.

Ответ 5

Причина - читаемость: fit ( "Парабола", xValues, fValues) против fit (Parabola.getInstance(), xValues, fValues) против fit (новый Parabola(), xValues, fValues). Почему я хочу имеют установленный экземпляр функции полностью своими аргументами без внутренние данные?

На самом деле вам не хватает чего-то о принципах ориентированного программирования объектов...

Если вы определяете объект Parabola, этот объект должен представлять Parabola, а не панель инструментов для проверки параметров в порядке и т.д.

Ваш элемент Parabola должен содержать параметры (x, y...), и вы можете передать их с помощью конструктора...

double x;
double [] parameters;
public Parabola(double x, double[] parameters) {
  this.x = x;
  this.parameters = parameters;
}

Таким образом, вы не должны использовать параметры для своей функции, поскольку параметры теперь объявляются как атрибуты членов класса...

public double getValue() {
  return ( this.parameters[2] + x*(this.parameters[1] + x*this.parameters[0]));
}

Затем просто позвоните

parabolaInstance.getValue();

Ответ 6

Одно решение - делает все методы нестатическими с требованием, чтобы класс должен иметь конструктор по умолчанию. Затем вы можете легко создать экземпляр и вызвать методы, которые вам нужны.

Ответ 7

Что вы хотите сделать, это не нормально...

Вы хотите определить статические методы в интерфейсе я и иметь некоторые реализации A и B этого интерфейса с собственной реализацией этих статических методов, объявленных в интерфейсе I.

Представьте себе, как компьютер будет знать, что делать, если вы вызываете I.staticMethod()??? будет ли он использовать реализацию A или B?!!

Интерес к объявлению метода в интерфейсе заключается в использовании полиморфизма и возможности вызвать этот метод для разных реализаций объектов... Но для статических методов, поскольку вы не вызываете метод из экземпляра (на самом деле вы можете но на самом деле не нужен...), но с ClassName.xxxMethod, он абсолютно не интересуется...

Таким образом, вам не нужно ставить эти статические методы в интерфейсе... просто поместите их в обе реализации и вызовите их с помощью методов A.staticMethod() и B.staticMethod() (и они даже не нужны использовать одно и то же имя метода!)

Интересно, как вы хотите вызвать свой статический метод, вы пример кода для показа?

Ответ 8

@Sebastien: Почему нет интереса для обоих классов такое же имя статического метода? С помощью отражение это может быть единственным способом чтобы убедиться, что метод существует. я хотел бы getDescription() вернуться описание класса. Зачем если он изменится на разные случаи? Вот почему я хотел бы это метод должен быть статичным и при этом обеспечивать соблюдение интерфейс, как реализованы. - Тобиас Киенцлер 3

Как я уже сказал, объявляя метод static, вы можете вызывать его непосредственно из класса и не нуждаетесь в экземпляре класса. Поскольку нет смысла называть I.staticMethod() (как уже объяснялось), вы можете просто вызвать A.staticMethod1() и B.staticMethod2(), их имя не имеет значения, поскольку вы вызываете их из A или Класс B, известный во время компиляции!

Если вы хотите, чтобы getDescription возвращал одно и то же описание независимо от соответствующего экземпляра ParametricFunction, просто сделайте ParametricFunction абстрактным классом и реализуйте статические методы непосредственно в этом классе. Затем вы сможете вызвать A, я или B.getDescription(); (даже a, я или b...). Но он остается тем же, что и реализовать его в и B и называя его броском A или B...

Вызов статического метода из экземпляра не является хорошей практикой и не представляет интереса, поэтому вам следует называть A.meth() или B.meth(), а не a.meth() или b.meth()

Потому что я хотел, чтобы A и B что staticMethod наверняка и сделать убедитесь, что кто-то еще использует интерфейс для нового класса тоже это сделают. - Тобиас Киенцлер 5 часов назад

На самом деле "кто-то еще" будет нормально не вызывать a.meth() или b.meth(), поэтому, если он сделает класс C и хочет вызвать C.meth(), он никогда не сможет этого сделать, потому что C.meth() не реализована или не статична... поэтому он сделает это, или C.meth() никогда не был вызван, а затем также бессмысленно заставить разработчиков внедрять статические функции, которые никогда не будут использоваться...

Я не знаю, что я могу добавить...

Ответ 9

Конструктор в интерфейсе? э? Вы хотите иметь возможность называть интерфейс я = новый интерфейс (double [])? И компьютер в другой раз выберет себе реализацию? Это так же странно, как и статический интерфейс: D

Как вы сказали, проверка параметров должна быть выполнена до начала строительства... Но это не значит, что вы не можете создавать исключение при построении, если параметры не в порядке. Это просто безопасность, которую вы можете добавить, которая обеспечит согласованность построенного объекта. Но такой код не позволяет обойти предыдущую проверку: повышение исключений при построении скажет вам: "Эй, у вас есть ошибка!" в то время как не проверяя параметры, вы просто скажете: "кто-то, кто использует GUI, пытался установить плохую ценность, мы отправим ему сообщение об ошибке..."

Собственно, поскольку вам нужно проверить значения и объект даже не построен, почему вы абсолютно хотите добавить эту проверку на объект модели? Form/Gui/любая проверка может быть выполнена в любом месте, в классе Java проверки валидации... Просто установите статический (или не) метод в другом классе ParametricFunctionValidationHelper, где вы добавляете свой метод и реализацию проверки.

public static boolean validateParametricFunction(String functionType, double[] parameters) {
  if ( functionType.equals("bessel") ) return validateBessel(parameters);
  if ( functionType.equals("parabola") ) return validateParabola(parameters);
}

Не имеет значения, как представлен ваш functionType (я выбираю String, потому что я предполагаю, что вы получите его из пользовательского интерфейса, Интернета или gui... это могло быть Enum...

Вы даже можете проверить объект после его создания:

public static boolean validateParametricFunction(ParametricFunction pamFunc) {
  if ( pamFunc instanceOf BesselFunction ) return validateBessel(pamFunc.getParameters);
  ......
}

Вы даже можете поставить статические методы проверки в классы функций, а затем у вас будет:   public static boolean validateParametricFunction (ParametricFunction pamFunc) {     if (pamFunc instanceOf BesselFunction) возвращает BesselFunction.validateBessel(pamFunc.getParameters);     if (pamFunc instanceOf ParabolaFunction) возвращает ParabolaFunction.validateParabola(pamFunc.getParameters);   }

Да, вы не сможете установить статический метод в интерфейсе, но как бы вы назвали этот метод?

С кодом типа

public static boolean validateParametricFunction(ParametricFunction pamFunc) {
  return ParametricFunction.validate(pamFunc);
}

??? Это не имеет смысла, потому что JVM вообще не сможет узнать, какую реализацию статического метода использовать, поскольку вы не вызываете статический метод из экземпляра, а из класса! Это будет только смысл, если вы реализуете метод проверки непосредственно в классе ParametricFunction, но в любом случае, если вы это сделаете, вам нужно будет сделать то же самое, что я показал вам раньше с помощью instanceOf, потому что экземпляр pamFunc это единственный элемент, который вам нужно будет выбрать, какую проверку вы будете использовать...

Вот почему вам лучше использовать нестационарный метод и поместить его в интерфейс, например:

public static boolean validateParametricFunction(ParametricFunction pamFunc) {
  return pamFunc.validate();
}

Собственно, что вам нужно сделать: - Получить параметры (String?) Из графического интерфейса/веб-интерфейса/всего - Параметры Parse String в хорошем формате (String to int...) - Проверить эти параметры с помощью класса проверки (статический метод или нет) - Если нет подтверждения → распечатать сообщение пользователю - Элемент конструкции Else - Использовать объект

Я не вижу в любом случае необходимости статического метода в интерфейсе...