Le new
mot clé dans des langages tels que Java, Javascript et C # crée une nouvelle instance d'une classe.
Cette syntaxe semble avoir été héritée de C ++, où elle new
est utilisée spécifiquement pour allouer une nouvelle instance d'une classe sur le tas et renvoyer un pointeur sur la nouvelle instance. En C ++, ce n'est pas le seul moyen de construire un objet. Vous pouvez également construire un objet sur la pile, sans utiliser new
- et en fait, cette manière de construire des objets est beaucoup plus courante en C ++.
Alors, venant d’un fond C ++, le new
mot clé dans des langages tels que Java, Javascript et C # me paraissait naturel et évident. Ensuite, j'ai commencé à apprendre Python, qui n'a pas le new
mot clé. En Python, une instance est construite simplement en appelant le constructeur, comme suit:
f = Foo()
Au début, cela me paraissait un peu déroutant, jusqu'à ce que je réalise qu'il n'y avait aucune raison pour que Python en ait new
, car tout est un objet, il n'est donc pas nécessaire de lever les ambiguïtés entre les différentes syntaxes de constructeur.
Mais ensuite, j'ai pensé: à quoi sert vraiment new
Java? Pourquoi devrions-nous dire Object o = new Object();
? Pourquoi pas juste Object o = Object();
? En C ++, il est absolument nécessaire new
, car nous devons distinguer entre l’allocation sur le tas et l’allocation sur la pile, mais en Java, tous les objets sont construits sur le tas, pourquoi même le new
mot-clé? La même question pourrait être posée pour Javascript. En C #, que je connais beaucoup moins bien, je pense qu’il new
peut être utile de distinguer les types d’objet des types de valeur, mais je ne suis pas sûr.
Quoi qu'il en soit, il me semble que de nombreux langages ayant succédé à C ++ ont simplement "hérité" du new
mot clé - sans en avoir réellement besoin. C'est presque comme un mot-clé vestigial . Nous ne semblons en avoir besoin pour aucune raison, et pourtant, il est là.
Question: Ai-je raison à ce sujet? Ou y a-t-il une raison impérieuse qui new
doit être dans des langages à gestion de mémoire inspirés du C ++ tels que Java, Javascript et C #, mais pas Python?
new
mot clé. Bien sûr, je veux créer une nouvelle variable, un compilateur stupide! Une bonne langue serait à mon avis une syntaxe commef = heap Foo()
,f = auto Foo()
.f
n'échappe pas à la fonction, allouez de l'espace de pile.f
lorsque la fonction englobante revient.Réponses:
Vos observations sont correctes. C ++ est une bête compliquée, et le
new
mot clé a été utilisé pour faire la distinction entre quelque chose dont on aurait besoindelete
plus tard et quelque chose qui serait automatiquement récupéré. En Java et en C #, ils ont abandonné ledelete
mot - clé car le ramasse-miettes s'en charge pour vous.Le problème est alors pourquoi ont-ils gardé le
new
mot clé? Sans parler aux auteurs de la langue, il est difficile de répondre. Mes meilleures suppositions sont énumérées ci-dessous:new
mot - clé crée un objet sur le tas. Alors, pourquoi changer le comportement attendu?Ruby se situe quelque part entre Python et Java / C # dans son utilisation de
new
. En gros, vous instanciez un objet comme celui-ci:Ce n'est pas un mot-clé, c'est une méthode statique pour la classe. Cela signifie que si vous voulez un singleton, vous pouvez remplacer l'implémentation par défaut de
new()
pour renvoyer la même instance à chaque fois. Ce n'est pas forcément recommandé, mais c'est possible.la source
alloc
méthode (à peu près la même chose que Ruby'snew
) est aussi juste une méthode de classe.En bref, vous avez raison. Le mot-clé new est superflu dans des langages tels que Java et C #. Voici quelques idées de Bruce Eckel, membre du comité standard C ++ dans les années 1990 et qui a publié des ouvrages sur Java: http://www.artima.com/weblogs/viewpost.jsp?thread=260578
la source
var
mot clé n'est nulle part aussi bon qu'enauto
C ++, mais j'espère qu'il va s'améliorer.Je peux penser à deux raisons:
new
distingue entre un objet et une primitivenew
syntaxe est un peu plus lisible (IMO)Le premier est trivial. Je ne pense pas qu'il soit plus difficile de distinguer les deux. La seconde est un exemple du point de vue du PO, qui
new
est en quelque sorte redondant.Il pourrait cependant y avoir des conflits d’espace de noms; considérer:
Vous pourriez, sans trop étirer votre imagination, aboutir facilement à un appel infiniment récursif. Le compilateur devrait appliquer une erreur "Nom de la fonction identique à l'objet". Cela ne ferait vraiment pas de mal, mais il est beaucoup plus simple à utiliser
new
, ce quiGo to the object of the same name as this method and use the method that matches this signature.
veut dire que Java est un langage très simple à analyser, et je suppose que cela aide dans ce domaine.la source
Java, pour sa part, a encore la dichotomie de C ++: tout n'est pas tout objet. Java possède des types intégrés (par exemple,
char
etint
) qui ne doivent pas être alloués de manière dynamique.Cela ne signifie pas pour autant que cela
new
soit vraiment nécessaire en Java: l'ensemble des types qui n'ont pas besoin d'être alloués de manière dynamique est fixe et connu. Lorsque vous définissez un objet, le compilateur peut savoir (et sait en fait) s'il s'agit d'une valeur simplechar
ou d'un objet qui doit être alloué de manière dynamique.Je m'abstiendrai (encore une fois) de donner mon avis sur ce que cela signifie pour la qualité du design de Java (ou son absence, selon le cas).
la source
new
, donc ce n’est pas vraiment la raison.En JavaScript, vous en avez besoin, car le constructeur ressemble à une fonction normale. Comment JS devrait-il savoir que vous souhaitez créer un nouvel objet sans le nouveau mot clé?
la source
Fait intéressant, VB en a vraiment besoin - la distinction entre
qui déclare une variable sans l'affecter, l'équivalent de
Foo f;
C #, etqui déclare la variable et assigne une nouvelle instance de la classe, l’équivalent de
var f = new Foo();
C en, est une distinction de fond. Dans les versions antérieures à .NET, vous pouviez même utiliserDim f As Foo
ouDim f As New Foo
- car il n'y avait pas de surcharge sur les constructeurs.la source
Dim f As Foo()
déclare un tableau deFoo
s. Oh joie! :-)Dim Foo As New Bar
créerait effectivementFoo
une propriété qui construirait unBar
si elle était lue avec (ieNothing
). Ce comportement ne s'est pas limité à se produire une fois; mettreFoo
àNothing
et puis le lire créerait un autre nouveauBar
.J'aime beaucoup de réponses et je voudrais juste ajouter ceci:
Cela facilite la lecture du code.
Cette situation se produirait souvent, mais considérez que vous vouliez une méthode au nom d'un verbe qui partage le même nom qu'un nom. C # et les autres langues ont naturellement le mot
object
réservé. Mais si ce n'était pas le cas, celaFoo = object()
résulterait de l'appel de la méthode objet ou instancierait-il un nouvel objet. Espérons que la langue sansnew
mot - clé dispose de protections contre cette situation, mais ennew
autorisant l' exigence du mot - clé avant l'appel d'un constructeur, vous autorisez l'existence d'une méthode portant le même nom qu'un objet.la source
Il y a beaucoup de traces dans de nombreux langages de programmation. Parfois, c'est là pour des raisons de conception (C ++ a été conçu pour être aussi compatible que possible avec C), parfois, c'est juste là. Pour un exemple plus flagrant, considérons dans quelle mesure l’
switch
instruction C cassée se propageait.Je ne connais pas assez bien le langage Javascript et le langage C # pour le dire, mais je ne vois aucune raison de le faire
new
en Java, si ce n’est le cas du C ++.la source
x = new Y()
JavaScript n'instancier laY
classe, parce que JavaScript ne possède classes. Mais comme il ressemble à Java, il porte lenew
mot - clé de Java, qui bien sûr le fait passer de C ++.En C #, cela permet aux types visibles dans des contextes où ils pourraient sinon être masqués par un membre. Le vous permet d'avoir une propriété avec le même nom que son type. Considérer ce qui suit,
Notez que l'utilisation de
new
permet d'indiquer clairement queAddress
leAddress
type n'est pas leAddress
membre. Cela permet à un membre d'avoir le même nom que son type. Sans cela, vous auriez besoin de préfixer le nom du type pour éviter la collision de noms, tel queCAddress
. C'était très intentionnel, car Anders n'a jamais aimé la notation hongroise ou quelque chose de similaire et voulait que C # soit utilisable sans elle. Le fait que ce soit aussi familier était un double bonus.la source
Fait intéressant, avec l'avènement de la transmission parfaite, le non-placement
new
n'est plus du tout requis en C ++. Donc, sans doute, ce n'est plus nécessaire dans aucune des langues mentionnées.la source
std::shared_ptr<int> foo();
devra appeler ennew int
quelque sorte.Je ne suis pas sûr que les concepteurs de Java aient pensé à cela, mais lorsque vous considérez les objets comme des enregistrements récursifs , vous pouvez imaginer que
Foo(123)
cela ne retourne pas un objet, mais une fonction dont le point fixe est l'objet créé (c.-à-d. Une fonction qui renverrait l'objet s'il est donné en argument, l'objet en cours de construction). Et le but denew
est de "faire le noeud" et de retourner ce point de repère. En d' autres termes ,new
ferait l'objet « à être » au courant de sonself
.Ce type d’approche pourrait aider à formaliser l’héritage, par exemple: vous pourriez étendre une fonction objet avec une autre fonction objet et enfin leur fournir des éléments communs
self
en utilisantnew
:Ici,
&
combine deux fonctions-objets.Dans ce cas,
new
pourrait être défini comme:la source
Autoriser 'nil'.
Parallèlement à l'allocation basée sur le tas, Java a adopté l'utilisation d'objets nil. Pas simplement comme un artefact, mais comme une fonctionnalité. Lorsque les objets peuvent avoir un état nul, vous devez alors séparer la déclaration de l'initialisation. D'où le nouveau mot clé.
En C ++ une ligne comme
Appellerait instantanément le constructeur par défaut.
la source
Person me = Nil
ouPerson me
être Nil par défaut et utiliserPerson me = Person()
pour non-Nil? Mon point est qu'il ne semble pas que Nil ait été un facteur dans cette décision ...Person me
nil etPerson me()
appel du constructeur par défaut. Vous aurez donc toujours besoin de parenthèses pour pouvoir invoquer quoi que ce soit et vous débarrasser ainsi d'une irrégularité C ++.La raison pour laquelle Python n'en a pas besoin, c'est en raison de son système de types. Fondamentalement, quand vous voyez
foo = bar()
en Python, peu importe qu’il s’agisse d’bar()
une méthode invoquée, d’une classe instanciée ou d’un objet foncteur; en Python, il n'y a pas de différence fondamentale entre un foncteur et une fonction (car les méthodes sont des objets); et vous pourriez même affirmer qu'une classe en cours d'instanciation est un cas particulier de foncteur. Il n’ya donc aucune raison de créer une différence artificielle dans ce qui se passe (d’autant plus que la gestion de la mémoire est extrêmement cachée dans Python).Dans un langage utilisant un système de typage différent ou dans lequel les méthodes et les classes ne sont pas des objets, il est possible que la différence conceptuelle entre créer un objet et appeler une fonction ou un foncteur soit plus forte . Ainsi, même si le compilateur / interprète n'a pas besoin du
new
mot clé, il est compréhensible qu'il puisse être géré dans des langages n'ayant pas dépassé toutes les limites de Python.la source
En réalité, en Java, il y a une différence lors de l'utilisation de Strings:
est différent de
En supposant que la chaîne
"myString"
n'ait jamais été utilisée auparavant, la première instruction crée un seul objet String dans le pool String (une zone spéciale du segment de mémoire), tandis que la seconde crée deux objets, l'un dans la zone de segment normal pour les objets et l'autre dans le pool String. . Il est assez évident que la deuxième déclaration est inutile dans ce scénario particulier, mais est autorisée par le langage.Cela signifie que new garantit que l'objet est créé dans cette zone spéciale du tas, allouée pour l'instanciation normale d'un objet, mais il peut exister d'autres moyens d'instancier des objets sans lui. celui ci-dessus est un exemple et il reste de la place pour l'extensibilité.
la source
String myString = String("myString");
?" (notez l'absence dunew
mot clé)class MyClass { public MyClass() {} public MyClass MyClass() {return null;} public void doSomething { MyClass myClass = MyClass();}} //which is it, constructor or method?
String
va à l'encontre des conventions de style Java. Vous pouvez donc supposer que toute méthode commençant par une lettre majuscule est un constructeur. Et deuxièmement, si nous ne sommes pas limités par Java, Scala a des "classes de cas" où le constructeur ressemble exactement à ce que j'ai dit. Alors, où est le problème?new
des langues gérées . J'ai montré que cenew
n'est pas du tout nécessaire (par exemple, Scala n'en a pas besoin pour les classes de cas) et qu'il n'y a pas d'ambiguïté (puisqu'il est absolument impossible de nommer une méthodeMyClass
en classeMyClass
). Il n'y a pas d'ambiguïté pourString s = String("hello")
; ce ne peut être autre chose qu'un constructeur. Enfin, je ne suis pas d’accord: les conventions de code sont là pour améliorer et clarifier la syntaxe, ce sur quoi vous vous disputez!new
mot clé car sinon la syntaxe de Java aurait été différente"? Je suis sûr que vous pouvez voir la faiblesse de cet argument;) Et oui, vous continuez à discuter de syntaxe, pas de sémantique. Aussi, la compatibilité ascendante avec quoi? Si vous concevez un nouveau langage, tel que Java, vous êtes déjà incompatible avec le C et le C ++!En C #, il est important de faire la distinction entre les objets créés sur la pile et le tas. Nous créons fréquemment des objets sur la pile pour de meilleures performances. Vous voyez, lorsqu'un objet de la pile sort de son champ d'application, il disparaît immédiatement lorsque la pile se défait, comme une primitive. Il n’est pas nécessaire que le ramasse-miettes en garde la trace et le gestionnaire de mémoire n’a pas besoin de temps système supplémentaire pour allouer l’espace nécessaire sur le tas.
la source