Краткий обзор Java статическое Обходное решение

Я понимаю, что ни абстрактный класс, ни интерфейс не могут содержать метод, который и абстрактен и статичен из-за проблем неоднозначности, но является там обходным решением?

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

РЕДАКТИРОВАНИЕ 1: контекст этой проблемы - то, что у меня есть набор классов, назовите их Палкой, Шаром и Toy на данный момент, которые имеют набор записей в базе данных. Я хочу создать суперкласс/интерфейс под названием Fetchable, который требует статического метода getFetchables() в каждом из классов ниже его. Причина методы в Палке, Шаре и Toy должны быть статическими, состоит в том, потому что они будут говорить с базой данных для получения всех записей в базе данных для каждого класса.

РЕДАКТИРОВАНИЕ 2: тем, кто говорит, Вы не можете сделать этого ни на каком языке, который не верен. Можно, конечно, сделать это в Ruby, где методы класса наследованы. Это не случай кого-то, не получая OO, это - случай недостающей функциональности на языке Java. Можно попытаться утверждать, что Вы никогда не должны должны быть наследоваться статичный (класс) методы, но это совершенно неправильно, и я проигнорирую любые ответы, которые делают такие точки.

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

12 ответов

У вас есть несколько вариантов:

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

  3. Как говорили другие, старайтесь не использовать статический метод.

7
ответ дан 29 November 2019 в 00:22
поделиться

Нет смысла делать то, о чем вы спрашиваете:

Почему статические методы не могут быть абстрактными в Java

-2
ответ дан 29 November 2019 в 00:22
поделиться

Я бы создал класс WidgetCollection с абстрактным внутренним классом Widget.

Вы можете расширить класс WidgetCollection.Widget для каждого из ваших типов Widget.

Никаких статических методов не требуется .

Пример (не скомпилирован и не протестирован):

class WidgetCollection<W extends Widget> {
    Set<W> widgets = new HashSet<W>();

    Set<W> getAll() {
        return widgets;
    }

    abstract class Widget {

       Widget() {
           widgets.add(this);
       }

       abstract String getName();
    }

    public static void main(String[] args) {
         WidgetCollection<AWidget> aWidgets = new WidgetCollection<AWidget>();
         a.new AWidget();

         Set<AWidget> widgets = aWidgets.getAll();
    }
}

class AWidget extends Widget {
    String getName() {
        return "AWidget";
    }
}
-1
ответ дан 29 November 2019 в 00:22
поделиться

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

В абстрактном суперклассе у меня будет статический метод getAllWidgets (тип класса). В нем я проверю класс, который вы ему передали, и на основе этого сделаю правильную выборку. Обычно мне нравится избегать передачи классов и использования переключателей в подобных вещах, но я сделаю здесь исключение.

-1
ответ дан 29 November 2019 в 00:22
поделиться

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

abstract class A
{
    public static void foo()
    {
        java.lang.System.out.println("A::foo");
    }

    public void bar()
    {

        java.lang.System.out.println("A::bar");
    }
}

class B extends A
{
    public static void foo()
    {
        java.lang.System.out.println("B::foo");
    }

    public void bar()
    {

        java.lang.System.out.println("B::bar");
    }
}

public class Main
{
    public static void main(String[] args)
    {
        B b = new B();
        b.foo();
        b.bar();

        A a = b;
        a.foo();
        a.bar();
    }
}
0
ответ дан 29 November 2019 в 00:22
поделиться

Нет. Вы не можете этого сделать. Если вы готовы пойти на компромисс и сделать метод нестатическим или предоставить реализацию статического метода в своем абстрактном классе, вы сможете закодировать это на Java.

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

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

Передайте экземпляры реализации объекта контекста.

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

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

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

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

Я все равно предоставлю запутанный способ выразить ваше ограничение, но НЕ ДЕЛАЙТЕ ЭТОГО. люди действительно увлекаются тем, чтобы сделать все проверяемым во время компиляции, за счет того, что код становится нечитаемым.

interface WidgetEnumerator
{
    List getAllWidgets();
}

public class Abs<T extends WidgetEnumerator>
{
    static List getAllWidgets(Class<? extends Abs> clazz){ ... }
}

public class Sub extends Abs<SubWidgetEnumerator>
{
}

public class SubWidgetEnumerator implements WidgetEnumerator
{
    public List getAllWidgets() { ... }
}

Как это работает: для любого подкласса Abs он вынужден предоставлять реализацию WidgetEnumerator. автор подкласса не может забыть об этом. Теперь вызов Abs.getAllWidgets (Sub.class) содержит достаточно информации для разрешения этой реализации, то есть SubWidgetEnumerator . Это делается посредством отражения, но безопасно по типу, строковые литералы не используются.

class) содержит информацию, достаточную для разрешения этой реализации, например SubWidgetEnumerator . Это делается посредством отражения, но безопасно по типу, строковые литералы не используются.

class) содержит информацию, достаточную для разрешения этой реализации, например SubWidgetEnumerator . Это делается посредством отражения, но безопасно по типу, строковые литералы не используются.

1
ответ дан 29 November 2019 в 00:22
поделиться

Статические методы относятся ко всему классу объекта, а не к отдельным экземплярам. Разрешение переопределения статического метода нарушает это изречение.

Первое, что я хотел бы рассмотреть, - это доступ к вашей базе данных из нестатического контекста. На самом деле это норма для приложений Java.

Если вам абсолютно необходимо использовать статический метод, то параметризуйте его с помощью аргументов, специфичных для экземпляра (универсального типа), чтобы позволить различным подклассам взаимодействовать с ним. Затем вызовите этот единственный статический метод из своих полиморфных методов.

2
ответ дан 29 November 2019 в 00:22
поделиться

Есть ли способ сделать это в Java?

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

1
ответ дан 29 November 2019 в 00:22
поделиться

Есть много ответов о том, что «это не имеет смысла ...», но на самом деле я столкнулся с подобной проблемой буквально вчера.

Я хотел использовать наследование в своих модульных тестах. У меня есть API и несколько его реализаций. Так что мне нужен только один набор модульных тестов для всех реализаций, но с разными статическими методами setUp.

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

6
ответ дан 29 November 2019 в 00:22
поделиться

I think I can give you a better answer after seeing your edits--your best bet is probably a factory pattern. (Not lovely, but better than singleton).

abstract class Widget
    public static Widget[] getAllWidgetsOfType(Class widgetType) {
        if(widgetType instanceof ...)
    }
class Ball extends Widget
class Stick extends Widget
class Toy extends Widget

This is not a very good way to do it, but it's typical. Hibernate is the tool you would normally use to solve this problem, this is exactly what it's designed for.

The big problem is that it requires editing the base class whenever you add a new class of a given type. This can't be gotten around without reflection. If you want to use reflection, then you can implement it this way (Psuedocode, I'm not going to look up the exact syntax for the reflection, but it's not much more complex than this):

public static Widget[] getAllWidgetsOfType(Class widgetType) {
    Method staticMethod=widgetType.getStaticMethod("getAllInstances");
    return staticMethod.invoke();
}

This would give the solution you were asking for (to be bothered by the need to modify the base class each time you add a child class is a good instinct).

You could also make it an instance method instead of a static. It's not necessary, but you could then prototype the method (abstract) in Widget.

Again, all this is unnecessary and sloppy compared to Hibernate...

Edit: If you passed in a live "Empty" instance of a ball, stick or toy instead of it's "Class" object, you could then just call an inherited method and not use reflection at all. This would also work but you have to expand the definition of a Widget to include an "Empty" instance used as a key.

1
ответ дан 29 November 2019 в 00:22
поделиться
Другие вопросы по тегам:

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