В Java возникает вопрос, почему я не могу определить абстрактный статический метод? Например
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
В Java возникает вопрос, почему я не могу определить абстрактный статический метод? Например
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Аннотация abstract
к методу указывает, что метод ДОЛЖЕН быть переопределен в подклассе.
В Java член static
(метод или поле) не может быть переопределен подклассами (это не обязательно верно для других объектно-ориентированных языков, см. SmallTalk). Член static
может быть скрытым, но это принципиально отличается от переопределено.
Поскольку статические члены не могут быть переопределены в подклассе, аннотация abstract
не может применяться к ним.
Кстати, другие языки поддерживают статическое наследование, как и наследование экземпляров. С точки зрения синтаксиса, эти языки обычно требуют, чтобы имя класса было включено в оператор. Например, в Java, если вы пишете код в ClassA, это эквивалентные операторы (если methodA () является статическим методом и нет метода экземпляра с такой же подписью):
ClassA.methodA();
а также
methodA();
В SmallTalk имя класса не является необязательным, поэтому синтаксис следующий (обратите внимание, что SmallTalk не использует. Для разделения «предмета» и «глагола», а вместо этого использует его в качестве признака завершения изменения состояния):
ClassA methodA.
Поскольку имя класса требуется всегда, правильную «версию» метода всегда можно определить путем обхода иерархии классов. Как бы то ни было, я иногда пропускаю static
наследование, и когда я только начал с ним работать, меня укусило отсутствие статического наследования в Java. Вдобавок SmallTalk имеет тип «утка» (и, следовательно, не поддерживает «программу по контракту»). Таким образом, он не имеет модификатора abstract
для членов класса.
Потому что «абстрактный» означает: «Не реализует функциональность», а «статический» означает: «Функциональность есть, даже если у вас нет экземпляра объекта». И это логическое противоречие.
static
, а о abstract static
. Статический означает также принадлежность к классу в Java.
- person Tomalak; 15.05.2010
abstract static
имел бы смысл. Это был бы метод самого объекта класса, который должны реализовывать объекты подкласса. Конечно, ваш ответ верен, несмотря на то, что я скептически отношусь к языку.
- person Alexander Ljungberg; 16.05.2010
abstract static
: функция X, которая реализована в подклассе не может одновременно выполняться в классе - только в подклассе. Где это уже не абстрактно.
- person Tomalak; 08.06.2010
static
означает функциональность, даже без экземпляра объекта, но это не противоречит abstract
, за исключением конструкции языка. int
означает «одно целое число», а []
означает «массив», но тот факт, что Java знает, что я хочу от int[]
, не означает, что это противоречит самим себе, а скорее то, что авторы Java решили разрешить определенную функциональность, связанную с особый порядок грамматики.
- person plowman; 26.01.2011
static
не означает не пустой - это просто следствие того, что Java не позволяет статическим методам быть абстрактными. Это означает возможность вызова в классе. (Это должно означать вызываемый только в классе, но это другая проблема.) Если Java поддерживает abstract static
методы, я ожидал бы, что это будет означать, что метод 1) должен быть реализован подклассами, а 2) является class метод подкласса. Некоторые методы просто не имеют смысла как методы экземпляра. К сожалению, Java не позволяет указать это при создании абстрактного базового класса (или интерфейса).
- person Michael Carman; 30.03.2011
static
не означает, что функциональность существует без экземпляра объекта. static
означает, что функциональность может существовать без экземпляра объекта. В случае, когда это одновременно static
и abstract
, функциональность не будет существовать в родительском классе, но будет реализована в его подклассе.
- person Pacerier; 10.09.2014
T1 Parent.F1(T2 x)
Когда мы назовем его реализацией подкласса T1 Child.F1(T2 x)
, не будет исключений во время выполнения, так почему вы говорите, что у нас будут исключения во время выполнения? Кроме того, весь смысл абстрактного метода в том, что вам не нужно знать, реализован он или нет. Класс подкласса будет реализовывать это, а подкласс будет гарантировать, что контракт Лискова T1 Parent.F1(T2 x)
сохраняется. Если подкласса нет, в любом случае не о чем беспокоиться, поскольку абстрактный метод может быть вызван только для подкласса.
- person Pacerier; 10.09.2014
A
с методом static
main(String[] args)
и класс B
с static
main(String[] args) throws Exception
. И это привело к ошибке компилятора: не удалось переопределить метод.
- person MC Emperor; 30.09.2014
obj_child.StaticF()
. Итак, ваш опыт работы с Java заставил вас задуматься, но тогда он не должен был быть статичным; и ответ, который мы даем, является, но тогда он не обязательно должен быть нестатическим. Статический - это вариант по умолчанию для методов. Только методы, которые ссылаются на экземпляры объектов, должны быть объявлены нестатическими. Например, если мы .......................... .................................................. .....
- person Pacerier; 25.10.2014
f(){ return "hello world"; }
, он должен быть статическим, потому что нет ссылочного экземпляра объекта. Но если у нас есть метод f(){ return "hello world " + this.Name; }
, он должен быть нестатическим, потому что имеется ссылка на экземпляр объекта. Статический всегда должен быть параметром по умолчанию. В Java мы вынуждены объявлять статические методы нестатическими, потому что статическое наследование в Java нарушено. Это языковой недостаток, как заявил Эрик.
- person Pacerier; 25.10.2014
f(){ return "hello world"; }
. У вас есть два варианта. 1) Сделайте его статичным. 2) Сделайте его нестатичным. Что вы выберете, а какое по умолчанию?
- person Pacerier; 26.10.2014
f(){ return "hello world"; }
, нестатической, потому что, делая это, вы излишне соединили их вместе. с переменной this
. Гибкость, о которой вы говорите, является нарушением слабой связи. Это так же плохо, как гибкость, которую вы получаете, объявляя все поля и методы как public
.
- person Pacerier; 26.10.2014
Плохой языковой дизайн. Было бы гораздо эффективнее вызывать статический абстрактный метод напрямую, чем создавать экземпляр только для использования этого абстрактного метода. Это особенно актуально при использовании абстрактного класса в качестве обходного пути для невозможности расширения enum, что является еще одним неудачным примером дизайна. Надеюсь, они устранят эти ограничения в следующем выпуске.
static
уже является нарушением ....
- person Pacerier; 10.09.2014
Вы не можете переопределить статический метод, поэтому делать его абстрактным было бы бессмысленно. Более того, статический метод в абстрактном классе будет принадлежать этому классу, а не классу переопределения, поэтому его все равно нельзя использовать.
Я тоже задал тот же вопрос, вот почему
Поскольку абстрактный класс говорит, он не будет предоставлять реализацию и позволяет подклассу предоставлять ее
поэтому подкласс должен переопределить методы суперкласса,
ПРАВИЛО № 1 - Статический метод нельзя переопределить
Поскольку статические члены и методы являются элементами времени компиляции, поэтому разрешена перегрузка (полиморфизм времени компиляции) статических методов, а не переопределение (полиморфизм времени выполнения)
Итак, они не могут быть абстрактными.
Нет таких вещей, как абстрактная статика ‹--- Запрещено в Java Universe
abstract static
см. stackoverflow.com/questions/370962/. Настоящая причина, почему Java не позволяет переопределять статические методы, заключается в том, что Java не позволяет переопределять статические методы.
- person Pacerier; 10.09.2014
foo(String)
не то же самое, что foo(Integer)
- вот и все.
- person Captain Man; 15.12.2016
Это ужасный языковой дизайн, и на самом деле это не причина, почему это невозможно.
Фактически, вот реализация того, как это МОЖНО сделать в 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();
}
abstract static
, как задано в вопросе, и вы написали жирным шрифтом МОЖНО СДЕЛАТЬ В JAVA. Это полное заблуждение.
- person Blip; 28.06.2017
Абстрактный метод определяется только для того, чтобы его можно было переопределить в подклассе. Однако статические методы нельзя переопределить. Следовательно, наличие абстрактного статического метода является ошибкой времени компиляции.
Теперь следующий вопрос: почему статические методы нельзя переопределить ??
Это потому, что статические методы принадлежат определенному классу, а не его экземпляру. Если вы попытаетесь переопределить статический метод, вы не получите никаких ошибок компиляции или выполнения, но компилятор просто скроет статический метод суперкласса.
Статический метод по определению не должен знать this
. Таким образом, это не может быть виртуальный метод (который перегружен в соответствии с информацией о динамическом подклассе, доступной через this
); вместо этого перегрузка статического метода основана исключительно на информации, доступной во время компиляции (это означает: как только вы ссылаетесь на статический метод суперкласса, вы вызываете именно метод суперкласса, но никогда метод подкласса).
В соответствии с этим абстрактные статические методы были бы совершенно бесполезны, потому что вы никогда не будете заменять его ссылку каким-либо определенным телом.
Абстрактный класс не может иметь статический метод, потому что абстракция выполняется для достижения ДИНАМИЧЕСКОЙ ПРИВЯЗКИ, в то время как статические методы статически привязаны к своей функциональности. Статический метод означает поведение, не зависящее от переменной экземпляра, поэтому экземпляр / объект не требуется. Только класс. Статические методы принадлежат классу, а не объекту. Они хранятся в области памяти, известной как PERMGEN, откуда они используются для всех объектов. Методы абстрактного класса динамически привязаны к своей функциональности.
Я вижу, что уже есть миллионы ответов, но я не вижу никаких практических решений. Конечно, это настоящая проблема, и нет веских причин для исключения этого синтаксиса в 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();
}
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
метода.
Объявление метода как static
означает, что мы можем вызвать этот метод по имени его класса, и если этот класс также abstract
, нет смысла вызывать его, поскольку он не содержит тела, и, следовательно, мы не можем объявить метод одновременно как static
и abstract
.
getSimpleName()
. Мы хотим иметь abstract static String getClassName();
и расширить его на все дочерние классы.
- person CoolMind; 19.11.2020
Поскольку абстрактные методы принадлежат классу и не могут быть переопределены реализующим классом, даже если существует статический метод с такой же сигнатурой, он скрывает метод, а не переопределяет его. Таким образом, не имеет значения объявить абстрактный метод статическим, поскольку он никогда не получит тело. Таким образом, возникнет ошибка времени компиляции.
Статический метод можно вызвать без экземпляра класса. В вашем примере вы можете вызвать foo.bar2 (), но не foo.bar (), потому что для bar вам нужен экземпляр. Следующий код будет работать:
foo var = new ImplementsFoo();
var.bar();
Если вы вызываете статический метод, он всегда будет выполняться с одним и тем же кодом. В приведенном выше примере, даже если вы переопределите bar2 в ImplementsFoo, вызов var.bar2 () приведет к выполнению foo.bar2 ().
Если bar2 теперь не имеет реализации (что означает абстрактное), вы можете вызвать метод без реализации. Это очень вредно.
Я считаю, что нашел ответ на этот вопрос в виде того, почему методы интерфейса (которые работают как абстрактные методы в родительском классе) не могут быть статическими. Вот полный ответ (не мой)
В основном статические методы могут быть привязаны во время компиляции, поскольку для их вызова вам необходимо указать класс. Это отличается от методов экземпляра, для которых класс ссылки, из которой вы вызываете метод, может быть неизвестен во время компиляции (таким образом, какой блок кода вызывается, можно определить только во время выполнения).
Если вы вызываете статический метод, вы уже знаете класс, в котором он реализован, или любые его прямые подклассы. Если вы определите
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 определяет, какой блок кода он должен выполнить (первая часть моего ответа).
Поскольку абстрактный класс является концепцией 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
}
Идея наличия абстрактного статического метода заключалась бы в том, что вы не можете использовать этот конкретный абстрактный класс напрямую для этого метода, но только первая производная будет разрешена для реализации этого статического метода (или для дженериков: фактический класс универсального вы использовать).
Таким образом, вы можете создать, например, абстрактный класс 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 может еще не быть элементов, но уже необходимо обеспечить предпочтительную сортировку.
Чирио, Олаф.
Во-первых, ключевой момент об абстрактных классах - абстрактный класс не может быть создан (см. вики). Итак, вы не можете создать любой экземпляр абстрактного класса.
Теперь способ, которым Java работает со статическими методами, - это совместное использование метода со всеми экземплярами этого класса.
Итак, если вы не можете создать экземпляр класса, этот класс не может иметь абстрактных статических методов, поскольку абстрактный метод требует расширения.
Бум.
Согласно 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));
}
}
Потому что «абстрактный» означает, что метод предназначен для переопределения, и нельзя переопределить «статические» методы.
Обычные методы могут быть абстрактными, если они предназначены для переопределения подклассами и обеспечения функциональных возможностей. Представьте, что класс Foo
расширен на Bar1, Bar2, Bar3
и т. Д. Итак, у каждого будет своя собственная версия абстрактного класса в соответствии с их потребностями.
Теперь статические методы по определению принадлежат классу, они не имеют ничего общего с объектами класса или объектами его подклассов. Им даже не нужно, чтобы они существовали, их можно использовать без создания экземпляров классов. Следовательно, они должны быть готовы к использованию и не могут зависеть от подклассов для добавления к ним функциональности.
Поскольку abstract - это ключевое слово, которое применяется к абстрактным методам, не указывается тело. И если мы говорим о статическом ключевом слове, оно относится к области класса.
потому что, если вы используете какой-либо статический член или статическую переменную в классе, он будет загружаться во время загрузки класса.
Вы можете сделать это с помощью интерфейсов в Java 8.
Это официальная документация по этому поводу:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
Потому что, если класс расширяет абстрактный класс, он должен переопределить абстрактные методы, и это обязательно. И поскольку статические методы - это методы класса, разрешенные во время компиляции, тогда как переопределенные методы - это методы экземпляра, разрешенные во время выполнения и следующие динамическому полиморфизму.