Pytanie w Javie, dlaczego nie mogę zdefiniować abstrakcyjnej metody statycznej? na przykład
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Pytanie w Javie, dlaczego nie mogę zdefiniować abstrakcyjnej metody statycznej? na przykład
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Odpowiedzi:
Ponieważ „streszczenie” oznacza: „Nie implementuje żadnej funkcji”, a „statyczny” oznacza: „Istnieje funkcjonalność, nawet jeśli nie masz instancji obiektu”. I to jest logiczna sprzeczność.
abstract static
miałaby doskonały sens. Byłaby to metoda samego obiektu klasy, którą obiekty podklasy muszą zaimplementować. Oczywiście sposób, w jaki stoją twoje odpowiedzi, jest prawidłowy, mimo że mam obsesję na punkcie języka.
abstract static
: Funkcja X, która jest „zaimplementowana w podklasie”, nie może być jednocześnie „wykonana na klasie” - tylko na podklasie . Gdzie to nie jest już abstrakcyjne.
static
nie oznacza „niepusty” - to tylko konsekwencja tego, że Java nie pozwala abstrakcyjnym metodom statycznym. Oznacza to „możliwe do wywołania w klasie”. (Powinno to oznaczać „wywołanie tylko w klasie”, ale to już inna kwestia.) Jeśli abstract static
metody obsługiwane przez Javę oczekiwałbym, że będzie to oznaczać, że metoda 1) musi być zaimplementowana przez podklasy, a 2) jest metodą klasy podklasy. Niektóre metody po prostu nie mają sensu jako metody instancji. Niestety Java nie pozwala na określenie tego podczas tworzenia abstrakcyjnej klasy bazowej (lub interfejsu).
Słaby wygląd języka. O wiele bardziej efektywne byłoby bezpośrednie wywoływanie statycznej metody abstrakcyjnej niż tworzenie instancji wyłącznie w celu użycia tej metody abstrakcyjnej. Jest to szczególnie prawdziwe, gdy używa się klasy abstrakcyjnej jako obejścia niemożności rozszerzenia enum, co jest kolejnym złym przykładem projektu. Mam nadzieję, że rozwiążą te ograniczenia w następnym wydaniu.
static
samego siebie jest już naruszeniem ....
Nie można zastąpić metody statycznej, więc uczynienie jej abstrakcyjną byłoby bez znaczenia. Co więcej, metoda statyczna w klasie abstrakcyjnej należałaby do tej klasy, a nie do klasy nadrzędnej, więc i tak nie można jej użyć.
abstract
Adnotacji do metody wskazuje, że metoda musi być nadpisane w podklasie.
W Javie static
elementu (metody lub pola) nie można zastąpić podklasami (niekoniecznie jest to prawda w innych językach obiektowych, patrz SmallTalk.) Element static
członkowski może być ukryty , ale zasadniczo różni się od przesłaniania .
Ponieważ elementów statycznych nie można zastąpić w podklasie, abstract
adnotacja nie może zostać do nich zastosowana.
Nawiasem mówiąc - inne języki obsługują dziedziczenie statyczne, podobnie jak dziedziczenie instancji. Z perspektywy składni te języki zwykle wymagają włączenia nazwy klasy do instrukcji. Na przykład w Javie, przy założeniu, że piszesz kod w klasie A, są to równoważne instrukcje (jeśli metoda A () jest metodą statyczną i nie ma metody instancji o tej samej sygnaturze):
ClassA.methodA();
i
methodA();
W SmallTalk nazwa klasy nie jest opcjonalna, więc składnia jest następująca (zwróć uwagę, że SmallTalk nie używa. Do oddzielenia „podmiotu” i „czasownika”, ale zamiast tego używa go jako terminatora statemend):
ClassA methodA.
Ponieważ nazwa klasy jest zawsze wymagana, poprawną „wersję” metody można zawsze ustalić, przechodząc przez hierarchię klas. Za to, co warto, czasami tęsknięstatic
dziedziczenia i ugryziony przez brak statycznego dziedziczenia w Javie, kiedy zaczynałem od niego. Dodatkowo SmallTalk jest typu kaczego (i dlatego nie obsługuje programu według umowy). Zatem nie ma abstract
modyfikatora dla członków klasy.
Zadałem również to samo pytanie, oto dlaczego
Ponieważ klasa Abstract mówi, nie da implementacji i nie pozwoli na jej podklasę
więc podklasa musi zastąpić metody nadklasy,
ZASADA 1 - Nie można zastąpić metody statycznej
Ponieważ elementy i metody statyczne są elementami czasu kompilacji, dlatego przeciążanie (polimorfizm czasu kompilacji) metod statycznych jest dozwolone zamiast zastępowania (polimorfizm środowiska uruchomieniowego)
Więc nie mogą być abstrakcyjni.
Nie ma czegoś takiego jak abstrakcyjny statyczny <--- Niedozwolone w Java Universe
abstract static
zobaczyć stackoverflow.com/questions/370962/... . Prawdziwy powód dlaczego Java nie pozwala metody statyczne być zastąpiona jest ponieważ Java nie pozwala metody statyczne być nadpisane.
foo(String)
to nie to samo, co foo(Integer)
- to wszystko.
To okropny projekt językowy i naprawdę nie ma powodu, dla którego to niemożliwe.
W rzeczywistości oto implementacja tego, jak MOŻNA to zrobić w 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;
}
}
}
================= Stary przykład poniżej =================
Poszukaj getRequest i getRequestImpl ... setInstance można wywołać w celu zmiany implementacji przed wykonaniem wywołania.
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();
}
}
}
Używane w następujący sposób:
static {
Core.setSingleton(new Core.CoreDefaultImpl());
// Or
Core.setSingleton(new Core.CoreTestImpl());
// Later in the application you might use
Core.getRequest();
}
abstract static
metody zadanej w pytaniu i napisałeś pogrubioną czcionką MOŻNA ZROBIĆ W JAVA . To całkowicie mylące.
Metodę abstrakcyjną definiuje się tylko po to, aby można ją było zastąpić w podklasie. Jednak metod statycznych nie można zastąpić. Dlatego posiadanie abstrakcyjnej, statycznej metody jest błędem podczas kompilacji.
Teraz następne pytanie brzmi: dlaczego nie można zastąpić metod statycznych?
Jest tak, ponieważ metody statyczne należą do konkretnej klasy, a nie do jej instancji. Jeśli spróbujesz zastąpić metodę statyczną, nie pojawi się żaden błąd kompilacji ani środowiska wykonawczego, ale kompilator po prostu ukryje metodę statyczną nadklasy.
Metoda statyczna z definicji nie musi wiedzieć this
. Zatem nie może to być metoda wirtualna (która jest przeciążona zgodnie z informacjami dynamicznej podklasy dostępnymi za pośrednictwem this
); zamiast tego przeciążenie metody statycznej opiera się wyłącznie na informacjach dostępnych w czasie kompilacji (oznacza to: po odwołaniu się do statycznej metody nadklasy wywołuje się metodę nadklasy, ale nigdy metodę podklasy).
Zgodnie z tym abstrakcyjne metody statyczne byłyby zupełnie bezużyteczne, ponieważ nigdy nie zastąpi się odniesienia przez jakieś określone ciało.
Widzę, że istnieją już bogie odpowiedzi, ale nie widzę żadnych praktycznych rozwiązań. Oczywiście jest to prawdziwy problem i nie ma dobrego powodu, aby wykluczyć tę składnię w Javie. Ponieważ w pierwotnym pytaniu brakuje kontekstu, w którym może to być potrzebne, przedstawiam zarówno kontekst, jak i rozwiązanie:
Załóżmy, że masz metodę statyczną w grupie identycznych klas. Te metody nazywają metodę statyczną specyficzną dla klasy:
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()
metody C1
i C2
są identyczne. Może istnieć wiele takich przypadków: C3
C4
itd. Gdyby static abstract
było to dozwolone, wyeliminowałbyś duplikat kodu, wykonując coś takiego:
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
}
}
ale nie skompiluje się, ponieważ static abstract
kombinacja nie jest dozwolona. Można to jednak obejść za pomocą static class
konstrukcji, która jest dozwolona:
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();
}
}
Dzięki temu rozwiązaniu jedynym zduplikowanym kodem jest
public static void doWork() {
c.doWork();
}
C1.doWork()
lub C2.doWork()
Ale nie możesz zadzwonić C.doWork()
. Również w podanym przez ciebie przykładzie, który nie będzie działał, załóżmy, że gdyby było dozwolone, to w jaki sposób klasa C
znajdzie implementację doMoreWork()
? Na koniec nazwałbym twój kod kontekstowy złym projektem. Dlaczego? po prostu dlatego, że utworzono osobną funkcję dla kodu, która jest unikalna, zamiast tworzyć funkcję dla kodu, który jest wspólny, a następnie implementować funkcję statyczną w klasie C
. To jest łatwiejsze !!!
Załóżmy, że istnieją dwie klasy Parent
i Child
. Parent
jest abstract
. Deklaracje są następujące:
abstract class Parent {
abstract void run();
}
class Child extends Parent {
void run() {}
}
Oznacza to, że każde wystąpienie Parent
musi określać sposób run()
wykonania.
Załóżmy jednak, że Parent
tak nie jest abstract
.
class Parent {
static void run() {}
}
Oznacza to, że Parent.run()
wykona metodę statyczną.
Definicja abstract
metody to „Metoda zadeklarowana, ale nie zaimplementowana”, co oznacza, że sama niczego nie zwraca.
Definicja static
metody to „Metoda, która zwraca tę samą wartość dla tych samych parametrów bez względu na instancję, w której jest wywoływana”.
An abstract
wartość zwracana METHOD może ulec zmianie wraz ze zmianami instancji. static
Metoda nie będzie. static abstract
Metoda jest dość dużo metoda, w której wartość zwracana jest stała, ale niczego nie powrócić. To logiczna sprzeczność.
Poza tym static abstract
metoda nie ma zbyt wiele powodów .
Klasa abstrakcyjna nie może mieć metody statycznej, ponieważ abstrakcja jest wykonywana w celu osiągnięcia WIĄZANIA DYNAMICZNEGO, podczas gdy metody statyczne są statycznie powiązane z ich funkcjonalnością. Metoda statyczna oznacza zachowanie niezależne od zmiennej instancji, więc nie jest wymagana żadna instancja / obiekt. Tylko klasa. Metody statyczne należą do klasy, a nie do obiektu. Są one przechowywane w obszarze pamięci znanym jako PERMGEN, skąd jest współdzielony z każdym obiektem. Metody w klasie abstrakcyjnej są dynamicznie powiązane z ich funkcjonalnością.
Deklaracja metody jako static
oznacza, że możemy wywołać tę metodę po nazwie klasy, a jeśli ta klasa abstract
również jest, nie ma sensu nazywać go, ponieważ nie zawiera on żadnego ciała, a zatem nie możemy zadeklarować metody zarówno jako, jak static
i abstract
.
Ponieważ metody abstrakcyjne należą do klasy i nie mogą zostać zastąpione przez klasę implementującą, nawet jeśli istnieje metoda statyczna z tym samym podpisem, ukrywa metodę, nie zastępując jej. Nie ma zatem znaczenia, aby deklarować metodę abstrakcyjną jako statyczną, ponieważ nigdy nie otrzyma ona ciała, dlatego też błąd czasu kompilacji.
Metodę statyczną można wywołać bez wystąpienia klasy. W twoim przykładzie możesz wywołać foo.bar2 (), ale nie foo.bar (), ponieważ dla bar potrzebujesz instancji. Działa następujący kod:
foo var = new ImplementsFoo();
var.bar();
Wywołanie metody statycznej spowoduje wykonanie zawsze tego samego kodu. W powyższym przykładzie, nawet jeśli przedefiniujesz bar2 w ImplementsFoo, wywołanie var.bar2 () wykona foo.bar2 ().
Jeśli bar2 nie ma teraz implementacji (to znaczy streszczenie), możesz wywołać metodę bez implementacji. To bardzo szkodliwe.
Wydaje mi się, że znalazłem odpowiedź na to pytanie w postaci tego, dlaczego metody interfejsu (które działają jak metody abstrakcyjne w klasie nadrzędnej) nie mogą być statyczne. Oto pełna odpowiedź (nie moja)
Zasadniczo metody statyczne można wiązać w czasie kompilacji, ponieważ aby je wywołać, należy określić klasę. Różni się to od metod instancji, dla których klasa odwołania, z którego wywołujesz metodę, może być nieznana w czasie kompilacji (dlatego który blok kodu jest wywoływany, można określić tylko w czasie wykonywania).
Jeśli wywołujesz metodę statyczną, znasz już klasę, w której jest ona zaimplementowana, lub wszelkie jej bezpośrednie podklasy. Jeśli zdefiniujesz
abstract class Foo {
abstract static void bar();
}
class Foo2 {
@Override
static void bar() {}
}
Wtedy każde Foo.bar();
połączenie jest oczywiście nielegalne i zawsze będziesz używać Foo2.bar();
.
Mając to na uwadze, jedynym celem statycznej abstrakcyjnej metody byłoby wymuszenie podklas w celu wdrożenia takiej metody. Na początku możesz pomyśleć, że jest to BARDZO złe, ale jeśli masz parametr typu ogólnego, <E extends MySuperClass>
dobrze byłoby zagwarantować za pośrednictwem interfejsu, który E
może .doSomething()
. Należy pamiętać, że ze względu na wymazywanie typów, generycy istnieją tylko w czasie kompilacji.
Czy byłoby to przydatne? Tak, a może dlatego Java 8 zezwala na metody statyczne w interfejsach (choć tylko z domyślną implementacją). Dlaczego nie abstrakcyjne metody statyczne z domyślną implementacją w klasach? Po prostu dlatego, że abstrakcyjna metoda z domyślną implementacją jest w rzeczywistości konkretną metodą.
Dlaczego nie abstrakcyjne / statyczne metody interfejsu bez domyślnej implementacji? Najwyraźniej tylko z powodu sposobu, w jaki Java identyfikuje blok kodu, który musi wykonać (pierwsza część mojej odpowiedzi).
Ponieważ klasa abstrakcyjna jest koncepcją OOPS, a elementy statyczne nie są częścią OOPS ...
Teraz chodzi o to, że możemy zadeklarować statyczne pełne metody w interfejsie i możemy wykonać interfejs, deklarując główną metodę wewnątrz interfejsu
interface Demo
{
public static void main(String [] args) {
System.out.println("I am from interface");
}
}
Idea posiadania abstrakcyjnej metody statycznej polegałaby na tym, że nie można użyć tej konkretnej klasy abstrakcyjnej bezpośrednio dla tej metody, ale tylko pierwsza pochodna może zaimplementować tę metodę statyczną (lub dla ogólnych: rzeczywistej klasy ogólnej posługiwać się).
W ten sposób można na przykład utworzyć klasę abstrakcyjną sortableObject lub nawet interfejs z (automatycznymi) abstrakcyjnymi metodami statycznymi, która określa parametry opcji sortowania:
public interface SortableObject {
public [abstract] static String [] getSortableTypes();
public String getSortableValueByType(String type);
}
Teraz możesz zdefiniować sortowalny obiekt, który można sortować według głównych typów, które są takie same dla wszystkich tych obiektów:
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
}
}
Teraz możesz utworzyć
public class SortableList<T extends SortableObject>
który może pobierać typy, zbudować menu podręczne, aby wybrać typ do sortowania i posortować listę, pobierając dane z tego typu, a także uzyskać funkcję dodawania, która po wybraniu typu sortowania może automatycznie -sortuj nowe elementy w. Zauważ, że instancja SortableList może bezpośrednio uzyskać dostęp do metody statycznej „T”:
String [] MenuItems = T.getSortableTypes();
Problem z koniecznością użycia instancji polega na tym, że SortableList może jeszcze nie zawierać elementów, ale już musi zapewnić preferowane sortowanie.
Cheerio, Olaf.
Po pierwsze, kluczowy punkt dotyczący klas abstrakcyjnych - nie można utworzyć instancji klasy abstrakcyjnej (patrz wiki ). Dlatego nie można utworzyć żadnego wystąpienia klasy abstrakcyjnej.
Teraz sposób, w jaki Java radzi sobie z metodami statycznymi, polega na udostępnianiu metody wszystkim instancjom tej klasy.
Jeśli więc nie można utworzyć instancji klasy, klasa ta nie może mieć abstrakcyjnych metod statycznych, ponieważ metoda abstrakcyjna zaczyna być rozszerzana.
Bum.
Zgodnie z dokumentacją Java :
Metoda statyczna to metoda powiązana z klasą, w której jest zdefiniowana, a nie z dowolnym obiektem. Każda instancja klasy ma wspólne metody statyczne
W Javie 8 wraz z domyślnymi metodami dozwolone są również metody statyczne w interfejsie. Ułatwia nam to organizowanie metod pomocniczych w naszych bibliotekach. Możemy zachować metody statyczne specyficzne dla interfejsu w tym samym interfejsie, a nie w osobnej klasie.
Dobrym przykładem tego jest:
list.sort(ordering);
zamiast
Collections.sort(list, ordering);
Inny przykład użycia metod statycznych podano również w samym dokumencie :
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));
}
}
Ponieważ „streszczenie” oznacza, że metoda ma być nadpisana i nie można zastąpić metod „statycznych”.
Zwykłe metody mogą być abstrakcyjne, gdy mają być zastąpione przez podklasy i wyposażone w funkcje. Wyobraź sobie, że klasa Foo
jest przedłużonaBar1, Bar2, Bar3
itd. Tak więc każda z nich będzie miała własną wersję klasy abstrakcyjnej zgodnie z własnymi potrzebami.
Otóż metody statyczne z definicji należą do klasy, nie mają one nic wspólnego z obiektami klasy ani obiektami jej podklas. Nie potrzebują nawet ich istnienia, można z nich korzystać bez tworzenia instancji klas. Dlatego muszą być gotowe do pracy i nie mogą zależeć od podklas, aby dodać im funkcjonalność.
Ponieważ streszczenie jest słowem kluczowym stosowanym nad metodami abstrakcyjnymi, nie określają treści. A jeśli mówimy o statycznym słowie kluczowym, należy ono do obszaru klasy.
Możesz to zrobić za pomocą interfejsów w Javie 8.
Oto oficjalna dokumentacja na ten temat:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
Ponieważ jeśli klasa rozszerza klasę abstrakcyjną, musi zastąpić metody abstrakcyjne, co jest obowiązkowe. A ponieważ metody statyczne są metodami klasy rozstrzyganymi w czasie kompilacji, podczas gdy metody zastępowane są metodami instancji rozwiązywanymi w czasie wykonywania i po dynamicznym polimorfizmie.