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

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

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

person hhafez    schedule 16.12.2008    source источник
comment
Несколько причин: статический метод должен иметь тело, даже если они являются частью абстрактного класса, потому что не нужно создавать экземпляр класса для доступа к его статическому методу. Другой способ подумать об этом: если на мгновение мы предположим, что это разрешено, проблема в том, что вызовы статических методов не предоставляют никакой информации о типе времени выполнения (RTTI), помните, что создание экземпляра не требуется, поэтому они не могут перенаправляться к их конкретным переопределенным реализациям, и, таким образом, разрешение abstarct static вообще не имеет смысла. Другими словами, он не мог обеспечить никакого преимущества полиморфизма, поэтому недопустим.   -  person sactiw    schedule 10.11.2016


Ответы (26)


Аннотация abstract к методу указывает, что метод ДОЛЖЕН быть переопределен в подклассе.

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

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

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

ClassA.methodA();

а также

methodA();

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

ClassA methodA.

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

person Jared    schedule 16.12.2008
comment
Статический член не может быть переопределен подклассами неверно. Возможно, по крайней мере, на Java6. Не уверен, с каких это пор. - person Steven De Groote; 05.07.2012
comment
@Steven De Groote. Статический член действительно не может быть переопределен подклассами. Если у подкласса есть статический метод с той же сигнатурой, что и у статического метода в суперклассе, он не отменяет его, а скрывает. http://docs.oracle.com/javase/tutorial/java/IandI/override.html Разница в том, что полиморфизм работает только для переопределенных методов, но не для скрытых методов. - person John29; 07.12.2013
comment
@ John29 Спасибо за разъяснения, но, не считая разницы в именах, они похожи в использовании. - person Steven De Groote; 09.12.2013
comment
@Steven De Groote: Да, он похож на использование, но поведение другое. Вот почему нет статических абстрактных методов - какой смысл в статических абстрактных методах, если они не поддерживают полиморфизм? - person John29; 10.12.2013
comment
@ Стивен Де Гроот: разница становится очевидной, когда вы вызываете этот метод в самом суперклассе. Предположим, Super.foo вызывает Super.bar. Если подкласс реализует Subclass.bar, а затем вызывает foo, тогда foo по-прежнему будет вызывать Super.bar, а не Subclass.bar. Следовательно, на самом деле у вас есть два совершенно разных и не связанных между собой метода, оба называются bar. В каком-либо полезном смысле это не отменяет. - person Doradus; 02.09.2014

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

person Tomalak    schedule 16.12.2008
comment
Более лаконичный ответ - «ненормативная лексика». Статический должен означать «принадлежит классу», потому что именно так он используется интуитивно, как демонстрирует сам этот вопрос. См. Метод классов в Python. - person Alexander Ljungberg; 15.05.2010
comment
@Alexander: Это вопрос не о static, а о abstract static. Статический означает также принадлежность к классу в Java. - person Tomalak; 15.05.2010
comment
@Tomalak Прошу прощения, я не понял. Конечно, статический метод «принадлежит классу». Тем не менее, это только в том смысле, что он живет в том же пространстве имен. Статический метод не является методом самого объекта класса: он не работает с this в качестве объекта класса и не участвует должным образом в цепочке наследования. Если бы это действительно был классовый метод, abstract static имел бы смысл. Это был бы метод самого объекта класса, который должны реализовывать объекты подкласса. Конечно, ваш ответ верен, несмотря на то, что я скептически отношусь к языку. - person Alexander Ljungberg; 16.05.2010
comment
Это не логическое противоречие, это языковой недостаток, многие другие языки поддерживают это понятие. абстрактное означает реализованное в подклассах, статическое означает выполнение в классе, а не в экземплярах класса. Нет логического противоречия. - person Eric Grange; 08.06.2010
comment
@Eric: И тем не менее, то, что вы говорите, не относится к abstract static: функция X, которая реализована в подклассе не может одновременно выполняться в классе - только в подклассе. Где это уже не абстрактно. - person Tomalak; 08.06.2010
comment
Я согласен с @Eric. Чтобы возникло логическое противоречие, логика должна исходить из-за пределов правил java. Возможно, правда, что в java static означает функциональность, даже без экземпляра объекта, но это не противоречит abstract, за исключением конструкции языка. int означает «одно целое число», а [] означает «массив», но тот факт, что Java знает, что я хочу от int[], не означает, что это противоречит самим себе, а скорее то, что авторы Java решили разрешить определенную функциональность, связанную с особый порядок грамматики. - person plowman; 26.01.2011
comment
@uncheck: я понимаю, что две вещи (абстрактная и статическая) независимы, даже ортогональны. Тем не менее, метод, объявленный как оба, не имеет большого смысла. Либо он абстрактный (т. Е. пустой и должен быть реализован в дочернем классе), либо он статический (т. Е. не пустой и вызывается в самом классе). Может быть, вы могли бы объяснить мне, как логически это может быть и то, и другое одновременно. - person Tomalak; 26.01.2011
comment
@Tomakak: Ваша логика круговая. static не означает не пустой - это просто следствие того, что Java не позволяет статическим методам быть абстрактными. Это означает возможность вызова в классе. (Это должно означать вызываемый только в классе, но это другая проблема.) Если Java поддерживает abstract static методы, я ожидал бы, что это будет означать, что метод 1) должен быть реализован подклассами, а 2) является class метод подкласса. Некоторые методы просто не имеют смысла как методы экземпляра. К сожалению, Java не позволяет указать это при создании абстрактного базового класса (или интерфейса). - person Michael Carman; 30.03.2011
comment
@Tomalak явная проблема, с которой я сейчас сталкиваюсь, - это когда вам нужно знать класс дочернего объекта в унаследованном конструкторе (глубокая иерархия исключений): поскольку это информация, принадлежащая классу, вы должны сделать этот метод static, но поскольку вы не можете наследовать статические методы, вам нужно будет каким-то образом сделать его абстрактным; вы можете использовать нестатический метод, но проблема в том, что нестатические методы не могут быть вызваны в конструкторе; поэтому вы просто не можете узнать тип вашего экземпляра объекта в унаследованном конструкторе, если вы не укажете его в качестве аргумента! Это просто глупо. - person Léo Germond; 07.04.2011
comment
Я согласен с Александром, но один из способов сделать это - определить статический метод, чтобы он вызывал реализацию одноэлементного экземпляра того же класса. Затем этот метод может быть переопределен путем обмена синглтоном с другой реализацией подкласса ... - person mmm; 19.03.2012
comment
Как и многие вещи в Java, переход с другого языка кажется ограничением, но позже вы понимаете, что этого делать в любом случае не стоит. Например, в комментарии Лео, если вам нужно знать дочерний класс в унаследованном конструкторе, это вопиющее нарушение основных принципов ООП. Кроме того, как вы предлагаете вызывать такой метод? Чтобы вызвать статический метод, вам нужно имя класса. Используя имя базового класса, как узнать, какой подкласс вы намереваетесь? Тем не менее, если вы знаете подкласс, он не обязательно должен быть абстрактным. Покажите синтаксис, как это вообще будет работать. - person Chad N B; 28.08.2013
comment
Если бы даже был способ вызвать его, как бы вы узнали, реализован ли абстрактный метод? Класс должен реализовать все абстрактные методы, прежде чем он сможет быть создан, но для статического метода вы НЕ создаете экземпляр класса. Итак, как вы вообще узнаете, действительно ли это действительный звонок? В Delphi, например, вы можете создавать статические абстрактные методы, но вы также можете получать исключения во время выполнения, когда вы вызываете такой метод. Я всегда предпочитаю ошибку времени компиляции ошибке времени выполнения. Как я уже сказал, это кажется ограничением, исходящим от другого языка, но Java пытается помочь вам с хорошим дизайном. - person Chad N B; 28.08.2013
comment
Тогда почему в документации указано: абстрактный класс может иметь статические поля и статический метод, а здесь его не может быть? - person meso_2600; 13.11.2013
comment
Такие функции, как абстрактные статические методы, имеют тенденцию приводить к плохому дизайну. Вся цель абстрактного метода состоит в том, чтобы разрешить такие шаблоны, как фабрика методов, метод шаблона и т. Д. Это хорошие шаблоны проектирования при правильном использовании, и они доступны благодаря качеству полиморфизма ОО-языков. С другой стороны, абстрактный статический метод не имеет иной силы, кроме как заставить подклассы реализовывать что-то, что является явным нарушением нескольких принципов объектно-ориентированного проектирования (например, OCP). - person ethanfar; 25.03.2014
comment
Мне это кажется плохой «особенностью». Я все еще мог бы создать подкласс класса и пожелать переопределить статические методы этого класса. Этот способ вынуждает меня создать экземпляр класса только для того, чтобы переопределить методы, которые в противном случае могли бы быть объявлены статическими, если эти методы не изменяются и не используют состояние экземпляра. - person josiah; 06.05.2014
comment
-1, нужно больше голосов против. static не означает, что функциональность существует без экземпляра объекта. static означает, что функциональность может существовать без экземпляра объекта. В случае, когда это одновременно static и abstract, функциональность не будет существовать в родительском классе, но будет реализована в его подклассе. - person Pacerier; 10.09.2014
comment
@ChadNB, Как и многие вещи в Java, исход из Java кажется правильным, но позже вы понимаете, что это просто произвольное ограничение языка. Абстрактная статика может существовать в строго типизированных языках, таких как Java, она не создает исключения во время выполнения ............... - person Pacerier; 10.09.2014
comment
................. Рассмотрим статический абстрактный метод T1 Parent.F1(T2 x) Когда мы назовем его реализацией подкласса T1 Child.F1(T2 x), не будет исключений во время выполнения, так почему вы говорите, что у нас будут исключения во время выполнения? Кроме того, весь смысл абстрактного метода в том, что вам не нужно знать, реализован он или нет. Класс подкласса будет реализовывать это, а подкласс будет гарантировать, что контракт Лискова T1 Parent.F1(T2 x) сохраняется. Если подкласса нет, в любом случае не о чем беспокоиться, поскольку абстрактный метод может быть вызван только для подкласса. - person Pacerier; 10.09.2014
comment
Когда-то у меня был класс A с методом static main(String[] args) и класс B с static main(String[] args) throws Exception. И это привело к ошибке компилятора: не удалось переопределить метод. - person MC Emperor; 30.09.2014
comment
@Pacerier Подумайте об этом. Как вы это называете? Три способа: (1) Использование имени подкласса напрямую, как Child.Method - но в этом случае оно не должно быть абстрактным, потому что вы все равно ссылаетесь на конкретное имя подкласса; (2) через объект - но тогда он не должен быть статичным; (3) через экземпляр Class ‹?› С отражением - но тогда компилятор не может гарантировать, что экземпляр Class имеет определенный метод, и теперь вы подвержены исключению времени выполнения, если вы вызываете абстрактный метод, когда вы отражали Parent . Итог: необходимость в статической аннотации указывает на недостаток дизайна - person Chad N B; 25.10.2014
comment
@ChadNB, ты почти у цели. Еще несколько шагов, и вы увидите свет. Я расскажу вам: ваш второй вариант правильный. Он будет вызываться через экземпляр объекта, например. obj_child.StaticF(). Итак, ваш опыт работы с Java заставил вас задуматься, но тогда он не должен был быть статичным; и ответ, который мы даем, является, но тогда он не обязательно должен быть нестатическим. Статический - это вариант по умолчанию для методов. Только методы, которые ссылаются на экземпляры объектов, должны быть объявлены нестатическими. Например, если мы .......................... .................................................. ..... - person Pacerier; 25.10.2014
comment
.................................................. ............................ есть метод f(){ return "hello world"; }, он должен быть статическим, потому что нет ссылочного экземпляра объекта. Но если у нас есть метод f(){ return "hello world " + this.Name; }, он должен быть нестатическим, потому что имеется ссылка на экземпляр объекта. Статический всегда должен быть параметром по умолчанию. В Java мы вынуждены объявлять статические методы нестатическими, потому что статическое наследование в Java нарушено. Это языковой недостаток, как заявил Эрик. - person Pacerier; 25.10.2014
comment
@Pacerier На каких теоретических основаниях по умолчанию используется static? Похоже, вы это только что выдумали. Возможно в процедурном программировании; в ООП на самом деле я бы сказал, что методы экземпляра используются по умолчанию. В любом случае, почему? Если вы вызываете экземпляр, почему вас так беспокоит его статичность? Как это имеет практическое значение? - person Chad N B; 26.10.2014
comment
@ChadNB, Пожалуй, стоит разбить объяснение на шаги. Рассмотрим этот метод f(){ return "hello world"; }. У вас есть два варианта. 1) Сделайте его статичным. 2) Сделайте его нестатичным. Что вы выберете, а какое по умолчанию? - person Pacerier; 26.10.2014
comment
@Pacerier Сделать его статическим в родительском элементе менее гибко, потому что это означает, что подклассам никогда не будет разрешено использовать свои поля экземпляра. Нестатический - это более расширяемый, многоразовый дизайн. Я делаю его статическим только в том случае, если мне нужно удобство вызова без экземпляра, обычно это служебные методы. Если бы я планировал вызвать метод только для экземпляра, как в представленном вами сценарии, я бы сделал его нестатическим. Метод экземпляра более гибкий , даже если язык действительно поддерживает полиморфизм статических методов, поскольку он не добавляет ненужных ограничений на подклассы. - person Chad N B; 26.10.2014
comment
@ChadNB, это не лишнее ограничение, а необходимое, если вам важен красивый код и дизайн. Ужасно объявлять внутренне статическую функцию, такую ​​как f(){ return "hello world"; }, нестатической, потому что, делая это, вы излишне соединили их вместе. с переменной this. Гибкость, о которой вы говорите, является нарушением слабой связи. Это так же плохо, как гибкость, которую вы получаете, объявляя все поля и методы как public. - person Pacerier; 26.10.2014
comment
Как бы то ни было, что, если я хочу объявить метод класса в абстрактном классе, который я хочу, чтобы подклассы реализовали? - person Flying_Banana; 30.06.2015

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

person Community    schedule 20.10.2009
comment
Java полна странных ограничений. Замыкания, обращающиеся только к конечным переменным, - другое. А оставшийся список почти бесконечен. Работа программиста на Java - знать их и их обходные пути. Чтобы развлечься, мы должны использовать в свободное время что-то получше, чем Java. Но я бы не стал заморачиваться. Это семя для достижения прогресса. - person ceving; 04.12.2012
comment
Я считаю, что то, что вы называете плохим языковым дизайном, на самом деле больше похоже на защитный языковой дизайн, цель которого - ограничить нарушения принципов объектно-ориентированного программирования, которые допускают программисты из-за ненужных языковых функций. - person ethanfar; 25.03.2014
comment
Является ли концепция абстрактной статики нарушением объектно-ориентированных принципов? - person Trevor; 22.05.2014
comment
@threed, Вовсе нет, но, конечно, есть люди, которые говорят, что само понятие static уже является нарушением .... - person Pacerier; 10.09.2014
comment
Потребность в статике является четкой демонстрацией того, что принципы объектно-ориентированного программирования не так всеобъемлющи, как обычно утверждают. - person Ben; 12.05.2015
comment
@Ben Нет абсолютной необходимости в статике. И многие пуристы OO скажут вам, что статика - это мерзость. - person b1nary.atr0phy; 09.08.2015
comment
C ++ полон того же ограничения. - person user207421; 27.10.2015

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

person GaryF    schedule 16.12.2008
comment
Да, действительно обидно, что статические методы нельзя переопределить в Java. - person Michel; 16.12.2008
comment
@Michel: в чем будет смысл? Если вам нужно поведение на основе экземпляра, используйте методы экземпляра. - person Ran Biron; 16.12.2008
comment
Это неверный ответ. Статические методы в абстрактных классах работают нормально и широко используются. Просто статические методы самого класса не могут быть абстрактными. @Michel нет смысла переопределять статический метод. Как среда выполнения без экземпляра узнает, какой метод вызывать? - person erickson; 16.12.2008
comment
@erickson - Даже без экземпляра иерархия классов остается неизменной - наследование статических методов может работать так же, как наследование методов экземпляра. Smalltalk это делает, и это весьма полезно. - person Jared; 21.01.2009
comment
Хорошие новости. Из официальных документов для java 7 (см. docs.oracle.com/javase/ tutorial / java / IandI / abstract.html): абстрактный класс может иметь статические поля и статические методы. Вы можете использовать эти статические члены со ссылкой на класс, например AbstractClass.staticMethod (), как и с любым другим классом. - person matiasg; 25.04.2012
comment
@matiasg, в этом нет ничего нового. Абстрактным классам всегда разрешалось иметь статические, не абстрактные методы. - person Matt Ball; 09.08.2012
comment
@MattBall, это правда, я думаю, что мой разум добавил аннотацию там, где это не было написано. Итак: плохие новости. Это не изменилось в Java 7. - person matiasg; 23.08.2012

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

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

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

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

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

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

Нет таких вещей, как абстрактная статика ‹--- Запрещено в Java Universe

person anshulkatta    schedule 15.05.2013
comment
-1, неверно, что Java не позволяет переопределить статический метод, потому что статические члены и методы являются элементами времени компиляции. Статическая проверка типов определенно возможна с abstract static см. stackoverflow.com/questions/370962/. Настоящая причина, почему Java не позволяет переопределять статические методы, заключается в том, что Java не позволяет переопределять статические методы. - person Pacerier; 10.09.2014
comment
Перегрузка не имеет ничего общего с полиморфизмом. Перегрузка и переопределение не имеют ничего общего, кроме префикса over, почти так же, как Java и JavaScript содержат Java. Идентифицирует метод не имя, а его подпись. так что foo(String) не то же самое, что foo(Integer) - вот и все. - person Captain Man; 15.12.2016
comment
@CaptainMan Overloading буквально называется параметрическим полиморфизмом, потому что, в зависимости от типа параметра, вызывается другой метод, который является полиморфизмом. - person Davor; 28.01.2018

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

Фактически, вот реализация того, как это МОЖНО сделать в 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(); 

}
person mmm    schedule 19.03.2012
comment
Я не понял, где вы предоставили пример метода abstract static, как задано в вопросе, и вы написали жирным шрифтом МОЖНО СДЕЛАТЬ В JAVA. Это полное заблуждение. - person Blip; 28.06.2017
comment
Сам по себе он не позволяет вам определять его как абстрактный статический, но вы можете добиться аналогичного результата, с помощью которого вы можете изменить реализацию статического метода с помощью этого шаблона / хака. Это вряд ли ошибочно. Это можно сделать, но с другой семантикой. - person mmm; 28.06.2017
comment
Это пример расширения абстрактного класса с последующим помещением статических методов в дочерний. Это ни в коем случае не пример МОЖНО СДЕЛАТЬ В JAVA. - person Scuba Steve; 02.02.2019
comment
@ScubaSteve Во-первых, вы ошиблись в своем заключении. Во-вторых, достигается тот же результат. Значение статического доступа к классу может быть изменено другой реализацией. Это не ответ на то, чтобы сказать, что я сделал ключевое слово static абстрактным, но с помощью этого шаблона вы можете использовать статические методы и при этом изменять их реализацию. Хотя он имеет негативный эффект только потому, что он является глобальным, но для среды test / prod / dev он помогает нам. - person mmm; 03.02.2019

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

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

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

person Community    schedule 22.09.2012

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

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

person AndreyS Scherbakov    schedule 05.12.2015

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

person Sunil Kumar Jha    schedule 17.07.2015
comment
В абстрактных классах обязательно могут быть статические методы. Но не статические абстрактные методы. - person JacksOnF1re; 08.04.2016

Я вижу, что уже есть миллионы ответов, но я не вижу никаких практических решений. Конечно, это настоящая проблема, и нет веских причин для исключения этого синтаксиса в 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();
    }
person mhp    schedule 20.01.2016
comment
Поскольку в вашем окончательном решении абстрактный класс C не имеет никаких статических методов, почему бы просто не позволить C1 и C2 расширить его и переопределить метод doMoreWork () и позволить любым другим классам создавать его экземпляры и вызывать требуемые методы. В основном вы делаете то же самое, то есть расширяете класс C с помощью анонимного класса, а затем в C1 и C2, используя его статический экземпляр, чтобы разрешить доступ из статического метода, но это совсем не требуется. - person sactiw; 10.11.2016
comment
Я не понимаю контекст, который вы здесь предоставили. В вашем окончательном решении вы можете позвонить C1.doWork() или C2.doWork(), но вы не можете вызвать C.doWork(). Также в предоставленном вами примере, который не будет работать, предположим, что если это разрешено, то как класс C найдет реализацию doMoreWork()? Наконец, я бы назвал ваш контекстный код плохим дизайном. Почему? просто потому, что вы создали отдельную функцию для уникального кода вместо того, чтобы создать функцию для общего кода и затем реализовать статическую функцию в классе C. Это проще !!! - person Blip; 28.06.2017

Предположим, есть два класса, 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 метода: «Метод, который возвращает одно и то же значение для одних и тех же параметров независимо от экземпляра, в котором он вызван».

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

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

person hyper-neutrino    schedule 14.06.2015

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

person akash kumar    schedule 13.06.2018
comment
Но мы хотим иметь статические методы для расширения классов. Например, напишите имя класса вместо getSimpleName(). Мы хотим иметь abstract static String getClassName(); и расширить его на все дочерние классы. - person CoolMind; 19.11.2020

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

person Swapnillc    schedule 31.12.2019

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

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

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

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

person Mnementh    schedule 16.12.2008
comment
И абстрактный статический метод может быть вызван без экземпляра, но для этого потребуется создать реализацию в дочернем классе. Это не совсем полиморфизм, но единственный способ обойти его - заставить конкретный дочерний элемент реализовывать интерфейс, требующий абстрактного статического метода. Беспорядочно, но работоспособно. - person fijiaaron; 25.11.2010
comment
на самом деле, я был неправ. У вас также не может быть статических методов в интерфейсе. Языковой недостаток. - person fijiaaron; 25.11.2010

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

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

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

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 определяет, какой блок кода он должен выполнить (первая часть моего ответа).

person Blueriver    schedule 29.08.2015

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

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

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

Пример

abstract class foo {
    abstract static void bar2(); 
}


class Bar extends foo {
    //in this if you override foo class static method then it will give error
}
person Gaurav    schedule 28.12.2020

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

Таким образом, вы можете создать, например, абстрактный класс 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 может еще не быть элементов, но уже необходимо обеспечить предпочтительную сортировку.

Чирио, Олаф.

person Olaf Leimann    schedule 30.11.2013

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

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

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

Бум.

person bruhhhhh    schedule 24.07.2014
comment
Каждый метод в абстрактном классе требует, чтобы его класс в любом случае был расширен для выполнения, так что это не оправдание. Вы можете расширить абстрактный класс (одновременно реализуя абстрактный метод). Так что это не работает как объяснение. - person Pere; 17.01.2017

Согласно Java doc:

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

В 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));
    }    
}
person akhil_mittal    schedule 22.06.2015

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

person Praveen Kumar    schedule 28.09.2015
comment
Этот ответ не добавляет ничего из того, что еще не было рассмотрено в предыдущих ответах. - person MarsAtomic; 30.09.2015
comment
@MarsAtomic Я думаю, что это более уместно, чем ответ, получивший наибольшее количество голосов. Кроме того, это лаконично. - person Praveen Kumar; 30.09.2015
comment
Затем вы можете отредактировать предыдущие ответы, чтобы улучшить их, когда у вас будет достаточно репутации. Все, что вы делаете, это добавляете шум к сигналу, создавая повторяющиеся ответы. Пожалуйста, следуйте установленным правилам и обычаям Stack Overflow, а не создавайте свои собственные и ожидайте, что все остальные будут им следовать. - person MarsAtomic; 30.09.2015
comment
Я не согласен, пожалуйста, сравните мой ответ с другим, особенно с ответом, получившим наибольшее количество голосов. - person Praveen Kumar; 01.10.2015
comment
Почему я не могу этого сделать? Ответ: потому что не можешь. - person JacksOnF1re; 08.04.2016

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

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

person Darshan Chaudhary    schedule 05.12.2015

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

person Ashish Ranjan    schedule 13.05.2017
comment
пожалуйста, расскажите немного подробнее о своем ответе. - person Blip; 28.06.2017

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

person Manu    schedule 09.03.2018
comment
и почему это может быть проблемой? - person eis; 09.03.2018

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

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

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

person Jim Showalter    schedule 22.03.2014
comment
Как? Я искал решения, но не нашел. - person thouliha; 26.03.2015
comment
А? Ты не можешь. Все методы статических интерфейсов должны вызываться с использованием класса интерфейса. - person mmm; 07.08.2015
comment
Этот ответ неверен и вводит в заблуждение людей, плохо знакомых с Java. Это сделано для того, чтобы показать любой пример абстрактного статического метода, поскольку он не может быть реализован и заявлен в других ответах - person Blip; 09.07.2016

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

person Anubhav Nigam    schedule 16.02.2013
comment
Пожалуйста, используйте заглавные буквы и акцентируйте этот беспорядок. - person user207421; 27.10.2015