Słowo new
kluczowe w językach takich jak Java, JavaScript i C # tworzy nowe wystąpienie klasy.
Wydaje się, że ta składnia została odziedziczona z C ++, gdzie new
jest używana specjalnie do przydzielenia nowej instancji klasy na stercie i zwrócenia wskaźnika do nowej instancji. W C ++ nie jest to jedyny sposób na zbudowanie obiektu. Możesz także zbudować obiekt na stosie, bez użycia new
- i w rzeczywistości ten sposób konstruowania obiektów jest znacznie bardziej powszechny w C ++.
Tak więc, pochodzące z języka C ++, new
słowo kluczowe w językach takich jak Java, JavaScript i C # wydawało mi się naturalne i oczywiste. Potem zacząłem uczyć się języka Python, który nie ma new
słowa kluczowego. W Pythonie instancja jest budowana po prostu przez wywołanie konstruktora, na przykład:
f = Foo()
Na początku wydawało mi się to trochę dziwne, dopóki nie przyszło mi do głowy, że Python nie ma powodu new
, ponieważ wszystko jest przedmiotem, więc nie trzeba rozróżniać różnych składni konstruktorów.
Ale potem pomyślałem - jaki jest sens new
Java? Dlaczego powinniśmy powiedzieć Object o = new Object();
? Dlaczego nie tylko Object o = Object();
? W C ++ zdecydowanie jest taka potrzeba new
, ponieważ musimy rozróżnić między alokacją na stosie a alokacją na stosie, ale w Javie wszystkie obiekty są konstruowane na stercie, więc po co w ogóle new
słowo kluczowe? To samo pytanie można zadać dla Javascript. W języku C #, który jestem znacznie mniej obeznany, myślę, że new
może mieć jakiś cel pod względem rozróżniania typów obiektów i typów wartości, ale nie jestem pewien.
Niezależnie od tego wydaje mi się, że wiele języków, które pojawiły się po C ++, po prostu „odziedziczyło” new
słowo kluczowe - tak naprawdę go nie potrzebując. To prawie jak szczątkowe słowo kluczowe . Wydaje się, że nie potrzebujemy go z żadnego powodu, a jednak już istnieje.
Pytanie: Czy mam rację? A może jest jakiś ważny powód, dla którego new
należy używać języków zarządzanych przez pamięć inspirowanych C ++, takich jak Java, JavaScript i C #, ale nie Python?
źródło
new
słowo kluczowe. Oczywiście chcę stworzyć nową zmienną, głupi kompilator! Dobrym językiem moim zdaniem mają składnię jakf = heap Foo()
,f = auto Foo()
.f
znaczy, kiedy nie ucieka z funkcji, przydziel miejsce na stosie.f
po powrocie funkcji zamykającej.Odpowiedzi:
Twoje obserwacje są poprawne. C ++ jest skomplikowaną bestią, a
new
słowo kluczowe zostało użyte do odróżnienia czegoś, co było potrzebnedelete
później, od czegoś, co zostanie automatycznie odzyskane. W Javie i C # upuściłydelete
słowo kluczowe, ponieważ śmieciarz zaopiekuje się tobą.Problem polega na tym, dlaczego zachowali
new
słowo kluczowe? Bez rozmowy z ludźmi, którzy napisali język, trudno jest odpowiedzieć. Moje najlepsze domysły są wymienione poniżej:new
słowo kluczowe tworzy obiekt na stercie. Po co więc zmieniać oczekiwane zachowanie?Ruby jest gdzieś pomiędzy Pythonem a Java / C # w użyciu
new
. Zasadniczo tworzysz taki obiekt:To nie jest słowo kluczowe, to statyczna metoda dla klasy. Oznacza to, że jeśli chcesz singletonu, możesz zastąpić domyślną implementację
new()
zwracania tej samej instancji za każdym razem. Niekoniecznie jest to zalecane, ale jest możliwe.źródło
alloc
metoda (mniej więcej taka sama jak Rubynew
) jest również metodą klasową.Krótko mówiąc, masz rację. Słowo kluczowe new jest zbędne w językach takich jak Java i C #. Oto niektóre spostrzeżenia Bruce'a Eckela, który był członkiem C ++ Standard Comitee w latach 90., a później opublikował książki o Javie: http://www.artima.com/weblogs/viewpost.jsp?thread=260578
źródło
var
kluczowe nie jest tak dobre jakauto
w C ++, ale mam nadzieję, że się poprawi.Są dwa powody, dla których mogę wymyślić:
new
rozróżnia obiekt od prymitywunew
Składnia jest nieco bardziej czytelne (IMO)Pierwszy jest trywialny. Nie wydaje mi się, żeby trudniej było odróżnić te dwie strony. Drugi jest przykładem punktu PO, który
new
jest w pewnym sensie zbędny.Mogą jednak wystąpić konflikty przestrzeni nazw; rozważać:
Możesz bez nadmiernego rozciągania wyobraźni łatwo skończyć z nieskończenie rekurencyjnym wezwaniem. Kompilator musiałby wymusić błąd „Nazwa funkcji taka sama jak obiekt”. To naprawdę nie zaszkodzi, ale jest o wiele prostsze w użyciu
new
, co stanowi, żeGo to the object of the same name as this method and use the method that matches this signature.
Java jest bardzo prostym językiem do analizy i podejrzewam, że pomaga w tym obszarze.źródło
Java, na przykład, wciąż ma dychotomię C ++: nie całkiem wszystko jest przedmiotem. Java ma wbudowane typy (np.
char
Iint
), które nie muszą być przydzielane dynamicznie.Nie oznacza to jednak, że
new
jest to naprawdę konieczne w Javie - zestaw typów, które nie muszą być przydzielane dynamicznie, jest stały i znany. Podczas definiowania obiektu kompilator może wiedzieć (a tak naprawdę wie), czy jest to prosta wartość tegochar
obiektu, czy obiekt, który należy przypisać dynamicznie.Powstrzymam się (jeszcze raz) od wyrażania opinii na temat tego, co to znaczy na temat jakości projektu Java (lub jego braku, w zależności od przypadku).
źródło
new
, więc to nie jest tak naprawdę powód.W JavaScript potrzebujesz go, ponieważ konstruktor wygląda jak normalna funkcja, więc skąd JS powinien wiedzieć, że chcesz utworzyć nowy obiekt, gdyby nie nowe słowo kluczowe?
źródło
Co ciekawe, VB tego potrzebuje - rozróżnienia między
który deklaruje zmienną bez przypisywania jej, odpowiednik
Foo f;
w C # iktóra deklaruje zmienną i przypisuje nową instancję klasy, odpowiednik
var f = new Foo();
w C #, jest istotnym rozróżnieniem. W wersjach pre-.NET VB można nawet użyćDim f As Foo
lubDim f As New Foo
- ponieważ nie wystąpiło przeciążenie konstruktorów.źródło
Dim f As Foo()
deklaruje tablicę zFoo
s. O radości! :-)Dim Foo As New Bar
skutecznie tworzyFoo
właściwość, która konstruowałaby a,Bar
gdyby była czytana podczas (tjNothing
.). To zachowanie nie ograniczało się do jednorazowego zdarzenia; ustawienieFoo
naNothing
czym czytanie byłoby utworzyć kolejneBar
.Lubię wiele odpowiedzi i chciałbym po prostu dodać:
Ułatwia to czytanie kodu.
Nie żeby taka sytuacja zdarzała się często, ale pomyśl, że chciałeś metody w nazwie czasownika o tej samej nazwie co rzeczownik. C # i inny język mają oczywiście słowo
object
zastrzeżone. Ale gdyby tak nie było, byłbyFoo = object()
to wynik wywołania metody object lub instancja nowego obiektu. Mam nadzieję, że język beznew
słowa kluczowego ma zabezpieczenia przed tą sytuacją, ale wymagając tegonew
słowa kluczowego przed wywołaniem konstruktora, zezwalasz na istnienie metody o tej samej nazwie co obiekt.źródło
W wielu językach programowania jest wiele szczątkowych rzeczy. Czasami jest tam z założenia (C ++ został zaprojektowany tak, aby był jak najbardziej kompatybilny z C), czasem po prostu tam jest. Aby uzyskać bardziej skandaliczny przykład, zastanów się, jak daleko
switch
rozprzestrzeniła się uszkodzona instrukcja C.Nie znam JavaScriptu i języka C # wystarczająco dobrze, aby to powiedzieć, ale nie widzę powodu
new
w Javie, z wyjątkiem tego, że C ++ miał go.źródło
x = new Y()
w JavaScript nie wystąpienia zY
klasy, ponieważ JavaScript nie mają zajęcia. Ale wygląda jak Java, więc przenosinew
słowo kluczowe do przodu z Java, które oczywiście przeniosło je z C ++.W języku C # pozwala na typy widoczne w kontekstach, w których mogłyby zostać zasłonięte przez członka. Pozwala mieć właściwość o takiej samej nazwie jak jej typ. Rozważ następujące,
Zauważ, że użycie
new
pozwala na jasne, że nieAddress
jest toAddress
typAddress
członka. Dzięki temu członek może mieć taką samą nazwę jak jego typ. Bez tego trzeba by poprzedzić nazwę typu, aby uniknąć kolizji nazwy, npCAddress
. Było to bardzo celowe, ponieważ Anders nigdy nie lubił węgierskiej notacji ani niczego podobnego i chciał, aby C # był bez niej użyteczny. Fakt, że był również znany, był podwójną premią.źródło
Co ciekawe, wraz z nadejściem idealnego przekierowania
new
w C ++ nie jest wcale wymagane umieszczanie . Prawdopodobnie nie jest już potrzebny w żadnym z wymienionych języków.źródło
std::shared_ptr<int> foo();
będzie musiałnew int
jakoś zadzwonić .Nie jestem pewien, czy projektanci Java mieli to na uwadze, ale kiedy myślisz o obiektach jako rekursywnych rekordach , możesz sobie wyobrazić, że
Foo(123)
nie zwraca obiektu, ale funkcję, której punktem stałym jest tworzony obiekt (tj. Funkcja, która zwróci obiekt, jeśli jest podany jako argument budowanego obiektu). A celemnew
jest „zawiązanie węzła” i zwrócenie tego punktu stałego. Innymi słowynew
, uświadomiłby to „obiektowi, który ma być”self
.Takie podejście może pomóc w sformalizowaniu dziedziczenia, na przykład: możesz rozszerzyć funkcję obiektu o inną funkcję obiektu i w końcu zapewnić im wspólną funkcję,
self
używającnew
:Tutaj
&
łączy dwie funkcje obiektowe.W takim przypadku
new
można zdefiniować jako:źródło
Aby zezwolić na „zero”.
Wraz z alokacją opartą na stercie, Java objęła stosowanie zerowych obiektów. Nie tylko jako artefakt, ale jako funkcja. Gdy obiekty mogą mieć stan zerowy, musisz oddzielić deklarację od inicjalizacji. Stąd nowe słowo kluczowe.
W C ++ wiersz podobny
Natychmiast wywołałby domyślnego konstruktora.
źródło
Person me = Nil
lub mającePerson me
być Nil domyślnie i korzystaniaPerson me = Person()
przez nie-Nil? Chodzi mi o to, że nie wydaje się, aby Zero miał wpływ na tę decyzję ...Person me
ponieważ nie ma nic iPerson me()
wywołuje domyślnego konstruktora. Dlatego zawsze potrzebujesz nawiasów, aby wywołać cokolwiek, a tym samym pozbyć się jednej nieprawidłowości w C ++.Powodem, dla którego Python go nie potrzebuje, jest system typów. Zasadniczo, kiedy widzisz
foo = bar()
w Pythonie, nie ma znaczenia, czybar()
jest wywoływana metoda, instancja klasy, czy obiekt funktowy; w Pythonie nie ma zasadniczej różnicy między funktorem a funkcją (ponieważ metody są obiektami); i można nawet argumentować, że instancja klasy jest szczególnym przypadkiem funktora. Dlatego nie ma powodu, aby tworzyć sztuczną różnicę w tym, co się dzieje (zwłaszcza, że zarządzanie pamięcią jest tak bardzo ukryte w Pythonie).W języku z innym systemem pisania lub w którym metody i klasy nie są obiektami, istnieje możliwość silniejszej różnicy pojęciowej między tworzeniem obiektu a wywoływaniem funkcji lub funktora. Tak więc, nawet jeśli kompilator / interpreter nie potrzebuje
new
słowa kluczowego, zrozumiałe jest, że może on być utrzymywany w językach, które nie przekroczyły wszystkich granic, które ma Python.źródło
W rzeczywistości w Javie istnieje różnica w korzystaniu z ciągów:
jest różny od
Załóżmy, że ciąg
"myString"
nigdy nie był używany, pierwsza instrukcja tworzy pojedynczy obiekt String w puli String (specjalny obszar sterty), podczas gdy druga instrukcja tworzy dwa obiekty, jeden w normalnym obszarze sterty dla obiektów, a drugi w puli String . Jest całkiem oczywiste, że druga instrukcja jest bezużyteczna w tym konkretnym scenariuszu, ale jest dozwolona przez język.Oznacza to, że nowy zapewnia, że obiekt jest tworzony w tym specjalnym obszarze sterty, przeznaczonym do normalnego tworzenia instancji obiektu, ale mogą istnieć inne sposoby tworzenia instancji bez niego; powyższy jest przykładem i pozostało miejsce na rozszerzenie.
źródło
String myString = String("myString");
?” (zauważ braknew
słowa kluczowego)class MyClass { public MyClass() {} public MyClass MyClass() {return null;} public void doSomething { MyClass myClass = MyClass();}} //which is it, constructor or method?
String
jest sprzeczne z konwencjami stylu Java, więc możesz założyć, że dowolna metoda zaczynająca się od wielkich liter jest konstruktorem. Po drugie, jeśli nie jesteśmy ograniczeni przez Javę, wówczas Scala ma „klasy przypadków”, w których konstruktor wygląda dokładnie tak, jak powiedziałem. Więc gdzie jest problem?new
dla zarządzanych języków . Pokazałem, żenew
wcale nie jest potrzebny (np. Scala nie potrzebuje go do klas obserwacji), a także, że nie ma dwuznaczności (ponieważ absolutnie nie można mieć metody nazwanejMyClass
w klasieMyClass
). Nie ma żadnych dwuznaczności dlaString s = String("hello")
; nie może być niczym innym jak konstruktorem. Wreszcie nie zgadzam się: konwencje kodu mają na celu ulepszenie i wyjaśnienie składni, o co się kłócisz!new
słowa kluczowego, ponieważ w przeciwnym razie składnia Javy byłaby inna”? Jestem pewien, że widzisz słabość tego argumentu;) I tak, wciąż dyskutujesz o składni, a nie semantyce. Również kompatybilność wsteczna z czym? Jeśli projektujesz nowy język, taki jak Java, jesteś już niezgodny z C i C ++!W języku C # new jest ważne, aby odróżnić obiekty utworzone na stosie od stosu. Często tworzymy obiekty na stosie dla lepszej wydajności. Widzisz, gdy obiekt na stosie wykracza poza zakres, znika natychmiast, gdy stos się rozwija, zupełnie jak prymityw. Moduł zbierający śmieci nie musi go śledzić i nie ma dodatkowych kosztów związanych z zarządzaniem pamięcią w celu przydzielenia niezbędnej przestrzeni na stercie.
źródło