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


593

Вопрос в Java, почему я не могу определить абстрактный статический метод? например

abstract class foo {
    abstract void bar( ); // <-- this is ok
    abstract static void bar2(); //<-- this isn't why?
}

9
Несколько причин: статический метод должен иметь тело, даже если они являются частью абстрактного класса, потому что не нужно создавать экземпляр класса для доступа к его статическому методу. Еще один способ думать об этом: если на мгновение мы предполагаем, что это разрешено, то проблема заключается в том, что вызовы статических методов не предоставляют никакой информации о типе времени выполнения (RTTI), помните, что создание экземпляров не требуется, поэтому они не могут быть перенаправлены для их конкретных переопределенных реализаций и, таким образом, использование abstarct static не имеет никакого смысла. Другими словами, он не может обеспечить какую-либо пользу от полиморфизма, поэтому не допускается.
Sactiw

6
Если у вас есть что ответить на вопрос,
опубликуйте

Ответы:


568

Потому что «абстрактный» означает: «не реализует никакой функциональности», а «статический» означает: «есть функциональность, даже если у вас нет экземпляра объекта». И это логическое противоречие.


353
Более кратким ответом будет «плохой языковой дизайн». Статика должна означать «принадлежит классу», потому что именно так она используется интуитивно, как показывает этот самый вопрос. Смотрите "classmethod" в Python.
Александр Юнгберг

12
@ Томалак Я прошу прощения, мне было не ясно. Конечно, статический метод «принадлежит классу». Тем не менее, это только в том смысле, что он живет в том же пространстве имен. Статический метод не является методом самого объекта класса: он не работает с 'this' в качестве объекта класса и не участвует должным образом в цепочке наследования. Если бы это действительно был метод класса, abstract staticэто имело бы смысл. Это был бы метод самого объекта класса, который должны реализовывать объекты подкласса. Конечно, как обстоят дела, твой ответ верен, несмотря на мои разговоры о языке.
Александр Юнгберг

695
Это не логическое противоречие, это недостаток языка, многие другие языки поддерживают это понятие. «абстрактный» означает «реализованный в подклассах», «статический» означает «выполненный в классе, а не в экземплярах класса». Логического противоречия нет.
Эрик Грандж

10
@Eric: И все же то , что вы говорите, не относится к abstract static: функция X, которая «реализована в подклассе», не может одновременно «выполняться в классе» - только в подклассе . Где это тогда уже не абстрактно.
Томалак

72
@ Томакак: Ваша логика круговая. staticне означает «не пустой» - это просто следствие того, что Java не позволяет статическим методам быть абстрактными. Это означает «вызываемый в классе». (Это должно означать «вызываемый только в классе», но это другая проблема.) Если бы Java поддерживал abstract staticметоды, я ожидал бы, что это означает, что метод 1) должен быть реализован подклассами, а 2) является методом класса подкласса. Некоторые методы просто не имеют смысла как методы экземпляра. К сожалению, Java не позволяет вам указать это при создании абстрактного базового класса (или интерфейса).
Майкл Карман

326

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


25
Java полна странных ограничений. Замыкания, обращающиеся только к конечным переменным, - это другое. И оставшийся список практически бесконечен. Работа программиста на Java - знать их и их обходные пути. Чтобы повеселиться, мы должны использовать что-то лучше, чем Java, в свободное время. Но я бы не стал беспокоиться. Это семя для достижения прогресса.
ceving

22
Я считаю, что то, что вы называете «плохим языковым дизайном», на самом деле является скорее «защитным языковым дизайном», целью которого является ограничение нарушений принципа ОО, которые совершают программисты из-за ненужных языковых функций.
Этанфар

22
Является ли понятие «абстрактной статики» нарушением принципов ОО?
Тревор

7
@threed, Совсем нет, но, конечно, есть люди, которые говорят, что само понятие staticсебя уже является нарушением ....
Pacerier

4
Потребность в статическом явном подтверждении того, что «принципы ОО» не так всеобъемлющи, как обычно утверждается.
Бен

147

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


18
Да, действительно стыдно за то, что статические методы не могут быть переопределены в Java.
Мишель

12
@ Мишель: какой в ​​этом смысл? Если вы хотите поведение на основе экземпляра, используйте методы экземпляра.
Ран Бирон

8
Этот ответ неверен. Статические методы в абстрактных классах работают нормально и широко используются. Просто статические методы самого класса не могут быть абстрактными. @ Мишель не имеет смысла переопределять статический метод. Без экземпляра, как среда выполнения узнает, какой метод вызывать?
Эриксон

63
@erickson - даже без экземпляра иерархия классов не повреждена - наследование статических методов может работать так же, как наследование методов экземпляра. Smalltalk делает это, и это весьма полезно.
Джаред

8
@matiasg это вообще ничего нового. Абстрактным классам всегда разрешалось иметь статические неабстрактные методы.
Мэтт Болл

70

abstractАннотации к способу указывает на то, что этот метод должен быть переопределен в подклассе.

В Java staticэлемент (метод или поле) не может быть переопределен подклассами (это не обязательно верно в других объектно-ориентированных языках, см. SmallTalk.) Элемент staticможет быть скрыт , но это принципиально отличается от переопределенного .

Поскольку статические члены не могут быть переопределены в подклассе, abstractаннотация к ним не может быть применена.

Кроме того, другие языки поддерживают статическое наследование, как и наследование экземпляров. С точки зрения синтаксиса, эти языки обычно требуют, чтобы имя класса было включено в оператор. Например, в Java, если вы пишете код в ClassA, это эквивалентные операторы (если methodA () является статическим методом, и нет метода экземпляра с такой же сигнатурой):

ClassA.methodA();

а также

methodA();

В SmallTalk имя класса не является обязательным, поэтому синтаксис (обратите внимание, что SmallTalk не использует. Для разделения «субъекта» и «глагола», а вместо этого использует его в качестве терминатора исправления состояния):

ClassA methodA.

Поскольку имя класса всегда требуется, правильная «версия» метода всегда может быть определена путем обхода иерархии классов. Что бы это ни стоило, я иногда пропускаю staticнаследование, и меня укусило отсутствие статического наследования в Java, когда я впервые начал с ним. Кроме того, SmallTalk типизирован по типу утки (и поэтому не поддерживает программу по контракту.) Таким образом, он не имеет abstractмодификатора для членов класса.


1
«Статический член не может быть переопределен подклассами» неправильно. Это возможно, по крайней мере, в Java6. Не уверен с тех пор, когда это так.
Стивен Де Гроот

15
@Steven De Groote Статический член действительно не может быть переопределен подклассами. Если у подкласса есть статический метод с той же сигнатурой, что и у статического метода в суперклассе, он не переопределяет его, а скрывает. http://docs.oracle.com/javase/tutorial/java/IandI/override.html Разница в том, что полиморфизм работает только для переопределенных, но не для скрытых методов.
John29

2
@ John29 Спасибо за разъяснения, но, кроме различий в именах, они похожи в использовании.
Стивен Де Гроот

2
@ Steven De Groote Да, он похож на использование, но поведение отличается. Вот почему нет статических абстрактных методов - какой смысл в статических абстрактных методах, если они не поддерживают полиморфизм?
John29

3
@ Steven De Groote: Разница становится очевидной, когда у вас есть вызов этого метода в самом суперклассе. Предположим, Super.foo вызывает Super.bar. Если подкласс реализует Subclass.bar, а затем вызывает foo, то foo будет по-прежнему вызывать Super.bar, а не Subclass.bar. Следовательно, у вас есть два совершенно разных и не связанных между собой метода, которые называются «бар». Это не имеет преимуществ в любом полезном смысле.
Doradus

14

Я тоже задавал тот же вопрос, вот почему

Так как абстрактный класс говорит, он не даст реализацию и позволит подклассу давать его

поэтому подкласс должен переопределить методы суперкласса,

ПРАВИЛО № 1 - Статический метод не может быть переопределен

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

Таким образом, они не могут быть абстрактными.

Нет такой вещи, как абстрактная статика <--- Не допускается в Java Universe


5
-1, неверно, что «Java не позволяет переопределять статический метод, потому что статические члены и методы являются элементами времени компиляции». Статическая проверка типов определенно возможна с помощью abstract staticсм. Stackoverflow.com/questions/370962/… . Реальная причина , почему Java не позволяет статические методы быть переопределены в том , что Java не позволяет статические методы быть переопределены.
Pacerier

Перегрузка не имеет ничего общего с полиморфизмом. Перегрузка и переопределение не имеют ничего общего, кроме префикса «over», во многом так же, как в Java и JavaScript оба имеют «Java». Имя метода не в том, что его идентифицирует, а в его сигнатуре. это foo(String)не то же самое, foo(Integer)что и все.
Капитан Мэн

@CaptainMan Перегрузка буквально называется «параметрический полиморфизм», потому что, в зависимости от типа параметра, вызывается другой метод, который является полиморфизмом.
Давор

12

Это ужасный языковой дизайн и на самом деле нет причин, почему это невозможно.

На самом деле, здесь есть реализация того, как это МОЖЕТ быть сделано в JAVA :

public class Main {

        public static void main(String[] args) {
                // This is done once in your application, usually at startup
                Request.setRequest(new RequestImplementationOther());

                Request.doSomething();
        }

        public static final class RequestImplementationDefault extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something AAAAAA");
                }
        }

        public static final class RequestImplementaionOther extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something BBBBBB");
                }
        }

        // Static methods in here can be overriden
        public static abstract class Request {

                abstract void doSomethingImpl();

                // Static method
                public static void doSomething() {
                        getRequest().doSomethingImpl();
                }

                private static Request request;
                private static Request getRequest() {
                        // If setRequest is never called prior, it will default to a default implementation. Of course you could ignore that too. 
                        if ( request == null ) {
                                return request = new RequestImplementationDefault();
                        }
                        return request;
                }
                public static Request setRequest(Request r){
                        return request = r;
                }

        }
}

================= Старый пример ниже =================

Ищите getRequest, и можно вызвать getRequestImpl ... setInstance, чтобы изменить реализацию до вызова.

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author Mo. Joseph
 * @date 16 mar 2012
 **/

public abstract class Core {


    // ---------------------------------------------------------------        
    private static Core singleton; 
    private static Core getInstance() {
        if ( singleton == null )
            setInstance( new Core.CoreDefaultImpl() );  // See bottom for CoreDefaultImpl

        return singleton;
    }    

    public static void setInstance(Core core) {
        Core.singleton = core;
    }
    // ---------------------------------------------------------------        



    // Static public method
    public static HttpServletRequest getRequest() {      
        return getInstance().getRequestImpl();
    }


    // A new implementation would override this one and call setInstance above with that implementation instance
    protected abstract HttpServletRequest getRequestImpl();




    // ============================ CLASSES =================================

    // ======================================================================
    // == Two example implementations, to alter getRequest() call behaviour 
    // == getInstance() have to be called in all static methods for this to work
    // == static method getRequest is altered through implementation of getRequestImpl
    // ======================================================================

    /** Static inner class CoreDefaultImpl */
    public static class CoreDefaultImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }
    }

     /** Static inner class CoreTestImpl : Alternative implementation */
    public static class CoreTestImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return new MockedRequest();
        }
    }       

}

Используется следующим образом:

static {
     Core.setSingleton(new Core.CoreDefaultImpl());

     // Or

     Core.setSingleton(new Core.CoreTestImpl());

     // Later in the application you might use

     Core.getRequest(); 

}

6
Я не понял, где вы привели пример abstract staticметода, который был задан в вопросе, и вы написали жирным шрифтом МОЖНО СДЕЛАТЬ В ЯВА . Это полностью вводит в заблуждение.
Blip

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

Это пример расширения абстрактного класса, а затем помещения статических методов в дочерний класс. Это не пример того, что МОЖЕТ БЫТЬ СДЕЛАНО В JAVA, в любом случае.
Подводное Стив

2
@ScubaSteve Во-первых, вы ошибаетесь в своем заключении. Во-вторых, он достигает того же результата. Значение статического доступа к классу может быть изменено другой реализацией. Это не ответ на вопрос, что я сделал статическое ключевое слово абстрактным, но используя этот шаблон, вы можете использовать статические методы и при этом изменить их реализацию. Это имеет негативное влияние только глобальности, но для среды test / prod / dev это помогает нам.
ммм

5
  • Абстрактный метод определяется только для того, чтобы его можно было переопределить в подклассе. Однако статические методы не могут быть переопределены. Следовательно, ошибка времени компиляции - иметь абстрактный статический метод.

    Теперь следующий вопрос: почему статические методы нельзя переопределить?

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


4

Статический метод по определению не должен знать this. Таким образом, это не может быть виртуальный метод (который перегружен в соответствии с информацией динамического подкласса, доступной через this); вместо этого перегрузка статического метода основана исключительно на информации, доступной во время компиляции (это означает: как только вы ссылаетесь на статический метод суперкласса, вы вызываете именно метод суперкласса, но никогда не метод подкласса).

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


4

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

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

class C1 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C1
    }
}
class C2 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C2
    }
}

doWork()методы C1и C2идентичны. Может быть много таких calsses: C3 C4и т.д. Если бы это static abstractбыло разрешено, вы бы удалили дублирующийся код, выполнив что-то вроде:

abstract class C {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }

    static abstract void doMoreWork(int k);
}

class C1 extends C {
    private static void doMoreWork(int k) {
        // code for class C1
    }
}

class C2 extends C {
    private static void doMoreWork(int k) {
        // code for class C2
    }
}

но это не скомпилируется, потому что static abstractкомбинация не допускается. Однако это можно обойти с помощью static classконструкции, которая допускает:

abstract class C {
    void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    abstract void doMoreWork(int k);
}
class C1 {
    private static final C c = new  C(){  
        @Override void doMoreWork(int k) {
            System.out.println("code for C1");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}
class C2 {
    private static final C c = new C() {
        @Override void doMoreWork(int k) {
            System.out.println("code for C2");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}

С этим решением единственный дублирующийся код

    public static void doWork() {
        c.doWork();
    }

1
Поскольку в вашем конечном решении абстрактный класс C не имеет статических методов, то почему бы просто не позволить C1 и C2 расширить его и переопределить метод doMoreWork () и позволить любым другим классам создать свой экземпляр и вызвать требуемые методы. По сути, вы делаете то же самое, то есть расширяете класс C, используя анонимный класс, а затем в C1 и C2, используя его статический экземпляр, чтобы разрешить доступ из статического метода, но это совсем не требуется.
Sactiw

Я не понимаю контекст, который вы предоставили здесь. В вашем окончательном решении вы можете позвонить C1.doWork()или C2.doWork()Но вы не можете позвонить C.doWork(). Также в приведенном вами примере, который не сработает, предположим, если это было разрешено, то как класс Cнайдет реализацию doMoreWork()? Наконец, я бы назвал ваш контекстный код плохим дизайном. Почему? просто потому, что вы создали отдельную функцию для кода, который является уникальным, вместо того, чтобы создать функцию для кода, который является общим, и затем реализовать статическую функцию в классе C. Это проще !!!
Blip

2

Предположим, есть два класса, Parentи Child. Parentесть abstract. Заявления следующие:

abstract class Parent {
    abstract void run();
}

class Child extends Parent {
    void run() {}
}

Это означает, что любой экземпляр Parentдолжен указывать, как run()выполняется.

Однако предположим, что Parentэто не так abstract.

class Parent {
    static void run() {}
}

Это означает, что Parent.run()будет выполняться статический метод.

Определение abstractметода - «Метод, который объявлен, но не реализован», что означает, что он сам ничего не возвращает.

Определение staticметода: «Метод, который возвращает одно и то же значение для тех же параметров независимо от экземпляра, в котором он вызывается».

An abstractвозвращаемого значения метода будет меняться по мере изменения экземпляра. staticМетод не будет. static abstractМетод в значительной степени способ , при котором возвращаемое значение является постоянным, но не возвращает ничего. Это логическое противоречие.

Кроме того, для static abstractметода нет особой причины .


2

Абстрактный класс не может иметь статический метод, потому что абстракция выполняется для достижения ДИНАМИЧНОЙ СВЯЗИ, в то время как статические методы статически связаны с их функциональностью. Статический метод означает поведение, не зависящее от переменной экземпляра, поэтому экземпляр / объект не требуется. Просто класс. Статические методы принадлежат классу, а не объекту. Они хранятся в области памяти, известной как PERMGEN, откуда она используется для каждого объекта. Методы в абстрактном классе динамически связаны с их функциональностью.


1
Абстрактные классы, безусловно, могут иметь статические методы. Но не статичные абстрактные методы.
JacksOnF1re

2

Объявление метода как staticозначает, что мы можем вызвать этот метод по имени класса, и, если этот класс abstractтакже, нет смысла вызывать его, так как он не содержит никакого тела, и, следовательно, мы не можем объявить метод как staticи abstract.


2

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


1

Статический метод может быть вызван без экземпляра класса. В вашем примере вы можете вызвать foo.bar2 (), но не foo.bar (), потому что для bar вам нужен экземпляр. Следующий код будет работать:

foo var = new ImplementsFoo();
var.bar();

Если вы вызываете статический метод, он всегда будет выполняться с одним и тем же кодом. В приведенном выше примере, даже если вы переопределите bar2 в ImplementsFoo, вызов var.bar2 () выполнит foo.bar2 ().

Если bar2 теперь не имеет реализации (это означает абстрактное значение), вы можете вызвать метод без реализации. Это очень вредно.


1
И абстрактный статический метод может быть вызван без экземпляра, но для этого потребуется реализация в дочернем классе. Это не совсем полиморфизм, но единственный способ обойти это - заставить конкретного потомка реализовать интерфейс, который «требует» «абстрактный статический» метод. Грязный, но работоспособный.
Fijiaaron

3
на самом деле я был неправ. Вы не можете иметь статические методы в интерфейсе. Недостаток языка.
Fijiaaron

1

Я считаю, что нашел ответ на этот вопрос в форме того, почему методы интерфейса (которые работают как абстрактные методы в родительском классе) не могут быть статичными. Вот полный ответ (не мой)

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

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

abstract class Foo {
    abstract static void bar();
}

class Foo2 {
    @Override
    static void bar() {}
}

Тогда любой Foo.bar();вызов, очевидно, является незаконным, и вы всегда будете использовать Foo2.bar();.

Имея это в виду, единственная цель статического абстрактного метода состояла бы в том, чтобы заставить подклассы реализовать такой метод. Сначала вы можете подумать, что это ОЧЕНЬ неправильно, но если у вас есть параметр общего типа, <E extends MySuperClass>было бы неплохо гарантировать через интерфейс, который Eможет .doSomething(). Имейте в виду, что из-за стирания типов дженерики существуют только во время компиляции.

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

Почему бы не абстрактные / интерфейсные статические методы без реализации по умолчанию? По-видимому, просто из-за того, как Java определяет, какой блок кода он должен выполнить (первая часть моего ответа).


1

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

interface Demo 
{
  public static void main(String [] args) {
     System.out.println("I am from interface");
  }
}

0

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

Таким образом, вы можете создать, например, абстрактный класс sortableObject или даже интерфейс с (авто) абстрактными статическими методами, который определяет параметры опций сортировки:

public interface SortableObject {
    public [abstract] static String [] getSortableTypes();
    public String getSortableValueByType(String type);
}

Теперь вы можете определить сортируемый объект, который можно отсортировать по основным типам, которые одинаковы для всех этих объектов:

public class MyDataObject implements SortableObject {
    final static String [] SORT_TYPES = {
        "Name","Date of Birth"
    }
    static long newDataIndex = 0L ;

    String fullName ;
    String sortableDate ;
    long dataIndex = -1L ;
    public MyDataObject(String name, int year, int month, int day) {
        if(name == null || name.length() == 0) throw new IllegalArgumentException("Null/empty name not allowed.");
        if(!validateDate(year,month,day)) throw new IllegalArgumentException("Date parameters do not compose a legal date.");
        this.fullName = name ;
        this.sortableDate = MyUtils.createSortableDate(year,month,day);
        this.dataIndex = MyDataObject.newDataIndex++ ;
    }
    public String toString() {
        return ""+this.dataIndex+". "this.fullName+" ("+this.sortableDate+")";
    }

    // override SortableObject 
    public static String [] getSortableTypes() { return SORT_TYPES ; }
    public String getSortableValueByType(String type) {
        int index = MyUtils.getStringArrayIndex(SORT_TYPES, type);
        switch(index) {
             case 0: return this.name ;
             case 1: return this.sortableDate ;
        }
        return toString(); // in the order they were created when compared
    }
}

Теперь вы можете создать

public class SortableList<T extends SortableObject> 

который может извлекать типы, создавать всплывающее меню для выбора типа для сортировки и прибегать к списку, получая данные из этого типа, а также иметь функцию добавления, которая при выборе типа сортировки может автоматически -сортировать новые элементы в. Обратите внимание, что экземпляр SortableList может напрямую обращаться к статическому методу «T»:

String [] MenuItems = T.getSortableTypes();

Проблема с необходимостью использования экземпляра состоит в том, что в SortableList, возможно, еще нет элементов, но уже требуется обеспечить предпочтительную сортировку.

Привет, Олаф.


0

Во-первых, ключевой момент в отношении абстрактных классов - абстрактный класс не может быть создан (см. Вики ). Таким образом, вы не можете создать любой экземпляр абстрактного класса.

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

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

Boom.


Каждый метод в абстрактном классе нуждается в расширении в любом случае для выполнения, так что это не оправдание. Вы можете расширить абстрактный класс (одновременно реализуя абстрактный метод). Так что это не работает как объяснение.
Пере

0

Согласно документу Java :

Статический метод - это метод, связанный с классом, в котором он определен, а не с каким-либо объектом. Каждый экземпляр класса разделяет свои статические методы

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

Хороший пример этого:

list.sort(ordering);

вместо

Collections.sort(list, ordering);

Другой пример использования статических методов также приведен в самом документе :

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

0

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


Этот ответ не добавляет ничего, к чему предыдущие ответы еще не обращались.
MarsAtomic

@MarsAtomic Я думаю, что это более уместно, чем топ-проголосовавший ответ. Кроме того, это сжато.
Правин Кумар

Затем вы можете редактировать более ранние ответы, чтобы улучшить их, когда у вас будет достаточно повторений. Все, что вы делаете, это добавляете шум к сигналу, создавая дубликаты ответов. Пожалуйста, следуйте установленным правилам и обычаям Stack Overflow, а не создавайте свои собственные и ожидайте, что все остальные будут следовать.
MarsAtomic 30.09.15

Я не согласен, пожалуйста, сравните мой ответ с другим, особенно с ответом сверху.
Правин Кумар

"Почему я не могу сделать это?" Ответ: «потому что ты не можешь».
JacksOnF1re

0

Обычные методы могут быть абстрактными, если они должны быть переопределены подклассами и снабжены функциональностью. Представьте, что класс Fooрасширен и Bar1, Bar2, Bar3т. Д. Итак, у каждого будет своя версия абстрактного класса в соответствии со своими потребностями.

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


0

Потому что абстрактный - это ключевое слово, которое применяется к абстрактным методам, но не определяет тело. И если говорить о статическом ключевом слове, то оно относится к области классов.


пожалуйста, будьте немного точнее о своем ответе.
Blip

0

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


3
и почему это будет проблемой?
эйс

-1

Вы можете сделать это с помощью интерфейсов в Java 8.

Это официальная документация об этом:

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html


2
Как? Я искал решения и не мог их найти.
Тулиха

Wut? Тебе нельзя. Все методы статических интерфейсов должны вызываться с использованием класса интерфейса.
ммм

8
Этот ответ неверен и вводит в заблуждение людей, новичков в Java. Это сделано для того, чтобы показать любой пример абстрактного статического метода, поскольку он не может быть реализован и описан в других ответах
Blip

-1

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


Пожалуйста, используйте заглавные буквы и сделайте акцент на этом беспорядке.
маркиз Лорн
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.