Pourquoi les méthodes statiques ne peuvent-elles pas être abstraites en Java?
23 réponses
Parce que "abstrait" signifie: "Implémente pas de fonctionnalité", et "statique" signifie: "Il existe des fonctionnalités, même si vous n'avez pas une instance d'objet". Et c'est une contradiction logique.
Mauvaise langue de conception. Il serait beaucoup plus efficace d'appeler directement une méthode abstraite statique que de créer une instance juste pour utiliser cette méthode abstraite. Particulièrement vrai quand on utilise une classe abstraite comme solution de contournement pour l'incapacité d'extension d'enum, ce qui est un autre mauvais exemple de conception. Espérons qu'ils résoudre ces limitations dans une prochaine version.
vous ne pouvez pas remplacer une méthode statique, donc le rendre abstrait serait dénué de sens. De plus, une méthode statique dans une classe abstraite appartiendrait à cette classe, et non à la classe dominante, donc ne pourrait pas être utilisée de toute façon.
L'annotation abstract
à une méthode indique que la méthode doit être prépondérante dans une sous-classe.
en Java, un membre static
(méthode ou champ) ne peut pas être remplacé par des sous-classes (cela n'est pas nécessairement vrai dans d'autres langages orientés objet, voir SmallTalk.) Un static
membre peut être caché , mais qui est fondamentalement différent de celui de remplacée .
depuis static les membres ne peuvent pas être remplacés dans une sous-classe, l'annotation abstract
ne peut pas leur être appliquée.
comme un passage - d'autres langues supportent l'héritage statique, tout comme l'héritage d'instance. Du point de vue de la syntaxe, ces langages nécessitent habituellement que le nom de la classe soit inclus dans la déclaration. Par exemple, en Java, en supposant que vous écrivez du code dans ClassA, ce sont des déclarations équivalentes (si methota () est une méthode statique, et il n'y a pas de méthode d'instance avec même signature):
ClassA.methodA();
et
methodA();
dans SmallTalk, le nom de classe n'est pas optionnel, donc la syntaxe est (notez que SmallTalk n'utilise pas le . pour séparer le "sujet" et le "verbe", mais à la place l'utilise comme terminateur statemend):
ClassA methodA.
parce que le nom de classe est toujours requis, la" version " correcte de la méthode peut toujours être déterminée en traversant la hiérarchie de classe. Pour ce qu'il la peine, je ne le manquez de temps en temps static
de l'héritage, et a été mordu par le manque d'héritage statique en Java quand j'ai commencé avec elle. En outre, SmallTalk est tapé du canard (et ne supporte donc pas le programme-par-contrat.) Il n'a donc pas de modificateur abstract
pour les membres de la classe.
j'ai aussi posé la même question , voici pourquoi
puisque la classe abstraite dit, elle ne donnera pas la mise en œuvre et permettra à la sous-classe de lui donner
ainsi la sous-classe doit primer les méthodes de la superclasse,
RÈGLE N ° 1 - UNE méthode statique ne peut pas être remplacé
parce que les membres statiques et les méthodes sont des éléments temps de compilation , c'est pourquoi La surcharge (compilation du polymorphisme dans le temps) des méthodes statiques est autorisée plutôt que la surcharge (polymorphisme dans le temps D'exécution)
donc, ils ne peuvent pas être abstraits .
Il n'y a pas de chose comme abstrait statique <--- Pas autorisés dans Java Univers
il s'agit d'une conception linguistique terrible et vraiment aucune raison pour laquelle il ne peut pas être possible.
en fait, voici une implémentation sur la façon dont il 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 =================
cherchez getRequest, et getRequestImpl ... settinstance peut être appelé à modifier la mise en œuvre avant l'appel est effectué.
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();
}
}
}
-
une méthode abstraite n'est définie que pour pouvoir être dépassé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 statique abstraite.
maintenant, la prochaine question est pourquoi les méthodes statiques ne peuvent pas être dépassées??
-
c'est parce que les méthodes statiques appartiennent à une classe particulière et non à son instance. Si vous essayez d'outrepasser un méthode statique vous n'obtiendrez aucune erreur de compilation ou d'exécution, mais le compilateur ne ferait que cacher la méthode statique de superclass.
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, supposons maintenant que Parent
n'est pas abstract
.
class Parent {
static void run() {}
}
cela signifie que Parent.run()
exécutera la méthode statique.
la définition d'une méthode abstract
est" une méthode déclarée mais non appliquée", ce qui signifie qu'elle ne renvoie rien elle-même.
la définition d'une" méthode 1519120920 "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".
An abstract
la valeur de retour de la méthode change au fur et à mesure que l'instance change. Une méthode static
ne le sera pas. A static abstract
la méthode est à peu près une méthode où la valeur de retour est constante, mais ne retourne rien. C'est une contradiction logique.
en outre, il n'y a vraiment pas beaucoup de raison pour une méthode static abstract
.
une classe abstraite ne peut pas avoir de méthode statique parce que l'abstraction est faite pour obtenir la liaison dynamique tandis que les méthodes statiques sont liées statiquement à leur fonctionnalité.Une méthode statique signifie comportement non dépendant d'une variable d'instance, donc pas d'instance / objet est requis.Juste la classe.Méthodes statiques appartient à la classe et non à l'objet. Ils sont stockés dans une zone de mémoire connue sous le nom de PERMGEN d'où ils sont partagés avec chaque objet. Les méthodes de la classe abstraite sont dynamiquement liées à leurs fonctionnalité.
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 de l'information de la sous-classe dynamique disponible via this
); au lieu de cela, une surcharge de la méthode statique est uniquement basée sur l'information disponible au moment de la compilation (cela signifie: une fois que vous vous référez à une méthode statique de superclasse, vous appelez à savoir la méthode de superclasse, mais jamais une méthode de sous-classe).
selon cette méthode statique abstraite serait tout à fait inutile parce que vous n'aurez jamais sa référence substituée par quelque corps défini.
je vois qu'il y a déjà un milliard 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. Puisque la question originale n'a pas de contexte où cela peut être nécessaire, je fournis à la fois un contexte et une solution:
Supposons que vous avez une méthode statique dans un tas de classes qui sont identiques. Ces méthodes appellent une méthode statique qui est 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()
méthodes dans C1
et C2
sont identiques. Il peut y avoir beaucoup de ces calses: C3
C4
etc. Si static abstract
était autorisé, vous élimineriez le code dupliqué 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 parce que la combinaison static abstract
n'est pas autorisée.
Toutefois, cela peut être contourné avec la construction static class
, 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 qui est dupliqué est
public static void doWork() {
c.doWork();
}
une méthode statique peut être appelée sans instance de la classe. Dans votre exemple, vous pouvez appeler foo.bar2(), mais pas de foo.bar (), parce que 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 exécutée toujours 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 mise en œuvre (qui 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 mère) 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 il faut 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, le bloc de code qui 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 toute sous-classe directe de celle-ci. Si vous définissez
abstract class Foo {
abstract static void bar();
}
class Foo2 {
@Override
static void bar() {}
}
puis n'importe quel appel Foo.bar();
est évidemment illégal, et vous utiliserez toujours Foo2.bar();
.
dans cet esprit, le seul but d'une méthode d'Abstraction statique serait de faire respecter les sous-classes pour mettre en œuvre une telle méthode. Vous pourriez d'abord penser que c'est très mal, mais si vous avez un paramètre de type générique <E extends MySuperClass>
il serait bien de garantir via l'interface que E
peut .doSomething()
. Gardez à l'esprit qu'en raison de l'effacement de type génériques n'existent qu'au moment de la compilation.
alors, serait-ce utile? Oui, et C'est peut-être la raison pour laquelle Java 8 autorise les méthodes statiques dans les interfaces (mais seulement avec une implémentation par défaut). Pourquoi pas des méthodes statiques abstraites avec un implémentation par défaut dans les classes? Simplement parce qu'une méthode abstraite avec une implémentation par défaut est en fait une méthode concrète.
pourquoi ne pas abstraire / interfacer les méthodes statiques sans implémentation par défaut? Apparemment, simplement à cause de la façon dont Java identifie le bloc de code qu'il doit exécuter (première partie de ma réponse).
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 seulement la première dérivée serait autorisée à mettre en œuvre cette méthode statique (ou pour les génériques: la classe réelle du générique que vous utilisez).
de cette façon, vous pouvez créer par exemple une classe abstraite sortableObject ou même une interface avec les 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);
}
maintenant vous pouvez définir un objet sortable 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
}
}
Maintenant vous pouvez créer un
public class SortableList<T extends SortableObject>
qui peut récupérer les types, construire un menu pop-up pour sélectionner un type de trier et de recourir à la liste en obtenant les données de ce type, ainsi que hainv une fonction add qui, lorsqu'un type de tri a été sélectionné, peut trier automatiquement 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 avec l'utilisation d'une instance est que la liste Sortablel N'a peut-être pas encore 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 ). Donc, vous ne pouvez pas créer n'importe quelle instance d'une classe abstraite.
maintenant, la façon dont java traite les méthodes statiques est en partageant 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 puisque une méthode abstraite demande à être étendue.
Boom.
selon Java doc :
Une méthode statique est une méthode qui est associé à la classe dans laquelle il est défini plutôt qu'avec 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'aide dans nos bibliothèques. Nous pouvons garder statique des méthodes spécifiques à une interface dans la même interface, plutôt que dans une catégorie 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 doc lui-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 'abstract' signifie que la méthode est censée être dépassée et qu'on ne peut pas outrepasser les méthodes 'statiques'.
vous pouvez le faire avec des interfaces en Java 8.
C'est la documentation officielle à son sujet:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
les méthodes régulières peuvent être abstraites lorsqu'elles sont censées être supplantées par des sous-classes et dotées de fonctionnalités.
Imaginez que la classe Foo
soit prolongée de Bar1, Bar2, Bar3
etc. Ainsi, chacun aura sa propre version de la classe abstraite selon 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'ont même pas besoin d'eux pour exister, ils peuvent être utilisé sans instancier les classes. Par conséquent, ils doivent être prêts à l'emploi et ne peuvent pas dépendre des sous-classes pour y ajouter de la fonctionnalité.
parce que abstract est un mot-clé qui est appliqué sur les méthodes abstraites ne précisent pas un corps. Et si nous parlons de mot-clé statique il appartient à la zone de classe.
parce que si vous utilisez un élément statique ou une variable statique en classe, il se chargera au moment du chargement en classe.
déclarer une méthode comme static
signifie que nous pouvons appeler cette méthode par son nom de classe et si cette classe est abstract
aussi, il ne fait aucun sens de l'appeler comme il ne contient aucun corps, et donc nous ne pouvons pas déclarer une méthode à la fois comme static
et abstract
.
parce que si une classe étend une classe abstraite alors elle doit outrepasser 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 dépassées sont des méthodes d'instance résolues au moment de l'exécution et suivant un polymorphisme dynamique.