Duplicata possible:
Java: justification de la classe Object non déclarée abstraite
Pourquoi la classe Object, qui est leur classe de base en Java, n'est-elle pas abstraite?
J'ai cette question depuis très très longtemps et elle est posée ici uniquement par curiosité, c'est tout. Rien dans mon code ou le code de quiconque ne casse parce qu'il n'est pas abstrait, mais je me demandais pourquoi ils l'ont rendu concret?
Pourquoi quelqu'un voudrait-il une "instance" (et non sa présence a.k.a. Reference) de cette classe Object? Un cas est un mauvais code de synchronisation qui utilise l'instance d'un objet pour le verrouillage (au moins je l'ai utilisé de cette façon une fois .. mon mauvais).
Y a-t-il une utilisation pratique d'une "instance" d'une classe Object? Et comment son instanciation s'inscrit-elle dans la POO? Que se serait-il passé s'ils l'avaient marqué abstrait (bien sûr après avoir fourni des implémentations à ses méthodes)?
Sans que les concepteurs de Java.lang.Object
Nous le disent, nous devons baser nos réponses sur l'opinion. Il y a quelques questions qui peuvent être posées qui peuvent aider à clarifier les choses.
Est-ce que l'une des méthodes de Object aurait intérêt à être abstraite?
On pourrait faire valoir que certaines des méthodes en bénéficieraient. Prenez hashCode()
et equals()
par exemple, il y aurait probablement eu beaucoup moins de frustration autour de la complexité de ces deux si elles avaient toutes deux été faites abstraites. Cela obligerait les développeurs à comprendre comment ils devraient les implémenter, ce qui rendrait plus évident leur cohérence (voir Java efficace). Cependant, je suis plus d'avis que hashCode()
, equals()
et clone()
appartiennent à des abstractions opt-in distinctes (c'est-à-dire des interfaces). Les autres méthodes, wait()
, notify()
, finalize()
, etc. sont suffisamment compliquées et/ou sont natives, il est donc préférable qu'elles soient déjà implémentées et ne bénéficiera pas d'être abstrait.
Donc je suppose que la réponse serait non, aucune des méthodes d'Object ne gagnerait à être abstraite.
Serait-ce un avantage de marquer la classe Object comme abstraite?
En supposant que toutes les méthodes sont implémentées, le seul effet du marquage d'un objet abstrait est qu'il ne peut pas être construit (c'est-à-dire que new Object()
est une erreur de compilation). Cela aurait-il un avantage? Je suis d'avis que le terme "objet" est lui-même abstrait (pouvez-vous trouver quelque chose autour de vous qui puisse être totalement décrit comme "un objet"?), Donc il cadrerait avec le paradigme orienté objet. C'est cependant du côté puriste . On pourrait soutenir que forcer les développeurs à choisir un nom pour toute sous-classe concrète, même vide, entraînera un code qui exprime mieux leur intention. Je pense que, pour être totalement correct en termes de paradigme, Object devrait être marqué abstract
, mais en fin de compte, il n'y a pas de réel avantage, c'est une question de préférence de conception (pragmatisme vs pureté).
La pratique d'utiliser un objet simple pour la synchronisation est-elle une raison suffisante pour qu'il soit concret?
De nombreuses autres réponses parlent de la construction d'un objet simple à utiliser dans l'opération synchronized()
. Bien que cela ait pu être une pratique courante et acceptée, je ne pense pas que ce serait une raison suffisante pour empêcher Object d'être abstrait si les concepteurs le voulaient. D'autres réponses ont mentionné comment nous devrions déclarer une seule sous-classe vide d'objet chaque fois que nous voulions synchroniser sur un certain objet, mais cela ne tient pas debout - une sous-classe vide aurait pu être fournie dans le SDK (Java.lang.Lock
Ou autre), qui pourrait être construit à tout moment lorsque nous voulions synchroniser. Cela aurait l'avantage supplémentaire de créer une déclaration d'intention plus forte.
Y a-t-il d'autres facteurs qui auraient pu être affectés négativement en rendant Object abstrait?
Il existe plusieurs domaines, séparés d'un point de vue purement conceptuel, qui peuvent avoir influencé le choix. Malheureusement, je n'en sais pas assez pour les développer. Cependant, cela ne me surprendrait pas si l'un de ces éléments avait un impact sur la décision:
Pourrait-il y avoir d'autres raisons?
Il a été mentionné que cela pouvait être lié à la réflexion. Cependant, la réflexion a été introduite après la conception d'Object. Donc, que cela affecte ou non la réflexion est théorique - ce n'est pas la raison. Idem pour les génériques.
Il y a aussi le point inoubliable que Java.lang.Object a été conçu par les humains: ils ont peut-être fait une erreur, ils n'ont peut-être pas considéré la question. Il n'y a pas de langage sans défauts, et cela peut être l'un d'entre eux, mais si c'est le cas, ce n'est guère un gros. Et je pense que je peux dire en toute sécurité, sans manque d'ambition, qu'il est très peu probable que je participe à la conception d'un élément clé d'une technologie aussi largement utilisée, en particulier celle qui a duré 15 (?) Ans et qui est toujours aussi solide, donc cela ne devrait pas être considéré comme une critique.
Cela dit, je l'aurais fait abstrait ;-p
Résumé
Fondamentalement, pour autant que je le vois, la réponse aux deux questions "Pourquoi Java.lang.Object est-il concret?" ou (s'il en était ainsi) "Pourquoi Java.lang.Object est-il abstrait?" est ... "Pourquoi pas?".
Instances simples de Java.lang.Object
sont généralement utilisés dans les scénarios de verrouillage/synchronisation et c'est une pratique acceptée.
Aussi - quelle serait la raison pour laquelle cela serait abstrait? Parce qu'il n'est pas pleinement fonctionnel en tant qu'instance? Cela pourrait-il vraiment faire avec certains membres abstraits? Ne pense pas. Donc l'argument pour le rendre abstrait en premier lieu est inexistant. Ce n'est donc pas le cas.
Prenez la hiérarchie classique des animaux, où vous avez une classe abstraite Animal
, le raisonnement pour rendre la classe Animal
abstraite est dû au fait qu'une instance d'Animal est effectivement un "invalide" -par manque d'un meilleur Word-animal (même si toutes ses méthodes fournissent une implémentation de base). Avec Object
, ce n'est tout simplement pas le cas. Il n'y a aucun cas écrasant pour le rendre abstrait en premier lieu.
Je peux penser à plusieurs cas où des instances de Object
sont utiles:
equals
retournera toujours false, sauf sur l'instance elle-même.null
s.Object o = new Object() {...code here...}
D'après tout ce que j'ai lu, il semble que Object
n'a pas besoin d'être concret , et en fait devrait ont été abstraits.
Non seulement il n'est pas nécessaire que ce soit concret, mais après quelques plus de lecture je suis convaincu que Object
pas le fait d'être abstrait est en conflit avec le modèle d'héritage de base - nous ne devrions pas autoriser les sous-classes abstraites d'une classe concrète, car les sous-classes devraient seulement - ajouter la fonctionnalité.
Ce n'est clairement pas le cas en Java, où nous avons des sous-classes abstraites de Object
.
Je pense qu'il aurait probablement dû être déclaré abstrait, mais une fois qu'il est fait et publié, il est très difficile de l'annuler sans causer beaucoup de douleur - voir Java Language Spec 13.4.1:
"Si une classe qui n'était pas abstraite est modifiée pour être déclarée abstraite, les binaires préexistants qui tentent de créer de nouvelles instances de cette classe lèveront soit une InstantiationError au moment du lien, soit (si une méthode réfléchissante est utilisée) une InstantiationException au moment de l'exécution un tel changement n'est donc pas recommandé pour les classes largement distribuées. "
Je ne comprends pas pourquoi la plupart semblent croire que faire une classe entièrement fonctionnelle, qui implémente toutes ses méthodes de manière abstraite serait une bonne idée.
Je préférerais demander pourquoi le rendre abstrait? Fait-il quelque chose qu'il ne devrait pas faire? manque-t-il certaines fonctionnalités qu'il devrait avoir? Il est possible de répondre à ces deux questions par non, c'est une classe à part entière, ce qui en fait un résumé conduit simplement les gens à implémenter des classes vides.
public class UseableObject extends AbstractObject{}
UseableObject hérite de Object abstrait et surprend qu'il puisse être implémenté, il n'ajoute aucune fonctionnalité et sa seule raison d'exister est de permettre l'accès aux méthodes exposées par Object.
Je dois également être en désaccord avec l'utilisation dans une synchronisation "médiocre". L'utilisation d'objets privés pour synchroniser l'accès est plus sûre que l'utilisation de synchronize (this) et plus sûre et plus facile à utiliser que les classes Lock de Java util concurrent).
De temps en temps, vous avez besoin d'un objet simple qui n'a pas d'état propre. Bien que de tels objets semblent inutiles à première vue, ils ont toujours une utilité puisque chacun a différent identité. Tnis est utile dans plusieurs scénarios, dont le plus important est le verrouillage: Vous souhaitez coordonner deux threads. Dans Java vous le faites en utilisant un objet qui sera utilisé comme verrou. L'objet n'a pas besoin d'avoir aucun état, sa simple existence suffit pour qu'il devienne un verrou:
class MyThread extends Thread {
private Object lock;
public MyThread(Object l) { lock = l; }
public void run() {
doSomething();
synchronized(lock) {
doSomethingElse();
}
}
}
Object lock = new Object();
new MyThread(lock).start();
new MyThread(lock).start();
Dans cet exemple, nous avons utilisé un verrou pour empêcher les deux threads d'exécuter simultanément doSomethingElse()
Si Object était abstrait et que nous avions besoin d'un verrou, nous devions le sous-classer sans ajouter de méthode ni de champs afin de pouvoir instancier le verrou.
En y réfléchissant, voici une double question à vous: supposez que l'objet soit abstrait, va-t-il définir des méthodes abstraites? Je suppose que la réponse est Non. Dans de telles circonstances, il n'est pas très utile de définir la classe comme abstraite.
Il me semble qu'il y a ici une simple question pratique. Faire un résumé de classe enlève la capacité du programmeur à faire quelque chose, à savoir l'instancier. Il n'y a rien que vous puissiez faire avec une classe abstraite que vous ne pouvez pas faire avec une classe concrète. (Eh bien, vous pouvez y déclarer des fonctions abstraites, mais dans ce cas, nous n'avons pas besoin d'avoir des fonctions abstraites.) Donc, en le rendant concret, vous le rendez plus flexible.
Bien sûr, s'il y avait un préjudice actif en le rendant concret, cette "flexibilité" serait un inconvénient. Mais je ne peux penser à aucun mal actif causé en rendant l'objet instanciable. (Est-ce que "instanciable" est un mot? Peu importe.) Nous pourrions débattre si une utilisation donnée que quelqu'un a faite d'une instance d'objet brut est une bonne idée. Mais même si vous pouviez me convaincre que chaque utilisation que j'ai jamais vue d'une instance d'objet brut était une mauvaise idée, cela ne prouverait toujours pas qu'il pourrait ne pas y avoir de bonnes utilisations. Donc, si cela ne fait rien de mal et que cela pourrait aider, même si nous ne pouvons pas penser à une façon dont cela pourrait réellement aider pour le moment, pourquoi l'interdire?
Je pense que toutes les réponses jusqu'ici oublient ce que c'était avec Java 1.0. Dans Java 1.0, vous ne pouviez pas créer une classe anonyme, donc si vous Je voulais juste un objet dans un but (synchronisation ou espace réservé nul), vous devriez aller déclarer une classe à cet effet, puis tout un tas de code aurait ces classes supplémentaires à cet effet. Beaucoup plus simple pour autoriser directement instanciation de l'objet.
Bien sûr, si vous concevez Java aujourd'hui, vous pourriez dire que tout le monde devrait faire:
Object NULL_OBJECT = new Object(){};
Mais ce n'était pas une option en 1.0.
Je soupçonne que les concepteurs ne savaient pas de quelle façon les gens pourraient utiliser un objet à l'avenir, et ne voulaient donc pas limiter les programmeurs en les obligeant à créer une classe supplémentaire lorsque cela n'était pas nécessaire, par exemple pour des choses comme les mutex, les clés etc.
Cela signifie également qu'il peut être instancié dans un tableau. Au cours de la période antérieure à 1,5 jour, cela vous permettrait d'avoir des structures de données génériques. Cela pourrait encore être vrai sur certaines plates-formes (je pense à J2ME, mais je ne suis pas sûr)