Чому статичні методи не можуть бути абстрактними на Java?


592

Питання в Java, чому я не можу визначити абстрактний статичний метод? наприклад

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

9
Мало причин: статичний метод повинен мати тіло, навіть якщо вони є частиною абстрактного класу, оскільки не потрібно створювати екземпляр класу для доступу до його статичного методу. Ще один спосіб подумати над цим, якщо на мить ми припустимо, що це дозволено, проблема полягає в тому, що виклики статичних методів не надають будь-якої інформації про тип часу виконання (RTTI), пам’ятайте, що створення екземпляра не потрібно, тому вони не можуть бути перенаправлені до їх конкретних переосмислених реалізацій і, таким чином, дозволяючи abstarct статики взагалі не має сенсу. Іншими словами, це не могло забезпечити будь-яку користь від поліморфізму, таким чином, не дозволяється.
сатрій

6
Якщо у вас є щось, щоб відповісти на питання, опублікуйте це як відповідь , а не коментар
Соломон Учко

Відповіді:


569

Оскільки "абстрактний" означає: "Не реалізує ніякої функціональності", а "статичний" означає: "Є функціональність, навіть якщо у вас немає екземпляра об'єкта". І це логічне протиріччя.


353
Більш лаконічною відповіддю буде «поганий дизайн мови». Статичний має означати "належить до класу", тому що саме так воно використовується інтуїтивно, як це показує саме це питання. Дивіться "класний метод" в Python.
Олександр Люнгберг

12
@Tomalak Вибачаюсь, мені не було зрозуміло. Звичайно статичний метод "належить до класу". І все-таки лише в тому сенсі він живе в одному просторі імен. Статичний метод не є самим методом об’єкта класу: він не оперує "цим" як об'єктом класу, і він не бере належної участі у ланцюжку успадкування. Якби це справді був класний метод, abstract staticмав би ідеальний сенс. Це був би сам метод об’єкта класу, який повинні реалізувати об'єкти підкласу. Звичайно, те, на що стоїть ваша відповідь, є правильним, незважаючи на те, що я захоплююсь мовою.
Олександр Люнгберг

693
Це не логічне протиріччя, це недоліки в мові, багато інших мов підтримують це поняття. "абстрактне" середнє ", реалізоване в підкласах", "статичне" означає "виконане на класі, а не екземпляри класу" Немає логічного суперечності.
Ерік Грандж

10
@Eric: І все-таки те, що ви говорите, не стосується abstract static: Функція X, що "реалізована в підкласі", не може бути "виконана в класі" - лише на підкласі . Де це тоді вже не абстрактно.
Томалак

72
@Tomakak: Ваша логіка кругла. staticне означає "не порожньо" - це лише наслідок того, що Java не дозволяє статичним методам бути абстрактними. Це означає "дзвонить на заняття". (Це повинно означати "дзвонити тільки для класу", але це інша проблема.) Якщо abstract staticметоди, які підтримують Java, я б очікував, що це означає, що метод 1) повинен бути реалізований підкласами, а 2) - метод класу підкласу. Деякі методи просто не мають сенсу як методи екземпляра. На жаль, Java не дозволяє вказати це при створенні абстрактного базового класу (або інтерфейсу).
Майкл Карман

326

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


25
Ява сповнена дивних обмежень. Закриття, що має доступ лише до остаточних змінних, - це ще одна. А список, що залишився, майже нескінченний. Завдання Java-програміста - знати їх та їх обхідні шляхи. Для того, щоб розважитися, ми повинні у вільний час використовувати щось краще, ніж Java. Але я б не переймався. Це насіння для досягнення прогресу.
квітня 12

22
Я вважаю, що те, що ви називаєте "поганим дизайном мови", насправді більше "дизайн захисної мови", метою якого є обмеження порушень принципу ОО, які роблять програмісти через непотрібні мовні особливості.
етанфар

22
Чи поняття "абстрактна статична" є порушенням принципів ОО?
Тревор

7
@threed, зовсім не так, але, звичайно, є люди, які говорять, що сама концепція staticсама по собі є вже порушенням ....
Pacerier

4
Необхідність статики - це наочна демонстрація того, що "принципи ОО" не такі всеохоплюючі, як зазвичай заявлено.
Бен

147

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


18
Так, це справді прикро тим, що статичні методи не можна перемогти на Java.
Мішель

12
@Michel: який би був сенс? Якщо ви хочете поведінку, засновану на екземплярі, використовуйте методи екземпляра.
Ран Бірон

8
Ця відповідь невірна. Статичні методи в абстрактних класах працюють чудово і широко застосовуються. Просто статичні методи самого класу можуть бути не абстрактними. @Michel не має сенсу переставляти статичний метод. Без примірника, як би час виконання часу знав, до якого методу слід звертатися?
erickson

63
@erickson - Навіть без екземпляра ієрархія класів є неушкодженою - успадкування статичних методів може працювати так само, як і успадкування методів екземплярів. Smalltalk це робить, і це досить корисно.
Джаред

8
@matiasg це взагалі нічого нового. Абстрактним заняттям завжди дозволялося мати статичні, не абстрактні методи.
Метт Бал

70

The abstractАнотації до способу вказує на те, що цей метод повинен бути перевизначений в підкласі.

У Java staticчлен (метод або поле) не може бути замінений підкласами (це не обов'язково вірно в інших об'єктно-орієнтованих мовах, див. SmallTalk.) staticЧлен може бути прихованим , але це принципово відрізняється від переосмисленого .

Оскільки статичні члени не можуть бути замінені в підкласі, то abstract анотація не може бути застосована до них.

Як осторонь - інші мови підтримують статичне успадкування, подібно до спадкування екземплярів. З точки зору синтаксису, ці мови, як правило, вимагають, щоб ім’я класу було включено до виписки. Наприклад, у Java, якщо припустити, що ви пишете код у ClassA, це еквівалентні висловлювання (якщо methodA () є статичним методом, і немає методу екземпляра з однаковою підписом):

ClassA.methodA();

і

methodA();

У SmallTalk назва класу не є обов'язковою, тому синтаксис є (зауважте, що SmallTalk не використовує.

ClassA methodA.

Оскільки назва класу завжди потрібна, правильну "версію" методу завжди можна визначити шляхом проходження ієрархії класів. Що я того вартий, я час від часу пропускаю staticспадщину, і мене вкусила відсутність статичного успадкування на Яві, коли я вперше розпочав його. Крім того, 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. Отже, у вас насправді є два абсолютно різних і не пов'язаних між собою методи, які називаються "бар". Це не переважає в жодному корисному сенсі.
Дорадус

14

Я теж задав те саме питання, ось чому

Оскільки клас Анотація каже, він не дасть імплементації та дозволить йому надавати підклас

тому підклас повинен перекрити методи суперкласу,

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

Оскільки статичні члени та методи є елементами компіляції часу, тому дозволено перевантажувати (Поліморфізм часу компіляції) статичними методами, а не переосмислювати (поліморфізм під час виконання)

Отже, вони не можуть бути абстрактними.

У Всесвіті Java немає такої речі, як абстрактна статична <--- Не дозволено


5
-1, Неправда, що "Java не дозволяє перекрити статичний метод, оскільки статичні члени та методи - це компільовані елементи часу". Статичний тип перевірка, безумовно , можливо з abstract staticSEE 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методу, про який ви питаєте у запитанні, і ви написали жирним шрифтом МОЖНА ЗРОБИТИсь в JAVA . Це зовсім неправильно.
Бліп

1
Вона сама по собі не дозволяє визначити її як абстрактну статичну, але ви можете досягти аналогічного результату, завдяки якому ви можете змінити реалізацію статичного методу s, використовуючи цей шаблон / хак. Це навряд чи помилково. Це можна зробити, але з використанням різної семантики.
ммм

Це приклад розширення абстрактного класу, а потім введення статичних методів у дитини. Це не приклад МОЖНО ЗРОБИТИ В ЯВУ, в будь-якому разі.
Скуба Стів

2
@ScubaSteve По-перше, ви помиляєтесь у своєму висновку. По-друге, вона досягає того ж результату. Значення статичного доступу до класу може бути змінено іншою реалізацією. Це не відповідь, щоб сказати, що я зробив статичне ключове слово непридатним, але, використовуючи цю схему, ви можете використовувати статичні методи і все ж змінити їх реалізацію. Це має негативний вплив на те, що він є лише глобальним, але для тестового / 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є ідентичними. Таких випадків може бути багато: 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, використовуючи його статичний екземпляр, щоб дозволити доступ зсередини статичного методу, але це зовсім не потрібно.
сатрій

Я не розумію контексту, який ви тут надали. У своєму остаточному рішенні ви можете зробити дзвінок C1.doWork()або C2.doWork()ви не можете зателефонувати C.doWork(). Також у наведеному вами прикладі, який не працюватиме, припустимо, якщо це було дозволено, то як клас Cзнайде реалізацію doMoreWork()? Нарешті я назвав би ваш контекстний код поганим дизайном. Чому? просто тому, що ви створили окрему функцію для коду, який є унікальним замість того, щоб створити функцію для коду, яка є загальною, а потім реалізувати статичну функцію в класі C. Це простіше !!!
Бліп

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 методу - це "метод, який оголошується, але не реалізується", це означає, що він сам нічого не повертає.

Визначення a static методу - це "метод, який повертає те саме значення для тих же параметрів, незалежно від екземпляра, на який він викликається".

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

Також причин для static abstractметоду насправді не так вже й багато .


2

Абстрактний клас не може мати статичний метод, оскільки абстрагування робиться для досягнення ДИНАМІЧНОГО ОБ'ЄДНАННЯ, а статичні методи статично прив'язані до їх функціональності. Статичний метод означає поведінку, не залежну від змінної екземпляра, тому жоден екземпляр / об'єкт не потрібен. Просто клас. Статичні методи належать до класу, а не до об'єкта. Вони зберігаються в області пам'яті, відомої як PERMGEN, звідки вона спільна з кожним об'єктом. Методи в абстрактному класі динамічно прив’язані до їх функціональності.


1
Абстрактні заняття, безумовно, можуть мати статичні методи. Але не статичні абстрактні методи.
JacksOnF1re

2

Декларуючи метод як staticзасіб, ми можемо назвати цей метод за назвою його класу, і якщо цей клас є abstract, немає сенсу називати його, оскільки він не містить жодного тіла, і, отже, ми не можемо оголосити метод як staticі abstract.


2

Оскільки абстрактні методи належать до класу і їх не можна перекрити класом, що реалізує. Навіть якщо є статичний метод з однаковою підписом, він приховує метод, не перекриває його. Тож неважливо оголосити абстрактний метод статичним, оскільки він ніколи не отримає тіло. Отже, складіть помилку часу.


1

Статичний метод можна викликати без екземпляра класу. У вашому прикладі ви можете зателефонувати foo.bar2 (), але не foo.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 ....
Тепер справа в тому, що ми можемо оголосити статичні повні методи в інтерфейсі, і ми можемо виконати інтерфейс, оголосивши основний метод всередині інтерфейсу.

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

По-перше, ключовий момент щодо абстрактних класів - абстрактний клас неможливо встановити (див. Вікі ). Отже, ви не можете створити жодного примірника абстрактного класу.

Тепер спосіб ява поводиться зі статичними методами - це обмін методом з усіма примірниками цього класу.

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

Бум.


Кожен метод в абстрактному класі потребує розширення його класу, щоб його виконати, так що це не привід. Ви можете розширити абстрактний клас (одночасно реалізуючи абстрактний метод). Тому це не працює як пояснення.
Пере

0

Відповідно до документа Java :

Статичний метод - це метод, який асоціюється з класом, у якому він визначений, а не з будь-яким об'єктом. Кожен екземпляр класу поділяє свої статичні методи

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

Гарний приклад цього:

list.sort(ordering);

замість

Collections.sort(list, ordering);

Ще один приклад використання статичних методів також наведений у самому doc :

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 Я вважаю, що це більше, ніж відповідь, яка проголосувала вгорі. Також він є лаконічним.
Praveen Kumar

Тоді ви можете редагувати попередні відповіді, щоб вдосконалити їх, коли у вас є достатня кількість представників. Все, що ви робите, - це додавати шум до сигналу, створюючи повторювані відповіді. Будь ласка, дотримуйтесь встановлених правил та звичаїв Stack Overflow, а не створюйте свої власні та очікуйте, що всі інші дотримуватимуться.
MarsAtomic

Я не погоджуюсь, будь ласка, порівняйте мою відповідь з іншими, особливо голосовою відповіддю.
Praveen Kumar

"Чому я не можу цього зробити?" Відповідь: "тому що ти не можеш".
JacksOnF1re

0

Регулярні методи можуть бути абстрактними, коли вони мають бути замінені підкласами та забезпечені функціональністю. Уявіть собі класFoo подовжений і Bar1, Bar2, Bar3т. Д. Отже, кожен матиме свою версію абстрактного класу відповідно до своїх потреб.

Тепер статичні методи за визначенням належать до класу, вони не мають нічого спільного з об'єктами класу або об'єктами його підкласів. Їм навіть не потрібно, щоб вони існували, вони можуть бути використані без інстанції класів. Отже, вони повинні бути готовими до роботи і не можуть залежати від підкласів, щоб додати їм функціональність.


0

Оскільки абстракт - це ключове слово, яке застосовується над абстрактними методами, не визначають тіло. А якщо говорити про статичне ключове слово, воно належить до області класу.


будь-ласка, будьте трохи докладніше щодо вашої відповіді.
Бліп

0

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


3
і чому це було б проблемою?
eis

-1

Це можна зробити за допомогою інтерфейсів на Java 8.

Це офіційна документація про це:

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


2
Як? Я шукав рішення і не зміг знайти жодного.
Теліха

Вут? Ви не можете. Усі методи статичних інтерфейсів повинні використовуватися за допомогою класу інтерфейсів.
ммм

8
Ця відповідь є неправильною і хибно орієнтується на людей, що з’являються у Java. Це показує будь-який приклад абстрактного статичного методу, оскільки його неможливо реалізувати та заявити в інших відповідях
Blip

-1

Тому що, якщо клас поширює абстрактний клас, то він повинен перекривати абстрактні методи, і це обов'язково. А оскільки статичні методи - це класові методи, вирішені під час компіляції, тоді як перекриті методи - це методи екземпляра, вирішені під час виконання та наступні динамічний поліморфізм.


Будь ласка, використовуйте великі букви та розділіть їх.
Маркіз Лорнський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.