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

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

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

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

sactiw 10.11.2016 19:18
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
616
1
286 988
26
Перейти к ответу Данный вопрос помечен как решенный

Ответы 26

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

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

Michel 16.12.2008 14:29

@Michel: в чем будет смысл? Если вам нужно поведение на основе экземпляра, используйте методы экземпляра.

Ran Biron 16.12.2008 15:12

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

erickson 16.12.2008 18:57

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

Jared 21.01.2009 01:51

Хорошие новости. Из официальных документов для java 7 (см. docs.oracle.com/javase/tutorial/java/IandI/abstract.html): «Абстрактный класс может иметь статические поля и статические методы. Вы можете использовать эти статические члены со ссылкой на класс, например AbstractClass.staticMethod (), как и с любым другим классом. . "

matiasg 25.04.2012 16:55

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

Matt Ball 09.08.2012 16:41

@MattBall, это правда, я думаю, мой разум добавил «аннотацию» там, где это не было написано. Итак: плохие новости. Это не изменилось в Java 7.

matiasg 23.08.2012 18:47

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

Более краткий ответ - «ненормативная лексика». Статический должен означать «принадлежит классу», потому что именно так он используется интуитивно, как демонстрирует сам этот вопрос. См. «Метод класса» в Python.

Alexander Ljungberg 15.05.2010 05:01

@Alexander: Это вопрос не о static, а о abstract static. Статический также означает «принадлежность к классу» в Java.

Tomalak 15.05.2010 19:17

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

Alexander Ljungberg 16.05.2010 02:09

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

Eric Grange 08.06.2010 13:04

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

Tomalak 08.06.2010 15:21

Я согласен с @Eric. Чтобы возникло логическое противоречие, логика должна исходить из-за пределов правил java. Возможно, верно, что в java static означает «функциональность даже без экземпляра объекта», но это не противоречит abstract, за исключением конструкции языка. int означает «одно целое число», а [] означает «массив», но тот факт, что Java знает, что я хочу от int[], не означает, что он противоречит сам себе, а скорее то, что авторы Java решили разрешить определенную функциональность, связанную с особый порядок грамматики.

plowman 26.01.2011 07:34

@uncheck: я понимаю, что две вещи (абстрактная и статическая) независимы, даже ортогональны. Тем не менее, метод, объявленный как оба, не имеет большого смысла. Либо он абстрактный (т.е. пустой и должен быть реализован в дочернем классе), либо он статический (т.е. не пустой и вызывается в самом классе). Может быть, вы могли бы объяснить мне, как логически это может быть и то, и другое одновременно.

Tomalak 26.01.2011 12:40

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

Michael Carman 30.03.2011 00:10

@Tomalak явная проблема, с которой я сейчас сталкиваюсь, - это когда вам нужно знать класс дочернего объекта в унаследованном конструкторе (глубокая иерархия исключений): поскольку это информация, принадлежащая классу, вы должны сделать этот метод static, но поскольку вы не можете наследовать статические методы, вам нужно будет каким-то образом сделать их абстрактными; вы можете использовать нестатический метод, но проблема в том, что нестатические методы не могут быть вызваны в конструкторе; поэтому вы просто не можете узнать тип вашего экземпляра объекта в унаследованном конструкторе, если вы не укажете его в качестве аргумента! Это просто глупо.

Léo Germond 07.04.2011 14:22

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

mmm 19.03.2012 20:43

Как и многие вещи в Java, переход с другого языка кажется ограничением, но позже вы понимаете, что этого делать в любом случае не стоит. Например, в комментарии Лео, если вам нужно знать дочерний класс в унаследованном конструкторе, это вопиющее нарушение основных принципов ООП. Кроме того, как вы предлагаете вызывать такой метод? Чтобы вызвать статический метод, вам нужно имя класса. Используя имя базового класса, как узнать, какой подкласс вы намереваетесь? Тем не менее, если вы знаете подкласс, он не обязательно должен быть абстрактным. Покажите синтаксис, как это вообще будет работать.

Chad N B 28.08.2013 08:07

Если бы даже был способ вызвать его, как бы вы узнали, реализован ли абстрактный метод? Класс должен реализовать все абстрактные методы, прежде чем он сможет быть создан, но для статического метода вы НЕ создаете экземпляр класса. Итак, как вы вообще узнаете, действительно ли это действительный звонок? В Delphi, например, вы можете создавать статические абстрактные методы, но вы также можете получать исключения во время выполнения, когда вы вызываете такой метод. Я всегда предпочитаю ошибку времени компиляции ошибке времени выполнения. Как я уже сказал, это кажется ограничением, исходящим от другого языка, но Java пытается помочь вам с хорошим дизайном.

Chad N B 28.08.2013 08:13

Тогда почему в документации сказано: «У абстрактного класса могут быть статические поля и статический метод», а здесь их не может быть?

meso_2600 13.11.2013 16:14

Такие функции, как абстрактные статические методы, имеют тенденцию приводить к плохому дизайну. Вся цель абстрактного метода состоит в том, чтобы разрешить такие шаблоны, как фабрика методов, метод шаблона и т. д. Это хорошие шаблоны проектирования при правильном использовании, которые доступны благодаря качеству полиморфизма объектно-ориентированных языков. С другой стороны, абстрактный статический метод не имеет иной силы, кроме как заставить подклассы реализовывать что-то, что является явным нарушением нескольких принципов объектно-ориентированного проектирования (например, OCP).

ethanfar 25.03.2014 11:07

Мне это кажется плохой «особенностью». Я все еще мог бы создать подкласс класса и пожелать переопределить статические методы этого класса. Этот способ вынуждает меня создать экземпляр класса только для переопределения методов, которые в противном случае могли бы быть объявлены статическими, если эти методы не изменяются и не используют состояние экземпляра.

josiah 06.05.2014 00:53

-1, нужно больше голосов против. static не означает, что нет означает «функциональность существует без экземпляра объекта». static означает «функциональность май существует без экземпляра объекта». В случае, если это и static, и abstract, функциональность не будет существовать в родительском классе, но будет реализована в его подклассе.

Pacerier 10.09.2014 22:21

@ChadNB, Как и многие вещи в Java, исход из Java кажется правильным, но позже вы понимаете, что это просто произвольное ограничение языка. Абстрактная статика может существовать в строго типизированных языках, таких как Java, нет будет выдавать исключения во время выполнения ...............

Pacerier 10.09.2014 22:22

................. Рассмотрим статический абстрактный метод T1 Parent.F1(T2 x). Когда мы назовем его реализацией подкласса T1 Child.F1(T2 x), не будет исключений времени выполнения, так почему вы говорите, что у нас будут исключения времени выполнения? Кроме того, весь смысл абстрактного метода в том, что вам не нужно знать, реализован он или нет. Класс подкласса будет реализовывать это, а подкласс будет гарантировать, что контракт Лискова T1 Parent.F1(T2 x) сохраняется. Если подкласса нет, в любом случае не о чем беспокоиться, поскольку абстрактный метод может быть вызван только для подкласса.

Pacerier 10.09.2014 22:23

Однажды у меня был класс A с методом staticmain(String[] args) и класс B с staticmain(String[] args) throws Exception. И это привело к ошибке компилятора: не удалось переопределить метод.

MC Emperor 30.09.2014 15:36

@Pacerier Подумайте об этом. Как вы это называете? Три способа: (1) Использование имени подкласса напрямую, как Child.Method - но в этом случае оно не должно быть абстрактным, потому что вы все равно ссылаетесь на конкретное имя подкласса; (2) через объект - но тогда он не должен быть статичным; (3) через экземпляр Class <?> С отражением - но тогда компилятор не может гарантировать, что экземпляр Class имеет определенный метод, и теперь вы подвержены исключению времени выполнения, если вы вызываете абстрактный метод, когда вы отражали Parent . Итог: необходимость в статической аннотации указывает на недостаток дизайна

Chad N B 25.10.2014 07:20

@ChadNB, ты почти у цели. Еще несколько шагов, и вы увидите свет. Я расскажу вам: ваш второй вариант правильный. Он будет вызываться через экземпляр объекта, например. obj_child.StaticF(). Итак, ваш опыт работы с Java заставил вас подумать: «Но тогда это не обязательно должно быть статичным»; и ответ, который мы даем, - «но тогда он не обязательно должен быть статическим не». Статический - это вариант по умолчанию для методов. Только методы, которые ссылаются на экземпляры объектов, должны быть объявлены нестатическими. Например, если мы ............................................ ................ ‌ .................... ‌.

Pacerier 25.10.2014 14:25

.................................................. .......... ‌ .................. есть метод f(){ return "hello world"; }, он должен быть статическим, потому что нет ссылочного экземпляра объекта. Но если у нас есть метод f(){ return "hello world " + this.Name; }, он должен быть нестатическим, потому что имеется ссылка на экземпляр объекта. Статический всегда должен быть параметром по умолчанию. В Java мы вынуждены объявлять статические методы нестатическими, потому что статическое наследование в Java нарушено. Это языковой недостаток, как сказал Эрик.

Pacerier 25.10.2014 14:25

@Pacerier На каких теоретических основаниях статичность является "дефолтной"? Похоже, вы это только что выдумали. Возможно в процедурном программировании; в ООП на самом деле я бы сказал, что методы экземпляра используются по умолчанию. В любом случае, Зачем? Если вы вызываете экземпляр, почему вас так беспокоит его статичность? Как это имеет какое-то практическое значение?

Chad N B 26.10.2014 02:05

@ChadNB, Пожалуй, стоит разбить объяснение на шаги. Рассмотрим этот метод f(){ return "hello world"; }. У вас есть два варианта. 1) Сделайте его статичным. 2) Сделайте его нестатичным. Что вы выберете, а какое по умолчанию?

Pacerier 26.10.2014 04:55

@Pacerier Сделать его статическим в родительском элементе менее гибко, потому что это означает, что подклассам никогда не будет разрешено использовать свои поля экземпляра. Нестатический - это более расширяемый, многоразовый дизайн. Я делаю его статическим только в том случае, если мне нужно удобство вызова без экземпляра, обычно это служебные методы. Если бы я планировал вызвать метод только для экземпляра, как в представленном вами сценарии, я бы сделал его нестатическим. Метод экземпляра более гибкий даже если язык поддерживает полиморфизм статических методов, потому что он не добавляет ненужных ограничений на подклассы.

Chad N B 26.10.2014 05:15

@ChadNB, это не лишнее ограничение, а необходимое, если вам важен красивый код и дизайн. Уродливый прием - объявлять внутренне статическую функцию, такую ​​как f(){ return "hello world"; }, нестатической, потому что, делая это, вы излишне соединенный ее вместе с переменной this. Типа «гибкости», о котором вы говорите, является нарушение низкой связи. Это так же плохо, как "гибкость", которую вы получаете, объявляя все поля и методы как public.

Pacerier 26.10.2014 06:04

Как бы то ни было, что, если я хочу объявить метод класса в абстрактном классе, который я хочу, чтобы подклассы реализовали?

Flying_Banana 30.06.2015 17:35

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

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

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

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

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

fijiaaron 25.11.2010 05:11

на самом деле, я был неправ. У вас также не может быть статических методов в интерфейсе. Языковой недостаток.

fijiaaron 25.11.2010 05:17
Ответ принят как подходящий

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

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

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

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

ClassA.methodA();

а также

methodA();

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

ClassA methodA.

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

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

Steven De Groote 05.07.2012 19:22

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

John29 07.12.2013 18:24

@ John29 Спасибо за разъяснения, но, не считая разницы в именах, они похожи в использовании.

Steven De Groote 09.12.2013 12:09

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

John29 10.12.2013 21:52

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

Doradus 02.09.2014 04:10

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

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

ceving 04.12.2012 22:48

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

ethanfar 25.03.2014 11:10

Является ли концепция «абстрактной статики» нарушением объектно-ориентированных принципов?

Trevor 22.05.2014 01:38

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

Pacerier 10.09.2014 22:26

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

Ben 12.05.2015 07:29

@Ben Абсолютного нужно для статики не существует. И многие пуристы OO скажут вам, что статика - это мерзость.

b1nary.atr0phy 09.08.2015 07:21

C++ полон того же ограничения.

user207421 27.10.2015 23:51

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

Фактически, вот реализация того, как сделать МОЖЕТ в ЯВА:

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

}

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

Blip 28.06.2017 11:13

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

mmm 28.06.2017 14:59

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

Scuba Steve 02.02.2019 04:08

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

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

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

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

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

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

user207421 27.10.2015 23:52

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

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

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

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

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

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

Нет ничего похожего на абстрактная статика <--- Не разрешено в Java Universe

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

Pacerier 10.09.2014 22:39

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

Captain Man 15.12.2016 23:15

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

Davor 28.01.2018 18:52

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

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

Cheerio, Олаф.

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

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

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

Как? Я искал решения, но не нашел.

thouliha 26.03.2015 17:18

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

mmm 07.08.2015 18:39

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

Blip 09.07.2016 11:04

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

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

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

Бум.

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

Pere 17.01.2017 19:11

Предположим, есть два класса: 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.

Согласно Java док:

A static method is a method that is associated with the class in which it is defined rather than with any object. Every instance of the class shares its static methods

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

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

В абстрактных классах обязательно могут быть статические методы. Но не статические абстрактные методы.

JacksOnF1re 08.04.2016 01:15

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

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

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

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

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

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

MarsAtomic 30.09.2015 03:16

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

Praveen Kumar 30.09.2015 10:46

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

MarsAtomic 30.09.2015 22:23

Я не согласен, пожалуйста, сравните мой ответ с другим, особенно с ответом, получившим наибольшее количество голосов.

Praveen Kumar 01.10.2015 10:07

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

JacksOnF1re 08.04.2016 01:13

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

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

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

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

Я вижу, что уже есть миллионы ответов, но я не вижу никаких практических решений. Конечно, это настоящая проблема, и нет веских причин для исключения этого синтаксиса в 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 идентичны. Таких кодов может быть много: C3C4 и т. д. Если 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();
    }

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

sactiw 10.11.2016 19:06

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

Blip 28.06.2017 12:07

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

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

Blip 28.06.2017 11:15

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

и почему это может быть проблемой?

eis 09.03.2018 09:51

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

Но мы хотим иметь статические методы для расширения классов. Например, напишите имя класса вместо getSimpleName(). Мы хотим иметь abstract static String getClassName(); и распространить его на все дочерние классы.

CoolMind 19.11.2020 21:03

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

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

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

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

Пример

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
}

Другие вопросы по теме