La domanda è in Java perché non posso definire un metodo statico astratto? per esempio
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
La domanda è in Java perché non posso definire un metodo statico astratto? per esempio
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Risposte:
Perché "astratto" significa: "Non implementa alcuna funzionalità" e "statico" significa: "Esiste funzionalità anche se non si dispone di un'istanza di oggetto". E questa è una contraddizione logica.
abstract static
avrebbe perfettamente senso. Sarebbe un metodo dell'oggetto classe stesso che gli oggetti della sottoclasse devono implementare. Certo, il modo in cui le cose stanno la tua risposta è corretto, nonostante la mia presa sulla lingua.
abstract static
: Una funzione X che viene "implementato nella sottoclasse" non può al tempo stesso essere "eseguito sulla classe" - solo sulla sottoclasse . Dove quindi non è più astratto.
static
non significa "non vuoto" - questa è solo una conseguenza di Java che non consente ai metodi statici di essere astratti. Significa "richiamabile sulla classe". (Dovrebbe significare "richiamabile solo sulla classe" ma questo è un altro problema.) Se i abstract static
metodi supportati da Java mi aspetto che significhi che il metodo 1) deve essere implementato da sottoclassi e 2) è un metodo di classe della sottoclasse. Alcuni metodi semplicemente non hanno senso come metodi di istanza. Sfortunatamente Java non ti consente di specificarlo quando crei una classe base astratta (o un'interfaccia).
Design del linguaggio scadente. Sarebbe molto più efficace chiamare direttamente un metodo astratto statico rispetto alla creazione di un'istanza solo per l'utilizzo di quel metodo astratto. Soprattutto quando si utilizza una classe astratta come soluzione alternativa all'enorme incapacità di estendere, che è un altro esempio di progettazione scadente. Spero che risolvano questi limiti nella prossima versione.
static
se stesso sia già una violazione ...
Non è possibile ignorare un metodo statico, quindi renderlo astratto sarebbe privo di significato. Inoltre, un metodo statico in una classe astratta appartiene a quella classe, e non alla classe prevalente, quindi non può essere utilizzato comunque.
L' abstract
annotazione a un metodo indica che il metodo DEVE essere sostituito in una sottoclasse.
In Java, un static
membro (metodo o campo) non può essere sovrascritto da sottoclassi (questo non è necessariamente vero in altri linguaggi orientati agli oggetti, vedere SmallTalk). Un static
membro può essere nascosto , ma fondamentalmente diverso da sovrascritto .
Poiché i membri statici non possono essere sostituiti in una sottoclasse, l' abstract
annotazione non può essere applicata ad essi.
A parte questo, altre lingue supportano l'ereditarietà statica, proprio come l'ereditarietà delle istanze. Dal punto di vista della sintassi, tali lingue richiedono generalmente che il nome della classe sia incluso nell'istruzione. Ad esempio, in Java, supponendo che tu stia scrivendo codice in ClassA, si tratta di istruzioni equivalenti (se methodA () è un metodo statico e non esiste un metodo di istanza con la stessa firma):
ClassA.methodA();
e
methodA();
In SmallTalk, il nome della classe non è facoltativo, quindi la sintassi è (si noti che SmallTalk non usa il. Per separare "soggetto" e "verbo", ma invece lo usa come terminatore di stato):
ClassA methodA.
Poiché il nome della classe è sempre richiesto, la "versione" corretta del metodo può sempre essere determinata attraversando la gerarchia di classi. Per quello che vale, a volte mi manca l' static
eredità ed è stato morso dalla mancanza di eredità statica in Java quando ho iniziato con esso. Inoltre, SmallTalk è duck-type (e quindi non supporta il programma per contratto). Pertanto, non ha abstract
modificatore per i membri della classe.
Ho anche fatto la stessa domanda, ecco perché
Dal momento che dice la classe astratta, non darà l'implementazione e consentirà alla sottoclasse di fornirla
quindi la sottoclasse deve sovrascrivere i metodi di Superclass,
REGOLA N. 1 - Un metodo statico non può essere ignorato
Poiché i membri e i metodi statici sono elementi del tempo di compilazione, ecco perché sono consentiti il sovraccarico (polimorfismo del tempo di compilazione) dei metodi statici piuttosto che l'override (polimorfismo di runtime)
Quindi, non possono essere astratti.
Non esiste nulla di simile allo statico astratto <--- Non consentito nell'universo Java
abstract static
vedi stackoverflow.com/questions/370962/… . Il vero motivo per cui Java non consente l'override dei metodi statici è perché Java non consente l'override dei metodi statici.
foo(String)
non è lo stesso di foo(Integer)
- questo è tutto.
Questo è un design del linguaggio terribile e davvero nessuna ragione per cui non è possibile.
In effetti, ecco un'implementazione su come può essere fatto in 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;
}
}
}
================= Vecchio esempio di seguito =================
Cerca getRequest e getRequestImpl ... setInstance può essere chiamato per modificare l'implementazione prima di effettuare la chiamata.
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();
}
}
}
Usato come segue:
static {
Core.setSingleton(new Core.CoreDefaultImpl());
// Or
Core.setSingleton(new Core.CoreTestImpl());
// Later in the application you might use
Core.getRequest();
}
abstract static
metodo come richiesto nella domanda e hai scritto in grassetto PUO 'ESSERE FATTO IN JAVA . Questo è completamente fuorviante.
Un metodo astratto è definito solo in modo che possa essere sovrascritto in una sottoclasse. Tuttavia, i metodi statici non possono essere ignorati. Pertanto, è un errore in fase di compilazione avere un metodo astratto e statico.
Ora la domanda successiva è perché i metodi statici non possono essere ignorati ??
È perché i metodi statici appartengono a una classe particolare e non alla sua istanza. Se si tenta di sovrascrivere un metodo statico non si otterrà alcun errore di compilazione o runtime ma il compilatore nasconderebbe semplicemente il metodo statico di superclasse.
Un metodo statico, per definizione, non ha bisogno di sapere this
. Pertanto, non può essere un metodo virtuale (che viene sovraccaricato in base alle informazioni della sottoclasse dinamica disponibile attraverso this
); invece, un sovraccarico del metodo statico si basa esclusivamente sulle informazioni disponibili al momento della compilazione (questo significa: una volta che si fa riferimento a un metodo statico di superclasse, si chiama in particolare il metodo superclasse, ma mai un metodo di sottoclasse).
Secondo questo, i metodi statici astratti sarebbero del tutto inutili perché non si sostituirà mai il suo riferimento con un corpo definito.
Vedo che ci sono già un milione di risposte, ma non vedo alcuna soluzione pratica. Ovviamente questo è un vero problema e non c'è una buona ragione per escludere questa sintassi in Java. Poiché la domanda originale manca di un contesto in cui ciò potrebbe essere necessario, fornisco sia un contesto che una soluzione:
Supponiamo di avere un metodo statico in un gruppo di classi identiche. Questi metodi chiamano un metodo statico specifico della classe:
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()
i metodi in C1
e C2
sono identici. Potrebbero esserci molti di questi calsses: C3
C4
ecc. Se static abstract
fosse permesso, elimineresti il codice duplicato facendo qualcosa del tipo:
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
}
}
ma questo non si compilerebbe perché la static abstract
combinazione non è consentita. Tuttavia, questo può essere eluso con il static class
costrutto, che è consentito:
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();
}
}
Con questa soluzione l'unico codice duplicato è
public static void doWork() {
c.doWork();
}
C1.doWork()
o C2.doWork()
Ma non puoi chiamare C.doWork()
. Anche nell'esempio che hai fornito, che non funzionerà, supponi che se fosse permesso, come C
troverà l'implementazione della classe doMoreWork()
? Infine, definirei il tuo codice di contesto un cattivo design. Perché? semplicemente perché hai creato una funzione separata per il codice che è unica invece di creare una funzione per il codice comune e quindi implementare una funzione statica nella classe C
. Questo è più facile !!!
Supponiamo che ci siano due classi Parent
e Child
. Parent
lo è abstract
. Le dichiarazioni sono le seguenti:
abstract class Parent {
abstract void run();
}
class Child extends Parent {
void run() {}
}
Ciò significa che qualsiasi istanza di Parent
deve specificare come run()
viene eseguita.
Tuttavia, supponiamo ora che Parent
non lo sia abstract
.
class Parent {
static void run() {}
}
Ciò significa che Parent.run()
eseguirà il metodo statico.
La definizione di un abstract
metodo è "Un metodo dichiarato ma non implementato", il che significa che non restituisce nulla da solo.
La definizione di un static
metodo è "Un metodo che restituisce lo stesso valore per gli stessi parametri indipendentemente dall'istanza su cui è chiamato".
abstract
Il valore restituito di un metodo cambierà al variare dell'istanza. Un static
metodo no. Un static abstract
metodo è praticamente un metodo in cui il valore restituito è costante, ma non restituisce nulla. Questa è una contraddizione logica.
Inoltre, non c'è davvero molto motivo per un static abstract
metodo.
Una classe astratta non può avere un metodo statico perché l'astrazione viene eseguita per ottenere il DYNAMIC BINDING mentre i metodi statici sono associati staticamente alla loro funzionalità. Un metodo statico significa un comportamento non dipendente da una variabile di istanza, quindi non è richiesta alcuna istanza / oggetto. I metodi statici appartengono alla classe e non all'oggetto. Sono memorizzati in un'area di memoria nota come PERMGEN da cui è condivisa con ogni oggetto. I metodi in classe astratta sono legati dinamicamente alla loro funzionalità.
Dichiarare un metodo come static
mezzo che possiamo chiamare quel metodo con il nome della sua classe e se anche quella classe lo è abstract
, non ha senso chiamarlo in quanto non contiene alcun corpo, e quindi non possiamo dichiarare un metodo sia come static
e abstract
.
Poiché i metodi astratti appartengono alla classe e non possono essere sovrascritti dalla classe di implementazione. Anche se esiste un metodo statico con la stessa firma, nasconde il metodo, non lo sovrascrive. Quindi è irrilevante dichiarare statico il metodo astratto in quanto non otterrà mai il corpo. Quindi, compilare l'errore nel tempo.
Un metodo statico può essere chiamato senza un'istanza della classe. Nel tuo esempio puoi chiamare foo.bar2 (), ma non foo.bar (), perché per bar hai bisogno di un'istanza. Il seguente codice funzionerebbe:
foo var = new ImplementsFoo();
var.bar();
Se chiami un metodo statico, verrà eseguito sempre lo stesso codice. Nell'esempio sopra, anche se si ridefinisce bar2 in ImplementsFoo, una chiamata a var.bar2 () eseguirà foo.bar2 ().
Se bar2 ora non ha implementazione (questo è ciò che significa astratto), puoi chiamare un metodo senza implementazione. È molto dannoso.
Credo di aver trovato la risposta a questa domanda, nella forma del perché i metodi di un'interfaccia (che funzionano come metodi astratti in una classe genitore) non possono essere statici. Ecco la risposta completa (non la mia)
I metodi sostanzialmente statici possono essere associati al momento della compilazione, poiché per chiamarli è necessario specificare una classe. Questo è diverso dai metodi di istanza, per i quali la classe del riferimento da cui si chiama il metodo potrebbe essere sconosciuta al momento della compilazione (quindi quale blocco di codice viene chiamato può essere determinato solo in fase di esecuzione).
Se stai chiamando un metodo statico, conosci già la classe in cui è implementata o le sue sottoclassi dirette. Se lo definisci
abstract class Foo {
abstract static void bar();
}
class Foo2 {
@Override
static void bar() {}
}
Quindi ogni Foo.bar();
chiamata è ovviamente illegale e la utilizzerai sempre Foo2.bar();
.
Con questo in mente, l'unico scopo di un metodo astratto statico sarebbe quello di imporre sottoclassi per implementare tale metodo. Inizialmente potresti pensare che sia MOLTO sbagliato, ma se hai un parametro di tipo generico <E extends MySuperClass>
sarebbe bello garantirlo tramite un'interfaccia che E
possa farlo .doSomething()
. Tieni presente che a causa della cancellazione dei tipi i generici esistono solo al momento della compilazione.
Quindi sarebbe utile? Sì, e forse è per questo che Java 8 sta consentendo metodi statici nelle interfacce (anche se solo con un'implementazione predefinita). Perché non utilizzare metodi statici astratti con un'implementazione predefinita nelle classi? Semplicemente perché un metodo astratto con un'implementazione predefinita è in realtà un metodo concreto.
Perché non utilizzare metodi statici astratti / di interfaccia senza implementazione predefinita? Apparentemente, semplicemente per il modo in cui Java identifica quale blocco di codice deve eseguire (prima parte della mia risposta).
Perché la classe astratta è un concetto OOPS e i membri statici non fanno parte di OOPS ....
Ora il fatto è che possiamo dichiarare metodi statici completi nell'interfaccia e possiamo eseguire l'interfaccia dichiarando il metodo principale all'interno di un'interfaccia
interface Demo
{
public static void main(String [] args) {
System.out.println("I am from interface");
}
}
L'idea di avere un metodo statico astratto sarebbe che non puoi usare quella particolare classe astratta direttamente per quel metodo, ma solo la prima derivata potrebbe implementare quel metodo statico (o per generici: la classe effettiva del generico che tu uso).
In questo modo, è possibile creare ad esempio una classe astratta sortableObject o addirittura interfacciarsi con metodi statici (auto) astratti, che definiscono i parametri delle opzioni di ordinamento:
public interface SortableObject {
public [abstract] static String [] getSortableTypes();
public String getSortableValueByType(String type);
}
Ora puoi definire un oggetto ordinabile che può essere ordinato in base ai tipi principali che sono gli stessi per tutti questi oggetti:
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
}
}
Ora puoi creare un
public class SortableList<T extends SortableObject>
che può recuperare i tipi, creare un menu a comparsa per selezionare un tipo su cui ordinare e ricorrere all'elenco ottenendo i dati da quel tipo, nonché avere una funzione di aggiunta che, quando è stato selezionato un tipo di ordinamento, può auto -ordinare nuovi elementi in. Si noti che l'istanza di SortableList può accedere direttamente al metodo statico di "T":
String [] MenuItems = T.getSortableTypes();
Il problema con la necessità di utilizzare un'istanza è che SortableList potrebbe non avere ancora elementi, ma è già necessario fornire l'ordinamento preferito.
Cheerio, Olaf.
Innanzitutto, un punto chiave sulle classi astratte: non è possibile creare un'istanza di una classe astratta (vedere wiki ). Quindi, non puoi creare alcuna istanza di una classe astratta.
Ora, il modo in cui java gestisce i metodi statici è condividendo il metodo con tutte le istanze di quella classe.
Pertanto, se non è possibile creare un'istanza di una classe, quella classe non può avere metodi statici astratti poiché un metodo astratto chiede di essere esteso.
Boom.
Secondo il documento Java :
Un metodo statico è un metodo associato alla classe in cui è definito anziché a qualsiasi oggetto. Ogni istanza della classe condivide i suoi metodi statici
In Java 8, insieme ai metodi predefiniti, sono consentiti anche metodi statici in un'interfaccia. Questo ci facilita l'organizzazione dei metodi di supporto nelle nostre librerie. Possiamo mantenere metodi statici specifici di un'interfaccia nella stessa interfaccia piuttosto che in una classe separata.
Un bell'esempio di questo è:
list.sort(ordering);
invece di
Collections.sort(list, ordering);
Un altro esempio di utilizzo di metodi statici è riportato anche nel documento stesso:
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));
}
}
Perché "astratto" significa che il metodo deve essere ignorato e non è possibile ignorare metodi "statici".
I metodi regolari possono essere astratti quando devono essere sovrascritti da sottoclassi e dotati di funzionalità. Immagina che la classe Foo
sia estesa di Bar1, Bar2, Bar3
ecc. Quindi, ognuno avrà la propria versione della classe astratta in base alle proprie esigenze.
Ora, i metodi statici per definizione appartengono alla classe, non hanno nulla a che fare con gli oggetti della classe o gli oggetti delle sue sottoclassi. Non hanno nemmeno bisogno che esistano, possono essere usati senza creare un'istanza delle classi. Pertanto, devono essere pronti all'uso e non possono dipendere dalle sottoclassi per aggiungere funzionalità ad esse.
Perché abstract è una parola chiave che viene applicata ai metodi Abstract non specifica un corpo. E se parliamo di parola chiave statica appartiene all'area di classe.
Puoi farlo con le interfacce in Java 8.
Questa è la documentazione ufficiale al riguardo:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
Perché se una classe estende una classe astratta, deve sovrascrivere i metodi astratti e questo è obbligatorio. E poiché i metodi statici sono metodi di classe risolti in fase di compilazione, mentre i metodi sovrascritti sono metodi di istanza risolti in fase di esecuzione e seguendo il polimorfismo dinamico.