La question est en Java, pourquoi ne puis-je pas définir une méthode statique abstraite? par exemple
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
La question est en Java, pourquoi ne puis-je pas définir une méthode statique abstraite? par exemple
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Réponses:
Parce que "abstrait" signifie: "n'implémente aucune fonctionnalité" et "statique" signifie: "il y a une fonctionnalité même si vous n'avez pas d'instance d'objet". Et c'est une contradiction logique.
abstract static
aurait un sens parfait. Ce serait une méthode de l'objet de classe lui-même que les objets de sous-classe doivent implémenter. Bien sûr, la façon dont les choses se présentent, votre réponse est correcte malgré mon emprise sur la langue.
abstract static
: Une fonction X qui est "implémentée dans la sous-classe" ne peut pas en même temps "être exécutée sur la classe" - uniquement sur la sous - classe . Là où il n'est alors plus abstrait.
static
ne signifie pas "pas vide" - c'est juste une conséquence de Java qui ne permet pas aux méthodes statiques d'être abstraites. Cela signifie "appelable sur la classe". (Cela devrait signifier "appelable uniquement sur la classe" mais c'est un autre problème.) Si les abstract static
méthodes prises en charge par Java , je m'attendrais à ce que cela signifie que la méthode 1) doit être implémentée par des sous-classes, et 2) est une méthode de classe de la sous-classe. Certaines méthodes n'ont tout simplement pas de sens en tant que méthodes d'instance. Malheureusement, Java ne vous permet pas de spécifier cela lors de la création d'une classe de base abstraite (ou d'une interface).
Mauvaise conception de la langue. Il serait beaucoup plus efficace d'appeler directement une méthode abstraite statique que de créer une instance uniquement pour utiliser cette méthode abstraite. Cela est particulièrement vrai lorsque vous utilisez une classe abstraite comme solution de contournement pour l'incapacité d'énumération à s'étendre, ce qui est un autre exemple de conception médiocre. J'espère qu'ils résoudront ces limitations dans une prochaine version.
static
lui-même est déjà une violation ....
Vous ne pouvez pas remplacer une méthode statique, donc la rendre abstraite n'aurait aucun sens. De plus, une méthode statique dans une classe abstraite appartiendrait à cette classe, et non à la classe prioritaire, elle ne pourrait donc pas être utilisée de toute façon.
L' abstract
annotation à une méthode indique que la méthode DOIT être remplacée dans une sous-classe.
En Java, un static
membre (méthode ou champ) ne peut pas être remplacé par des sous-classes (ce n'est pas nécessairement vrai dans d'autres langages orientés objet, voir SmallTalk.) Un static
membre peut être masqué , mais cela est fondamentalement différent du remplacement .
Étant donné que les membres statiques ne peuvent pas être remplacés dans une sous-classe, l' abstract
annotation ne peut pas leur être appliquée.
En passant, d'autres langages prennent en charge l'héritage statique, tout comme l'héritage d'instance. Du point de vue de la syntaxe, ces langages nécessitent généralement que le nom de la classe soit inclus dans l'instruction. Par exemple, en Java, en supposant que vous écrivez du code dans ClassA, ce sont des instructions équivalentes (si methodA () est une méthode statique et qu'il n'y a pas de méthode d'instance avec la même signature):
ClassA.methodA();
et
methodA();
Dans SmallTalk, le nom de classe n'est pas facultatif, donc la syntaxe est (notez que SmallTalk n'utilise pas le. Pour séparer le "sujet" et le "verbe", mais l'utilise à la place comme terminateur de statemend):
ClassA methodA.
Étant donné que le nom de classe est toujours requis, la "version" correcte de la méthode peut toujours être déterminée en parcourant la hiérarchie des classes. Pour ce que ça vaut, je manque parfois l' static
héritage, et j'ai été mordu par le manque d'héritage statique en Java lorsque j'ai commencé avec. De plus, SmallTalk est de type canard (et ne prend donc pas en charge le programme par contrat.) Ainsi, il n'a pas de abstract
modificateur pour les membres de la classe.
J'ai aussi posé la même question, voici pourquoi
Puisque la classe Abstract dit, elle ne donnera pas d'implémentation et permettra à la sous-classe de la donner
donc Subclass doit remplacer les méthodes de Superclass,
RÈGLE NO 1 - Une méthode statique ne peut pas être remplacée
Étant donné que les membres et les méthodes statiques sont des éléments de temps de compilation, c'est pourquoi la surcharge (polymorphisme de compilation) des méthodes statiques est autorisée plutôt que la substitution (polymorphisme d'exécution)
Donc, ils ne peuvent pas être abstraits.
Il n'y a rien de tel que l' abstrait statique <--- Non autorisé dans Java Universe
abstract static
voir stackoverflow.com/questions/370962/… . La vraie raison pour laquelle Java n'autorise pas le remplacement des méthodes statiques est que Java n'autorise pas le remplacement des méthodes statiques.
foo(String)
n'est donc pas la même chose que foo(Integer)
- c'est tout.
C'est une conception de langage terrible et vraiment aucune raison pour laquelle cela ne peut pas être possible.
En fait, voici une implémentation sur la façon dont cela PEUT être fait dans 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;
}
}
}
================= Ancien exemple ci-dessous =================
Recherchez getRequest, et getRequestImpl ... setInstance peut être appelé pour modifier l'implémentation avant l'appel.
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();
}
}
}
Utilisé comme suit:
static {
Core.setSingleton(new Core.CoreDefaultImpl());
// Or
Core.setSingleton(new Core.CoreTestImpl());
// Later in the application you might use
Core.getRequest();
}
abstract static
méthode comme demandé dans la question et vous avez écrit en gras CAN BE DONE IN JAVA . C'est complètement erroné.
Une méthode abstraite n'est définie que pour pouvoir être remplacée dans une sous-classe. Cependant, les méthodes statiques ne peuvent pas être remplacées. Par conséquent, c'est une erreur de compilation d'avoir une méthode abstraite et statique.
Maintenant, la question suivante est de savoir pourquoi les méthodes statiques ne peuvent pas être remplacées.
C'est parce que les méthodes statiques appartiennent à une classe particulière et non à son instance. Si vous essayez de remplacer une méthode statique, vous n'obtiendrez aucune erreur de compilation ou d'exécution, mais le compilateur masquera simplement la méthode statique de superclasse.
Une méthode statique, par définition, n'a pas besoin de savoir this
. Ainsi, il ne peut pas s'agir d'une méthode virtuelle (qui est surchargée en fonction des informations de sous-classe dynamique disponibles via this
); au lieu de cela, une surcharge de méthode statique est uniquement basée sur les informations disponibles au moment de la compilation (cela signifie: une fois que vous référez une méthode statique de superclasse, vous appelez notamment la méthode de superclasse, mais jamais une méthode de sous-classe).
Selon cela, les méthodes statiques abstraites seraient tout à fait inutiles car vous n'aurez jamais sa référence substituée par un corps défini.
Je vois qu'il y a déjà un dieu-zillion de réponses mais je ne vois pas de solutions pratiques. Bien sûr, c'est un vrai problème et il n'y a aucune bonne raison d'exclure cette syntaxe en Java. Étant donné que la question d'origine manque de contexte où cela peut être nécessaire, je fournis à la fois un contexte et une solution:
Supposons que vous ayez une méthode statique dans un groupe de classes identiques. Ces méthodes appellent une méthode statique spécifique à la 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()
dans C1
et C2
sont identiques. Il peut y avoir beaucoup de ces calsses: C3
C4
etc. Si static abstract
c'était autorisé, vous élimineriez le code en double en faisant quelque chose comme:
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
}
}
mais cela ne compilerait pas car la static abstract
combinaison n'est pas autorisée. Cependant, cela peut être contourné avec la static class
construction, ce qui est autorisé:
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();
}
}
Avec cette solution, le seul code dupliqué est
public static void doWork() {
c.doWork();
}
C1.doWork()
ou C2.doWork()
Mais vous ne pouvez pas appeler C.doWork()
. Toujours dans l'exemple que vous avez fourni, qui ne fonctionnera pas, supposez que cela ait été autorisé, alors comment la classe C
trouvera-t-elle l'implémentation de doMoreWork()
? Enfin, j'appellerais votre code de contexte une mauvaise conception. Pourquoi? tout simplement parce que vous avez créé une fonction distincte pour le code qui est unique au lieu de créer une fonction pour le code qui est commun, puis d'implémenter une fonction statique dans la classe C
. C'est plus facile !!!
Supposons qu'il existe deux classes, Parent
et Child
. Parent
est abstract
. Les déclarations sont les suivantes:
abstract class Parent {
abstract void run();
}
class Child extends Parent {
void run() {}
}
Cela signifie que toute instance de Parent
doit spécifier comment run()
est exécutée.
Cependant, supposez maintenant que ce Parent
n'est pas le cas abstract
.
class Parent {
static void run() {}
}
Cela signifie que Parent.run()
va exécuter la méthode statique.
La définition d'une abstract
méthode est "Une méthode déclarée mais non implémentée", ce qui signifie qu'elle ne retourne rien elle-même.
La définition d'une static
méthode est "Une méthode qui renvoie la même valeur pour les mêmes paramètres quelle que soit l'instance sur laquelle elle est appelée".
abstract
La valeur de retour d' une méthode change à mesure que l'instance change. Une static
méthode ne le fera pas. Une static abstract
méthode est à peu près une méthode où la valeur de retour est constante, mais ne renvoie rien. C'est une contradiction logique.
De plus, il n'y a vraiment pas beaucoup de raison pour une static abstract
méthode.
Une classe abstraite ne peut pas avoir de méthode statique car l'abstraction est effectuée pour obtenir une LIAISON DYNAMIQUE alors que les méthodes statiques sont liées statiquement à leur fonctionnalité.Une méthode statique signifie un comportement ne dépendant pas d'une variable d'instance, donc aucune instance / objet n'est requis.Juste la classe. Les méthodes statiques appartiennent à la classe et non à l'objet. Ils sont stockés dans une zone mémoire appelée PERMGEN d'où ils sont partagés avec chaque objet. Les méthodes de la classe abstraite sont liées dynamiquement à leur fonctionnalité.
Déclarer une méthode static
signifie que nous pouvons l'appeler par son nom de classe et si cette classe l'est abstract
également, cela n'a aucun sens de l'appeler car elle ne contient aucun corps, et donc nous ne pouvons pas déclarer une méthode à la fois comme static
et abstract
.
Comme les méthodes abstraites appartiennent à la classe et ne peuvent pas être remplacées par la classe d'implémentation, même s'il existe une méthode statique avec la même signature, elle masque la méthode, ne la remplace pas. Il est donc indifférent de déclarer la méthode abstraite comme statique car elle n'obtiendra jamais le corps. Ainsi, compiler l'erreur de temps.
Une méthode statique peut être appelée sans instance de la classe. Dans votre exemple, vous pouvez appeler foo.bar2 (), mais pas foo.bar (), car pour bar, vous avez besoin d'une instance. Le code suivant fonctionnerait:
foo var = new ImplementsFoo();
var.bar();
Si vous appelez une méthode statique, elle sera toujours exécutée avec le même code. Dans l'exemple ci-dessus, même si vous redéfinissez bar2 dans ImplementsFoo, un appel à var.bar2 () exécuterait foo.bar2 ().
Si bar2 n'a maintenant aucune implémentation (c'est ce que signifie abstrait), vous pouvez appeler une méthode sans implémentation. C'est très dangereux.
Je crois avoir trouvé la réponse à cette question, sous la forme de pourquoi les méthodes d'une interface (qui fonctionnent comme des méthodes abstraites dans une classe parente) ne peuvent pas être statiques. Voici la réponse complète (pas la mienne)
Les méthodes essentiellement statiques peuvent être liées au moment de la compilation, car pour les appeler, vous devez spécifier une classe. Ceci est différent des méthodes d'instance, pour lesquelles la classe de la référence à partir de laquelle vous appelez la méthode peut être inconnue au moment de la compilation (ainsi, quel bloc de code est appelé ne peut être déterminé qu'au moment de l'exécution).
Si vous appelez une méthode statique, vous connaissez déjà la classe où elle est implémentée, ou ses sous-classes directes. Si vous définissez
abstract class Foo {
abstract static void bar();
}
class Foo2 {
@Override
static void bar() {}
}
Ensuite, tout Foo.bar();
appel est évidemment illégal et vous l'utiliserez toujours Foo2.bar();
.
Dans cet esprit, le seul but d'une méthode abstraite statique serait d'imposer des sous-classes pour implémenter une telle méthode. Vous pourriez initialement penser que c'est TRÈS faux, mais si vous avez un paramètre de type générique, <E extends MySuperClass>
ce serait bien de garantir via une interface qui le E
peut .doSomething()
. Gardez à l'esprit qu'en raison du type d'effacement, les génériques n'existent qu'au moment de la compilation.
Alors, serait-ce utile? Oui, et c'est peut-être pour cela que Java 8 autorise les méthodes statiques dans les interfaces (mais uniquement avec une implémentation par défaut). Pourquoi pas des méthodes statiques abstraites avec une implémentation par défaut dans les classes? Tout simplement parce qu'une méthode abstraite avec une implémentation par défaut est en fait une méthode concrète.
Pourquoi pas des méthodes statiques abstraites / d'interface sans implémentation par défaut? Apparemment, simplement à cause de la façon dont Java identifie le bloc de code à exécuter (première partie de ma réponse).
Parce que la classe abstraite est un concept OOPS et que les membres statiques ne font pas partie d'OOPS ....
Maintenant, le problème est que nous pouvons déclarer des méthodes complètes statiques dans l'interface et nous pouvons exécuter l'interface en déclarant la méthode principale à l'intérieur d'une interface
interface Demo
{
public static void main(String [] args) {
System.out.println("I am from interface");
}
}
L'idée d'avoir une méthode statique abstraite serait que vous ne pouvez pas utiliser cette classe abstraite particulière directement pour cette méthode, mais seule la dérivée première serait autorisée à implémenter cette méthode statique (ou pour les génériques: la classe réelle du générique vous utilisation).
De cette façon, vous pouvez créer par exemple une classe abstraite sortableObject ou même une interface avec des méthodes statiques (auto-) abstraites, qui définit les paramètres des options de tri:
public interface SortableObject {
public [abstract] static String [] getSortableTypes();
public String getSortableValueByType(String type);
}
Vous pouvez maintenant définir un objet triable qui peut être trié par les principaux types qui sont les mêmes pour tous ces objets:
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
}
}
Vous pouvez maintenant créer un
public class SortableList<T extends SortableObject>
qui peut récupérer les types, créer un menu contextuel pour sélectionner un type sur lequel trier et recourir à la liste en obtenant les données de ce type, ainsi que disposer d'une fonction d'ajout qui, lorsqu'un type de tri a été sélectionné, peut automatiquement -sort les nouveaux éléments. Notez que l'instance de SortableList peut accéder directement à la méthode statique de "T":
String [] MenuItems = T.getSortableTypes();
Le problème lié à l'utilisation d'une instance est que la SortableList peut ne pas encore contenir d'éléments, mais doit déjà fournir le tri préféré.
Cheerio, Olaf.
Tout d'abord, un point clé sur les classes abstraites - Une classe abstraite ne peut pas être instanciée (voir wiki ). Vous ne pouvez donc pas créer d' instance d'une classe abstraite.
Maintenant, la façon dont java traite les méthodes statiques consiste à partager la méthode avec toutes les instances de cette classe.
Donc, si vous ne pouvez pas instancier une classe, cette classe ne peut pas avoir de méthodes statiques abstraites car une méthode abstraite demande à être étendue.
Boom.
Selon le document Java :
Une méthode statique est une méthode associée à la classe dans laquelle elle est définie plutôt qu'à n'importe quel objet. Chaque instance de la classe partage ses méthodes statiques
En Java 8, avec les méthodes par défaut, les méthodes statiques sont également autorisées dans une interface. Cela nous permet d'organiser plus facilement les méthodes d'assistance dans nos bibliothèques. Nous pouvons conserver des méthodes statiques spécifiques à une interface dans la même interface plutôt que dans une classe distincte.
Un bel exemple de ceci est:
list.sort(ordering);
au lieu de
Collections.sort(list, ordering);
Un autre exemple d'utilisation de méthodes statiques est également donné dans la doc elle-même:
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));
}
}
Parce que «abstrait» signifie que la méthode est censée être remplacée et que l'on ne peut pas remplacer les méthodes «statiques».
Les méthodes régulières peuvent être abstraites lorsqu'elles sont censées être remplacées par des sous-classes et dotées de fonctionnalités. Imaginez que la classe Foo
soit étendue par Bar1, Bar2, Bar3
etc. Ainsi, chacun aura sa propre version de la classe abstraite en fonction de ses besoins.
Or, les méthodes statiques appartiennent par définition à la classe, elles n'ont rien à voir avec les objets de la classe ou les objets de ses sous-classes. Ils n'en ont même pas besoin pour exister, ils peuvent être utilisés sans instancier les classes. Par conséquent, ils doivent être prêts à l'emploi et ne peuvent pas dépendre des sous-classes pour leur ajouter des fonctionnalités.
Parce que l'abstrait est un mot-clé appliqué aux méthodes abstraites, ne spécifiez pas de corps. Et si nous parlons de mot-clé statique, il appartient à la zone de classe.
Vous pouvez le faire avec des interfaces dans Java 8.
Voici la documentation officielle à ce sujet:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
Parce que si une classe étend une classe abstraite, elle doit remplacer les méthodes abstraites et c'est obligatoire. Et puisque les méthodes statiques sont des méthodes de classe résolues au moment de la compilation alors que les méthodes remplacées sont des méthodes d'instance résolues au moment de l'exécution et après le polymorphisme dynamique.