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

В первую очередь, я считал полезный ответ erickson на, "Почему я не могу определить статический метод в интерфейсе Java?". Этот вопрос не о "почему", а о "как затем?".


Править: мой исходный пример был плохо изложен, но я оставлю его ниже.

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

Я возьму ParametricFunction пример снова. Теперь давайте возьмем сложную функцию, как Функции Бесселя, где справочная таблица является соответствующей. Это должно быть инициализировано, таким образом, эти две опции передают параметры непосредственно конструктору или обеспечивают a 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 позволяет только определенные параметры, например, положительные целые числа. Как проверить, что vailidity параметров передал конструктору? Бросок IllegalArgument- исключением была бы возможность, но a checkParametersValidity(double[] parameters) кажется намного более удобным. Но проверка параметров должна быть сделана перед конструкцией, таким образом, это должен быть статический метод. И это - то, где я действительно хотел бы знать способ удостовериться каждый класс, реализовывая ParametricFunction интерфейс действительно определяет этот статический метод.

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

(исходный пример)

Так в основном я хочу, чтобы один Интерфейс предоставил и обычные методы и например, a 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 c = (Class) ClassLoader.getSystemClassLoader().loadClass(fnName);
  Method m = c.getMethod("getValue", x, parameters);
  return ((double) m.invoke(null));
}

и вызов evaluate("Parabola", 1, new double[]{1,2,0});.

21
задан Community 23 May 2017 в 12:10
поделиться

9 ответов

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

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

17
ответ дан 29 November 2019 в 21:32
поделиться

То, что вы хотите сделать, не подходит ...

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

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

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

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

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

0
ответ дан 29 November 2019 в 21:32
поделиться

Причина в удобочитаемости: fit ("Parabola", xValues, fValues) vs. fit (Parabola.getInstance (), xValues, fValues) vs. fit (новая Парабола (), 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();
1
ответ дан 29 November 2019 в 21:32
поделиться

Почему бы не попробовать перечисление 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
}

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


РЕДАКТИРОВАТЬ для проблем с размером файла с помощью enum way.

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

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);
    }

}

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

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);
}
4
ответ дан 29 November 2019 в 21:32
поделиться

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

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

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

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

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

3
ответ дан 29 November 2019 в 21:32
поделиться

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

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

Если вы хотите, чтобы getDescription возвращал одно и то же описание независимо от экземпляра соответствующей ParametricFunction, просто сделайте ParametricFunction абстрактным классом и реализуйте статические методы непосредственно в этом классе. Тогда вы сможете вызвать A, I или B.getDescription (); (даже a, i или b ...). Но он остается таким же, как реализация его в A и 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 () никогда не будет вызван, и тогда также бессмысленно заставить разработчиков реализовать статические функции, которые никогда не будут использоваться ...

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

0
ответ дан 29 November 2019 в 21:32
поделиться

Ваш ответ на свой вопрос можно упростить дальше. Оставьте интерфейс ParametricFunction как есть и измените 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.

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

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

3
ответ дан 29 November 2019 в 21:32
поделиться

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

0
ответ дан 29 November 2019 в 21:32
поделиться

Конструктор в интерфейсе? Эм-м-м? Хотели бы вы иметь возможность вызывать интерфейс i = новый интерфейс (параметры double [])? А компьютер в другой раз сам выберет реализацию? Это так же странно, как и статика в интерфейсе: D

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

На самом деле, поскольку вам нужно проверить значения, а объект даже не построен, почему вы действительно хотите добавить эту проверку к объекту модели? java class ... Просто установите статический (или нет) метод в другом классе, называемом 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, потому что полагаю, вы получаете его из пользовательского интерфейса, Интернета или графического интерфейса ... это могло быть 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) return BesselFunction.validateBessel (pamFunc.getParameters); {{1} } if (pamFunc instanceOf ParabolaFunction) вернет ParabolaFunction.val idateParabola (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?) из графического интерфейса / веб-интерфейса / чего угодно - Разобрать параметры String в хорошем формате (String to int ...) - Проверьте эти параметры с помощью класса проверки (статический метод или нет) - Если нет проверки -> распечатать сообщение пользователю - Другой объект конструкции - Используйте объект

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

0
ответ дан 29 November 2019 в 21:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: