В Java возникает вопрос, почему я не могу определить абстрактный статический метод? Например
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}




Вы не можете переопределить статический метод, поэтому делать его абстрактным было бы бессмысленно. Более того, статический метод в абстрактном классе будет принадлежать этому классу, а не классу переопределения, поэтому его все равно нельзя использовать.
Да, действительно обидно, что статические методы нельзя переопределить в Java.
@Michel: в чем будет смысл? Если вам нужно поведение на основе экземпляра, используйте методы экземпляра.
Это неверный ответ. Статические методы в абстрактных классах работают нормально и широко используются. Просто статические методы самого класса не могут быть абстрактными. @Michel нет смысла переопределять статический метод. Как среда выполнения без экземпляра узнает, какой метод вызывать?
@erickson - Даже без экземпляра иерархия классов остается неизменной - наследование статических методов может работать так же, как наследование методов экземпляра. Smalltalk это делает, и это весьма полезно.
Хорошие новости. Из официальных документов для java 7 (см. docs.oracle.com/javase/tutorial/java/IandI/abstract.html): «Абстрактный класс может иметь статические поля и статические методы. Вы можете использовать эти статические члены со ссылкой на класс, например AbstractClass.staticMethod (), как и с любым другим классом. . "
@matiasg, в этом нет ничего нового. Абстрактным классам всегда разрешалось иметь статические методы неабстрактный.
@MattBall, это правда, я думаю, мой разум добавил «аннотацию» там, где это не было написано. Итак: плохие новости. Это не изменилось в Java 7.
Потому что «абстрактный» означает: «Не реализует функциональность», а «статический» означает: «Функциональность есть, даже если у вас нет экземпляра объекта». И это логическое противоречие.
Более краткий ответ - «ненормативная лексика». Статический должен означать «принадлежит классу», потому что именно так он используется интуитивно, как демонстрирует сам этот вопрос. См. «Метод класса» в Python.
@Alexander: Это вопрос не о static, а о abstract static. Статический также означает «принадлежность к классу» в Java.
@Tomalak Прошу прощения, я не понял. Конечно, статический метод «принадлежит классу». Тем не менее, это только в том смысле, что он живет в том же пространстве имен. Статический метод не является методом самого объекта класса: он не работает с this в качестве объекта класса и не участвует должным образом в цепочке наследования. Если бы это действительно был метод класса, abstract static имел бы смысл. Это был бы метод самого объекта класса, который должны реализовывать объекты подкласса. Конечно, ваш ответ верен, несмотря на то, что я скептически отношусь к языку.
Это не логическое противоречие, это языковой недостаток, несколько других языков поддерживают это понятие. «абстрактное» означает «реализовано в подклассах», «статическое» означает «выполняется в классе, а не в экземплярах класса». Нет логического противоречия.
@Eric: И по-прежнему, то, что вы говорите, не относится к abstract static: функция X, которая «реализована в подклассе» не могу, в то же время будет «выполняться в классе» - только в подкласс. Где это уже не абстрактно.
Я согласен с @Eric. Чтобы возникло логическое противоречие, логика должна исходить из-за пределов правил java. Возможно, верно, что в java static означает «функциональность даже без экземпляра объекта», но это не противоречит abstract, за исключением конструкции языка. int означает «одно целое число», а [] означает «массив», но тот факт, что Java знает, что я хочу от int[], не означает, что он противоречит сам себе, а скорее то, что авторы Java решили разрешить определенную функциональность, связанную с особый порядок грамматики.
@uncheck: я понимаю, что две вещи (абстрактная и статическая) независимы, даже ортогональны. Тем не менее, метод, объявленный как оба, не имеет большого смысла. Либо он абстрактный (т.е. пустой и должен быть реализован в дочернем классе), либо он статический (т.е. не пустой и вызывается в самом классе). Может быть, вы могли бы объяснить мне, как логически это может быть и то, и другое одновременно.
@Tomakak: Ваша логика круговая. static не означает «не пустой» - это просто следствие того, что Java не позволяет статическим методам быть абстрактными. Это означает «вызываемый в классе». (Это должно означать «вызываемый Только в классе», но это другая проблема.) Если бы Java поддерживала методы abstract static, я бы ожидал, что это будет означать, что метод 1) должен быть реализован подклассами и 2) является методом класса подкласса. . Некоторые методы просто не имеют смысла как методы экземпляра. К сожалению, Java не позволяет указать это при создании абстрактного базового класса (или интерфейса).
@Tomalak явная проблема, с которой я сейчас сталкиваюсь, - это когда вам нужно знать класс дочернего объекта в унаследованном конструкторе (глубокая иерархия исключений): поскольку это информация, принадлежащая классу, вы должны сделать этот метод static, но поскольку вы не можете наследовать статические методы, вам нужно будет каким-то образом сделать их абстрактными; вы можете использовать нестатический метод, но проблема в том, что нестатические методы не могут быть вызваны в конструкторе; поэтому вы просто не можете узнать тип вашего экземпляра объекта в унаследованном конструкторе, если вы не укажете его в качестве аргумента! Это просто глупо.
Я согласен с Александром, но один из способов сделать это - определить статический метод, чтобы он вызывал реализацию одноэлементного экземпляра того же класса. Затем этот метод может быть переопределен путем обмена синглтоном с другой реализацией подкласса ...
Как и многие вещи в Java, переход с другого языка кажется ограничением, но позже вы понимаете, что этого делать в любом случае не стоит. Например, в комментарии Лео, если вам нужно знать дочерний класс в унаследованном конструкторе, это вопиющее нарушение основных принципов ООП. Кроме того, как вы предлагаете вызывать такой метод? Чтобы вызвать статический метод, вам нужно имя класса. Используя имя базового класса, как узнать, какой подкласс вы намереваетесь? Тем не менее, если вы знаете подкласс, он не обязательно должен быть абстрактным. Покажите синтаксис, как это вообще будет работать.
Если бы даже был способ вызвать его, как бы вы узнали, реализован ли абстрактный метод? Класс должен реализовать все абстрактные методы, прежде чем он сможет быть создан, но для статического метода вы НЕ создаете экземпляр класса. Итак, как вы вообще узнаете, действительно ли это действительный звонок? В Delphi, например, вы можете создавать статические абстрактные методы, но вы также можете получать исключения во время выполнения, когда вы вызываете такой метод. Я всегда предпочитаю ошибку времени компиляции ошибке времени выполнения. Как я уже сказал, это кажется ограничением, исходящим от другого языка, но Java пытается помочь вам с хорошим дизайном.
Тогда почему в документации сказано: «У абстрактного класса могут быть статические поля и статический метод», а здесь их не может быть?
Такие функции, как абстрактные статические методы, имеют тенденцию приводить к плохому дизайну. Вся цель абстрактного метода состоит в том, чтобы разрешить такие шаблоны, как фабрика методов, метод шаблона и т. д. Это хорошие шаблоны проектирования при правильном использовании, которые доступны благодаря качеству полиморфизма объектно-ориентированных языков. С другой стороны, абстрактный статический метод не имеет иной силы, кроме как заставить подклассы реализовывать что-то, что является явным нарушением нескольких принципов объектно-ориентированного проектирования (например, OCP).
Мне это кажется плохой «особенностью». Я все еще мог бы создать подкласс класса и пожелать переопределить статические методы этого класса. Этот способ вынуждает меня создать экземпляр класса только для переопределения методов, которые в противном случае могли бы быть объявлены статическими, если эти методы не изменяются и не используют состояние экземпляра.
-1, нужно больше голосов против. static не означает, что нет означает «функциональность существует без экземпляра объекта». static означает «функциональность май существует без экземпляра объекта». В случае, если это и static, и abstract, функциональность не будет существовать в родительском классе, но будет реализована в его подклассе.
@ChadNB, Как и многие вещи в Java, исход из Java кажется правильным, но позже вы понимаете, что это просто произвольное ограничение языка. Абстрактная статика может существовать в строго типизированных языках, таких как Java, нет будет выдавать исключения во время выполнения ...............
................. Рассмотрим статический абстрактный метод T1 Parent.F1(T2 x). Когда мы назовем его реализацией подкласса T1 Child.F1(T2 x), не будет исключений времени выполнения, так почему вы говорите, что у нас будут исключения времени выполнения? Кроме того, весь смысл абстрактного метода в том, что вам не нужно знать, реализован он или нет. Класс подкласса будет реализовывать это, а подкласс будет гарантировать, что контракт Лискова T1 Parent.F1(T2 x) сохраняется. Если подкласса нет, в любом случае не о чем беспокоиться, поскольку абстрактный метод может быть вызван только для подкласса.
Однажды у меня был класс A с методом staticmain(String[] args) и класс B с staticmain(String[] args) throws Exception. И это привело к ошибке компилятора: не удалось переопределить метод.
@Pacerier Подумайте об этом. Как вы это называете? Три способа: (1) Использование имени подкласса напрямую, как Child.Method - но в этом случае оно не должно быть абстрактным, потому что вы все равно ссылаетесь на конкретное имя подкласса; (2) через объект - но тогда он не должен быть статичным; (3) через экземпляр Class <?> С отражением - но тогда компилятор не может гарантировать, что экземпляр Class имеет определенный метод, и теперь вы подвержены исключению времени выполнения, если вы вызываете абстрактный метод, когда вы отражали Parent . Итог: необходимость в статической аннотации указывает на недостаток дизайна
@ChadNB, ты почти у цели. Еще несколько шагов, и вы увидите свет. Я расскажу вам: ваш второй вариант правильный. Он будет вызываться через экземпляр объекта, например. obj_child.StaticF(). Итак, ваш опыт работы с Java заставил вас подумать: «Но тогда это не обязательно должно быть статичным»; и ответ, который мы даем, - «но тогда он не обязательно должен быть статическим не». Статический - это вариант по умолчанию для методов. Только методы, которые ссылаются на экземпляры объектов, должны быть объявлены нестатическими. Например, если мы ............................................ ................ .................... .
.................................................. .......... .................. есть метод f(){ return "hello world"; }, он должен быть статическим, потому что нет ссылочного экземпляра объекта. Но если у нас есть метод f(){ return "hello world " + this.Name; }, он должен быть нестатическим, потому что имеется ссылка на экземпляр объекта. Статический всегда должен быть параметром по умолчанию. В Java мы вынуждены объявлять статические методы нестатическими, потому что статическое наследование в Java нарушено. Это языковой недостаток, как сказал Эрик.
@Pacerier На каких теоретических основаниях статичность является "дефолтной"? Похоже, вы это только что выдумали. Возможно в процедурном программировании; в ООП на самом деле я бы сказал, что методы экземпляра используются по умолчанию. В любом случае, Зачем? Если вы вызываете экземпляр, почему вас так беспокоит его статичность? Как это имеет какое-то практическое значение?
@ChadNB, Пожалуй, стоит разбить объяснение на шаги. Рассмотрим этот метод f(){ return "hello world"; }. У вас есть два варианта. 1) Сделайте его статичным. 2) Сделайте его нестатичным. Что вы выберете, а какое по умолчанию?
@Pacerier Сделать его статическим в родительском элементе менее гибко, потому что это означает, что подклассам никогда не будет разрешено использовать свои поля экземпляра. Нестатический - это более расширяемый, многоразовый дизайн. Я делаю его статическим только в том случае, если мне нужно удобство вызова без экземпляра, обычно это служебные методы. Если бы я планировал вызвать метод только для экземпляра, как в представленном вами сценарии, я бы сделал его нестатическим. Метод экземпляра более гибкий даже если язык поддерживает полиморфизм статических методов, потому что он не добавляет ненужных ограничений на подклассы.
@ChadNB, это не лишнее ограничение, а необходимое, если вам важен красивый код и дизайн. Уродливый прием - объявлять внутренне статическую функцию, такую как f(){ return "hello world"; }, нестатической, потому что, делая это, вы излишне соединенный ее вместе с переменной this. Типа «гибкости», о котором вы говорите, является нарушение низкой связи. Это так же плохо, как "гибкость", которую вы получаете, объявляя все поля и методы как public.
Как бы то ни было, что, если я хочу объявить метод класса в абстрактном классе, который я хочу, чтобы подклассы реализовали?
Статический метод можно вызвать без экземпляра класса. В вашем примере вы можете вызвать foo.bar2 (), но не foo.bar (), потому что для bar вам нужен экземпляр. Следующий код будет работать:
foo var = new ImplementsFoo();
var.bar();
Если вы вызываете статический метод, он всегда будет выполняться с одним и тем же кодом. В приведенном выше примере, даже если вы переопределите bar2 в ImplementsFoo, вызов var.bar2 () приведет к выполнению foo.bar2 ().
Если bar2 теперь не имеет реализации (что означает абстрактное), вы можете вызвать метод без реализации. Это очень вредно.
И абстрактный статический метод может быть вызван без экземпляра, но для этого потребуется создать реализацию в дочернем классе. Это не совсем полиморфизм, но единственный способ обойти это - заставить конкретный дочерний элемент реализовывать интерфейс, который «требует» «абстрактный статический» метод. Беспорядочно, но работоспособно.
на самом деле, я был неправ. У вас также не может быть статических методов в интерфейсе. Языковой недостаток.
Аннотация abstract к методу указывает, что метод ДОЛЖЕН быть переопределен в подклассе.
В Java член static (метод или поле) не может быть переопределен подклассами (это не обязательно верно для других объектно-ориентированных языков, см. SmallTalk.) Членом static может быть скрытый, но это принципиально отличается от отвергнутый.
Поскольку статические члены не могут быть переопределены в подклассе, аннотация abstract не может быть применена к ним.
Кстати, другие языки поддерживают статическое наследование, как и наследование экземпляров. С точки зрения синтаксиса, эти языки обычно требуют, чтобы имя класса было включено в оператор. Например, в Java, если вы пишете код в ClassA, это эквивалентные операторы (если methodA () является статическим методом и нет метода экземпляра с такой же подписью):
ClassA.methodA();
а также
methodA();
В SmallTalk имя класса не является необязательным, поэтому синтаксис следующий (обратите внимание, что SmallTalk не использует. Для разделения «предмета» и «глагола», а вместо этого использует его в качестве признака завершения изменения состояния):
ClassA methodA.
Поскольку имя класса требуется всегда, правильную «версию» метода всегда можно определить путем обхода иерархии классов. Как бы то ни было, я иногда пропускаю наследование static, и меня укусило отсутствие статического наследования в Java, когда я только начал с ним работать. Кроме того, SmallTalk имеет тип «утка» (и, следовательно, не поддерживает «программу по контракту»). Таким образом, он не имеет модификатора abstract для членов класса.
«Статический член не может быть переопределен подклассами» неверно. Возможно, по крайней мере, на Java6. Не уверен, с каких это пор.
@Steven De Groote. Статический член действительно не может быть переопределен подклассами. Если у подкласса есть статический метод с той же сигнатурой, что и у статического метода в суперклассе, он не отменяет его, а скрывает. http://docs.oracle.com/javase/tutorial/java/IandI/override.h tml Разница в том, что полиморфизм работает только для переопределенных, но не для скрытых методов.
@ John29 Спасибо за разъяснения, но, не считая разницы в именах, они похожи в использовании.
@Steven De Groote: Да, он похож на использование, но поведение другое. Вот почему нет статических абстрактных методов - какой смысл в статических абстрактных методах, если они не поддерживают полиморфизм?
@ Стивен Де Гроот: разница становится очевидной, когда вы вызываете этот метод в самом суперклассе. Предположим, Super.foo вызывает Super.bar. Если подкласс реализует Subclass.bar, а затем вызывает foo, тогда foo по-прежнему будет вызывать Super.bar, а не Subclass.bar. Следовательно, на самом деле у вас есть два совершенно разных и не связанных между собой метода, оба называемые «bar». Это не является приоритетным в любом полезном смысле.
Плохой языковой дизайн. Было бы гораздо эффективнее вызывать статический абстрактный метод напрямую, чем создавать экземпляр только для использования этого абстрактного метода. Это особенно актуально при использовании абстрактного класса в качестве обходного пути для невозможности расширения enum, что является еще одним неудачным примером дизайна. Надеюсь, они устранят эти ограничения в следующем выпуске.
Java полна странных ограничений. Замыкания, обращающиеся только к конечным переменным, - другое. А оставшийся список почти бесконечен. Работа программиста на Java - знать их и их обходные пути. Чтобы развлечься, мы должны использовать в свободное время что-то получше, чем Java. Но я бы не стал заморачиваться. Это семя для достижения прогресса.
Я считаю, что то, что вы называете «плохим языковым дизайном», на самом деле больше похоже на «защитный языковой дизайн», цель которого - ограничить нарушения принципов объектно-ориентированного программирования, которые допускают программисты из-за ненужных языковых функций.
Является ли концепция «абстрактной статики» нарушением объектно-ориентированных принципов?
@threed, Вовсе нет, но, конечно, есть люди, которые говорят, что сама концепция static уже является нарушением ....
Потребность в статике является четкой демонстрацией того, что «принципы объектно-ориентированного программирования» не так всеобъемлющи, как обычно утверждают.
@Ben Абсолютного нужно для статики не существует. И многие пуристы OO скажут вам, что статика - это мерзость.
C++ полон того же ограничения.
Это ужасный языковой дизайн, и на самом деле это не причина, почему это невозможно.
Фактически, вот реализация того, как сделать МОЖЕТ в ЯВА:
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. Это полное заблуждение.
Сам по себе он не позволяет вам определять его как абстрактную статику, но вы можете добиться аналогичного результата, с помощью которого вы можете изменить реализацию статического метода s, используя этот шаблон / хак. Это вряд ли ошибочно. Это можно сделать, но с другой семантикой.
Это пример расширения абстрактного класса с последующим помещением статических методов в дочерний. Это ни в коем случае не пример МОЖНО СДЕЛАТЬ В JAVA.
@ScubaSteve Во-первых, вы ошиблись в своем заключении. Во-вторых, достигается тот же результат. Значение статического доступа к классу может быть изменено другой реализацией. Это не ответ на то, чтобы сказать, что я сделал ключевое слово static абстрактным, но с помощью этого шаблона вы можете использовать статические методы и при этом изменять их реализацию. Хотя он имеет негативный эффект только потому, что он является глобальным, но для среды test / prod / dev он помогает нам.
Абстрактный метод определяется только для того, чтобы его можно было переопределить в подклассе. Однако статические методы нельзя переопределить. Следовательно, наличие абстрактного статического метода является ошибкой времени компиляции.
Теперь следующий вопрос: почему статические методы нельзя переопределить ??
Это потому, что статические методы принадлежат определенному классу, а не его экземпляру. Если вы попытаетесь переопределить статический метод, вы не получите никаких ошибок компиляции или выполнения, но компилятор просто скроет статический метод суперкласса.
Потому что, если класс расширяет абстрактный класс, он должен переопределить абстрактные методы, и это обязательно. И поскольку статические методы - это методы класса, разрешенные во время компиляции, тогда как переопределенные методы - это методы экземпляра, разрешенные во время выполнения и следующие динамическому полиморфизму.
Пожалуйста, используйте заглавные буквы и акцентируйте этот беспорядок.
Я тоже задал тот же вопрос, вот почему
Поскольку абстрактный класс говорит, он не будет предоставлять реализацию и позволяет подклассу предоставлять ее
поэтому подкласс должен переопределить методы суперкласса,
ПРАВИЛО № 1 - Статический метод нельзя переопределить
Поскольку статические члены и методы являются элементами времени компиляции, поэтому разрешена перегрузка (полиморфизм времени компиляции) статических методов, а не переопределение (полиморфизм времени выполнения)
Итак, они не могут быть абстрактными.
Нет ничего похожего на абстрактная статика <--- Не разрешено в Java Universe
-1, неверно, что «Java не позволяет переопределить статический метод, потому что статические члены и методы являются элементами времени компиляции». Статическая проверка типов определенно возможна с abstract static, см. stackoverflow.com/questions/370962/…. настоящая причина, почему Java не позволяет переопределять статические методы, заключается в том, что Java не позволяет переопределять статические методы.
Перегрузка не имеет ничего общего с полиморфизмом. Перегрузка и переопределение не имеют ничего общего, кроме префикса «over», почти так же, как Java и JavaScript имеют в себе «Java». Идентифицирует метод не имя, а его подпись. так что foo(String) - это не то же самое, что foo(Integer) - вот и все.
@CaptainMan Перегрузка буквально называется «параметрическим полиморфизмом», потому что, в зависимости от типа параметра, вызывается другой метод, который является полиморфизмом.
Идея наличия абстрактного статического метода заключалась бы в том, что вы не можете использовать этот конкретный абстрактный класс напрямую для этого метода, но только первая производная будет разрешена для реализации этого статического метода (или для дженериков: фактический класс универсального вы использовать).
Таким образом, вы могли бы создать, например, абстрактный класс 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
Как? Я искал решения, но не нашел.
Что? Ты не можешь. Все методы статических интерфейсов должны вызываться с использованием класса интерфейса.
Этот ответ неверен и вводит в заблуждение людей, плохо знакомых с Java. Это сделано для того, чтобы показать любой пример абстрактного статического метода, поскольку он не может быть реализован и заявлен в других ответах
Во-первых, ключевой момент об абстрактных классах - Невозможно создать экземпляр абстрактного класса (см. вики). Итак, вы не можете создать экземпляр любой абстрактного класса.
Теперь способ, которым Java работает со статическими методами, - это совместное использование метода со всеми экземпляры этого класса.
Итак, если вы не можете создать экземпляр класса, этот класс не может иметь абстрактных статических методов, поскольку абстрактный метод требует расширения.
Бум.
Каждый метод в абстрактном классе требует, чтобы его класс в любом случае был расширен для выполнения, так что это не оправдание. Вы можете расширить абстрактный класс (одновременно реализуя абстрактный метод). Так что это не работает как объяснение.
Предположим, есть два класса: 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, откуда они используются для всех объектов. Методы абстрактного класса динамически привязаны к своей функциональности.
В абстрактных классах обязательно могут быть статические методы. Но не статические абстрактные методы.
Я считаю, что нашел ответ на этот вопрос в виде того, почему методы интерфейса (которые работают как абстрактные методы в родительском классе) не могут быть статическими. Вот полный ответ (не мой)
В основном статические методы могут быть привязаны во время компиляции, поскольку для их вызова вам необходимо указать класс. Это отличается от методов экземпляра, для которых класс ссылки, из которой вы вызываете метод, может быть неизвестен во время компиляции (таким образом, какой блок кода вызывается, можно определить только во время выполнения).
Если вы вызываете статический метод, вы уже знаете класс, в котором он реализован, или любые его прямые подклассы. Если вы определите
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 Я думаю, что это более уместно, чем ответ, получивший наибольшее количество голосов. Кроме того, это лаконично.
Затем вы можете отредактировать предыдущие ответы, чтобы улучшить их, когда у вас будет достаточно репутации. Все, что вы делаете, это добавляете шум к сигналу, создавая повторяющиеся ответы. Пожалуйста, следуйте установленным правилам и обычаям Stack Overflow, а не создавайте свои собственные и ожидайте, что все остальные будут им следовать.
Я не согласен, пожалуйста, сравните мой ответ с другим, особенно с ответом, получившим наибольшее количество голосов.
"Почему я не могу этого сделать?" Ответ: «потому что не можешь».
Обычные методы могут быть абстрактными, если они предназначены для переопределения подклассами и обеспечения функциональности.
Представьте, что класс 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, используя его статический экземпляр, чтобы разрешить доступ из статического метода, но это совсем не требуется.
Я не понимаю контекст, который вы здесь предоставили. В вашем окончательном решении вы можете вызвать C1.doWork() или C2.doWork(). Но вы не можете вызвать C.doWork(). Также в примере, который вы предоставили, который не будет работать, предположим, что если это было разрешено, то как класс C найдет реализацию doMoreWork()? Наконец, я бы назвал ваш контекстный код плохим дизайном. Почему? просто потому, что вы создали отдельную функцию для уникального кода вместо того, чтобы создать функцию для общего кода и затем реализовать статическую функцию в классе C. Это проще !!!
Поскольку abstract - это ключевое слово, которое применяется к абстрактным методам, не указывается тело. И если мы говорим о статическом ключевом слове, оно относится к области класса.
пожалуйста, расскажите немного подробнее о своем ответе.
потому что, если вы используете какой-либо статический член или статическую переменную в классе, он будет загружаться во время загрузки класса.
и почему это может быть проблемой?
Объявление метода как static означает, что мы можем вызывать этот метод по имени его класса, и если этот класс также является abstract, нет смысла вызывать его, поскольку он не содержит тела, и, следовательно, мы не можем объявить метод как static, так и abstract.
Но мы хотим иметь статические методы для расширения классов. Например, напишите имя класса вместо getSimpleName(). Мы хотим иметь abstract static String getClassName(); и распространить его на все дочерние классы.
Поскольку абстрактный класс является концепцией 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
}
Несколько причин: статический метод должен иметь тело, даже если они являются частью абстрактного класса, потому что не нужно создавать экземпляр класса для доступа к его статическому методу. Другой способ подумать об этом: если на мгновение мы предположим, что это разрешено, проблема в том, что вызовы статических методов не предоставляют никакой информации о типе времени выполнения (RTTI), помните, что создание экземпляра не требуется, поэтому они не могут перенаправляться к их конкретным переопределенным реализациям, и, таким образом, разрешение abstarct static вообще не имеет смысла. Другими словами, он не мог обеспечить никакого преимущества полиморфизма, поэтому недопустим.