ทำไมภาษาที่มีการจัดการหน่วยความจำเช่น Java, Javascript และ C # จึงยังคงรักษาคำหลัก `ใหม่ 'อยู่


138

newคำหลักในภาษาเช่น Java, JavaScript, และ C # สร้างตัวอย่างใหม่ของชั้นเรียน

ดูเหมือนว่าไวยากรณ์นี้จะได้รับการสืบทอดมาจาก C ++ ซึ่งnewมีการใช้เฉพาะเพื่อจัดสรรอินสแตนซ์ใหม่ของคลาสบนฮีปและส่งกลับตัวชี้ไปยังอินสแตนซ์ใหม่ ใน C ++ นี่ไม่ใช่วิธีเดียวในการสร้างวัตถุ คุณยังสามารถสร้างวัตถุบนสแต็กโดยไม่ต้องใช้new- และในความเป็นจริงวิธีการสร้างวัตถุนี้เป็นเรื่องธรรมดามากใน C ++

ดังนั้นมาจากพื้นหลัง C ++ newคำสำคัญในภาษาเช่น Java, Javascript และ C # ดูเป็นธรรมชาติและชัดเจนสำหรับฉัน จากนั้นฉันก็เริ่มเรียนรู้ Python ซึ่งไม่มีnewคำหลัก ใน Python อินสแตนซ์ถูกสร้างโดยการเรียกนวกรรมิกเช่น:

f = Foo()

ในตอนแรกสิ่งนี้ดูจะยากสำหรับฉันจนกว่ามันจะเกิดขึ้นกับฉันว่า Python ไม่มีเหตุผลnewเพราะทุกอย่างเป็นวัตถุดังนั้นจึงไม่จำเป็นต้องแยกแยะระหว่างไวยากรณ์ตัวสร้างต่าง ๆ

แต่แล้วฉันก็คิดว่า - จุดประสงค์newใน Java คืออะไร? ทำไมเราควรจะพูดว่าObject o = new Object();? ทำไมไม่เป็นเช่นนั้นObject o = Object();? ใน C ++ มีความจำเป็นอย่างแน่นอนnewเนื่องจากเราจำเป็นต้องแยกแยะระหว่างการจัดสรรฮีปและการปันส่วนบนสแต็ก แต่ใน Java วัตถุทั้งหมดถูกสร้างบนฮีปดังนั้นทำไมถึงมีnewคำหลักด้วย? คำถามเดียวกันสามารถถามจาวาสคริปต์ได้ ใน C # ซึ่งฉันคุ้นเคยน้อยกว่าฉันคิดว่าnewอาจมีจุดประสงค์บางประการในแง่ของการแยกแยะความแตกต่างระหว่างชนิดของวัตถุและประเภทของค่า แต่ไม่แน่ใจ

ดูเหมือนว่าฉันจะมีหลายภาษาที่มาหลังจาก C ++ เพียงแค่ "สืบทอด" newคำหลัก - โดยไม่จำเป็นต้องใช้มันจริงๆ มันเกือบจะเหมือนคำหลักร่องรอย ดูเหมือนว่าเราจะไม่ต้องการมันด้วยเหตุผลใดก็ตาม แต่มันก็อยู่ที่นั่น

คำถาม:ฉันถูกต้องเกี่ยวกับเรื่องนี้หรือไม่? หรือมีเหตุผลที่น่าสนใจบางอย่างที่newต้องอยู่ใน C ++ - ภาษาที่ได้รับแรงบันดาลใจจากการจัดการหน่วยความจำเช่น Java, Javascript และ C # แต่ไม่ใช่ Python?


13
คำถามก็คือทำไมภาษาใดมีnewคำหลัก แน่นอนฉันต้องการสร้างตัวแปรใหม่คอมไพเลอร์โง่! ดีภาษาในความคิดของฉันจะมีไวยากรณ์เช่น,f = heap Foo() f = auto Foo()

7
ประเด็นสำคัญที่ควรพิจารณาคือความคุ้นเคยของภาษากับโปรแกรมเมอร์คนใหม่ Java ได้รับการออกแบบอย่างชัดเจนเพื่อให้คุ้นเคยกับโปรแกรมเมอร์ C / C ++

1
@Lundin: มันเป็นผลมาจากเทคโนโลยีคอมไพเลอร์ คอมไพเลอร์สมัยใหม่ไม่จำเป็นต้องมีคำใบ้ มันจะหาตำแหน่งที่จะวางวัตถุตามการใช้งานจริงของตัวแปรนั้น เช่นเมื่อfไม่หนีฟังก์ชันจัดสรรพื้นที่สแต็ค
MSalters

3
@Lundin: ทำได้และในความเป็นจริงแล้ว JVM สมัยใหม่ทำ มันเป็นเพียงเรื่องของการพิสูจน์ว่า GC สามารถรวบรวมวัตถุfเมื่อฟังก์ชันปิดล้อมส่งคืน
MSalters

1
มันไม่สร้างสรรค์เลยที่จะถามว่าทำไมภาษาถึงได้รับการออกแบบมาโดยเฉพาะอย่างยิ่งถ้าการออกแบบนั้นขอให้เราพิมพ์อักขระพิเศษสี่ตัวเพื่อผลประโยชน์ที่ไม่ชัดเจน? ฉันพลาดอะไรไป
MatrixFrog

คำตอบ:


93

ข้อสังเกตของคุณถูกต้อง C ++ เป็นสัตว์ร้ายที่มีความซับซ้อนและมีการใช้newคำหลักเพื่อแยกความแตกต่างระหว่างสิ่งที่ต้องการในdeleteภายหลังและสิ่งที่จะถูกเรียกคืนโดยอัตโนมัติ ใน Java และ C # พวกเขาลดdeleteคำหลักเนื่องจากตัวรวบรวมขยะจะดูแลให้คุณ

ปัญหาคือทำไมพวกเขารักษาnewคำหลัก? หากไม่ได้พูดคุยกับคนที่เขียนภาษามันเป็นการยากที่จะตอบ การคาดเดาที่ดีที่สุดของฉันอยู่ด้านล่าง:

  • มันถูกต้องทางความหมาย หากคุณคุ้นเคยกับ C ++ คุณจะรู้ว่าnewคำหลักนั้นสร้างวัตถุบนฮีป ดังนั้นทำไมเปลี่ยนพฤติกรรมที่คาดหวัง
  • มันเรียกร้องความสนใจไปที่ความจริงที่ว่าคุณกำลัง instantiating วัตถุแทนที่จะเรียกวิธีการ ด้วยการแนะนำสไตล์โค้ดของ Microsoft ชื่อวิธีการขึ้นต้นด้วยตัวอักษรพิมพ์ใหญ่เพื่อให้เกิดความสับสน

ทับทิมเป็นหนึ่งในระหว่างงูหลามและ Java / C # newในการใช้งานของ โดยทั่วไปคุณยกตัวอย่างวัตถุเช่นนี้

f = Foo.new()

มันไม่ใช่คำหลักมันเป็นวิธีการคงที่สำหรับชั้นเรียน หมายความว่าถ้าคุณต้องการซิงเกิลตันคุณสามารถแทนที่การใช้งานเริ่มต้นของnew()เพื่อส่งคืนอินสแตนซ์เดียวกันทุกครั้ง ไม่จำเป็นต้องแนะนำ แต่เป็นไปได้


5
ไวยากรณ์ทับทิมดูดีและสอดคล้องกัน! ใหม่คำหลักใน C # ยังจะใช้เป็นข้อ จำกัด ประเภททั่วไปสำหรับประเภทที่มีการสร้างเริ่มต้นที่
Steven Jeuris

3
ใช่. เราจะไม่พูดถึงเรื่องของยาชื่อสามัญ ทั้งเจเนอเรชั่นของ Java และ C # นั้นค่อนข้างสับสน การไม่พูดว่า C ++ นั้นง่ายกว่าที่จะเข้าใจ ข้อมูลทั่วไปมีประโยชน์สำหรับภาษาที่พิมพ์แบบคงที่เท่านั้น ภาษาที่พิมพ์แบบไดนามิกเช่น Python, Ruby และ Smalltalk ไม่ต้องการภาษาเหล่านั้น
Berin Loritsch

2
Delphi มีไวยากรณ์ที่คล้ายกันกับ Ruby ยกเว้นว่าตัวสร้างมักจะ (แต่มีเพียงแบบแผน bhy) ที่เรียกว่าสร้าง (`f: = TFoo.Create (param1, param2 ... ) '
Gerry

ใน Objective-C allocวิธีการ (ประมาณเดียวกับรูบี้new) เป็นเพียงวิธีการเรียน
mipadi

3
จากมุมมองการออกแบบภาษาคำหลักไม่ถูกต้องด้วยเหตุผลหลายประการส่วนใหญ่คุณไม่สามารถเปลี่ยนแปลงได้ ในทางตรงกันข้ามการนำแนวคิดของวิธีการกลับมาใช้ใหม่นั้นง่ายขึ้น แต่ต้องการความสนใจในขณะที่วิเคราะห์และวิเคราะห์ Smalltalk และญาติของมันใช้ข้อความ C + + และคำหลักอื่น ๆ
Gabriel Ščerbák

86

ในระยะสั้นคุณพูดถูก คำหลักใหม่นั้นไม่จำเป็นในภาษาเช่น Java และ C # นี่คือข้อมูลเชิงลึกบางส่วนจาก Bruce Eckel ซึ่งเป็นสมาชิกของ C ++ Standard Comitee ในปี 1990 และหนังสือที่ตีพิมพ์ในภายหลังบน Java: http://www.artima.com/weblogs/viewpost.jsp?thread=260578

จำเป็นต้องมีวิธีในการแยกวัตถุฮีปจากวัตถุสแต็ก เพื่อแก้ปัญหานี้คำหลักใหม่ได้รับการจัดสรรจาก Smalltalk ในการสร้างวัตถุสแต็กคุณเพียงแค่ประกาศเช่นเดียวกับใน Cat x; หรือด้วยอาร์กิวเมนต์ Cat x ("mittens"); ในการสร้างวัตถุฮีปคุณใช้ใหม่ใน Cat ใหม่ หรือ Cat ใหม่ ("ถุงมือ"); เมื่อพิจารณาถึงข้อ จำกัด นี่เป็นคำตอบที่สง่างามและสอดคล้องกัน

ป้อน Java หลังจากตัดสินใจว่าทุกอย่าง C ++ นั้นทำไม่ดีและซับซ้อนเกินไป ประชดที่นี่คือที่ Java สามารถและได้ตัดสินใจที่จะทิ้งการจัดสรรสแต็ค (โดยไม่สนใจการพังทลายของดั้งเดิมซึ่งฉันได้กล่าวถึงที่อื่น) และเนื่องจากวัตถุทั้งหมดได้รับการจัดสรรบนฮีปจึงไม่จำเป็นต้องแยกแยะระหว่างการจัดสรรสแต็กและฮีป พวกเขาสามารถพูดได้อย่างง่ายดาย Cat x = Cat () หรือ Cat x = Cat ("ถุงมือ") หรือดียิ่งขึ้นรวมถึงการอนุมานประเภทเพื่อกำจัดการทำซ้ำ (แต่นั่น - และคุณสมบัติอื่น ๆ เช่นการปิด - จะใช้เวลา "นานเกินไป" ดังนั้นเราจึงติดอยู่กับ Java เวอร์ชันปานกลางแทนการอนุมานประเภท แต่ฉันจะ วางโอกาสที่จะไม่เกิดขึ้นและไม่ควรให้ปัญหาในการเพิ่มคุณสมบัติใหม่ให้กับ Java)


2
กองซ้อนกับกอง ... ชาญฉลาดไม่เคยมีความคิด
WernerCD

1
"การอนุมานประเภทได้ถูกพูดถึงแล้ว แต่ฉันจะวางราคาต่อรองว่าจะไม่เกิดขึ้น", :) ทีนี้การพัฒนา Java ยังคงดำเนินต่อไป น่าสนใจว่านี่เป็นเรือธงเดียวสำหรับ Java 10 varคำหลักคือไม่มีที่ไหนเลยใกล้ดีเท่าautoใน C ++ แต่ผมหวังว่ามันจะดีขึ้น
patrik

15

มีสองเหตุผลที่ฉันนึกถึง:

  • new แยกความแตกต่างระหว่างวัตถุและดั้งเดิม
  • newไวยากรณ์เป็นบิตอ่านได้มากขึ้น (IMO)

ที่แรกก็ไม่สำคัญ ฉันไม่คิดว่าจะเป็นการยากที่จะบอกทั้งสองอย่างนี้ ประการที่สองคือตัวอย่างของจุดของ OP ซึ่งnewเป็นประเภทที่ซ้ำซ้อน

แม้ว่าอาจมีความขัดแย้งของเนมสเปซ พิจารณา:

public class Foo {
   Foo() {
      // Constructor
   }
}

public class Bar {
   public static void main(String[] args) {
      Foo f = Foo();
   }

   public Foo Foo() {
      return Foo();
   }
}

คุณสามารถทำได้โดยไม่ต้องยืดจินตนาการมากเกินไปจบลงด้วยการเรียกซ้ำอย่างไม่สิ้นสุด คอมไพเลอร์จะต้องบังคับใช้ข้อผิดพลาด "ชื่อฟังก์ชันเหมือนกับวัตถุ" สิ่งนี้จะไม่เจ็บ แต่มันใช้ง่ายกว่าnewมากซึ่งกล่าวว่าGo to the object of the same name as this method and use the method that matches this signature.Java เป็นภาษาที่ง่ายมากในการแยกวิเคราะห์และฉันสงสัยว่านี่จะช่วยในพื้นที่นั้น


1
สิ่งนี้แตกต่างจากการเรียกซ้ำแบบไม่สิ้นสุดอื่น ๆ อย่างไร
DeadMG

นั่นเป็นภาพประกอบที่ดีพอสมควรเกี่ยวกับสิ่งเลวร้ายที่อาจเกิดขึ้นได้แม้ว่านักพัฒนาซอฟต์แวร์ที่ทำสิ่งนั้นจะมีปัญหาทางจิตใจที่รุนแรง
Tjaart

10

Java, หนึ่ง, ยังคงมีการแบ่งขั้วของ C ++ ไปนี้: ไม่ค่อนข้างทุกอย่างเป็นวัตถุ Java มีชนิดในตัว (เช่นcharและint) ที่ไม่จำเป็นต้องจัดสรรแบบไดนามิก

นั่นไม่ได้หมายความว่าnewจำเป็นจริงๆใน Java - ชุดของประเภทที่ไม่จำเป็นต้องจัดสรรแบบไดนามิกนั้นได้รับการแก้ไขและรู้จัก เมื่อคุณกำหนดวัตถุคอมไพเลอร์สามารถรู้ได้ (และอันที่จริงรู้แล้ว) ไม่ว่าจะเป็นค่าอย่างง่ายcharหรือวัตถุที่ต้องจัดสรรแบบไดนามิก

ฉันจะละเว้น (อีกครั้ง) ไม่ให้ความสำคัญกับคุณภาพของการออกแบบของ Java (หรือขาดมันไปแล้วแต่กรณี)


ยิ่งไปกว่านั้นประเภทดั้งเดิมไม่ต้องการการเรียกใช้คอนสตรัคเตอร์เลย - พวกมันถูกเขียนเป็นตัวอักษรมาจากตัวดำเนินการหรือจากฟังก์ชันคืนค่าดั้งเดิม คุณยังสร้างสตริง (ซึ่งอยู่ในกอง) จริง ๆ โดยที่ไม่มีnewดังนั้นนี่ไม่ใช่เหตุผลจริงๆ
Paŭlo Ebermann

9

ใน JavaScript คุณต้องการเพราะคอนสตรัคเตอร์ดูเหมือนฟังก์ชั่นปกติดังนั้น JS จะรู้ได้อย่างไรว่าคุณต้องการสร้างวัตถุใหม่ถ้ามันไม่ใช่สำหรับคำหลักใหม่?


4

ที่น่าสนใจ, VB ไม่ต้องการ - ความแตกต่างระหว่าง

Dim f As Foo

ซึ่งประกาศตัวแปรโดยไม่กำหนดค่าเท่ากับFoo f;ใน C # และ

Dim f As New Foo()

ซึ่งประกาศตัวแปรและกำหนดอินสแตนซ์ใหม่ของคลาสซึ่งเทียบเท่ากับvar f = new Foo();ใน C # คือความแตกต่างที่สำคัญ ใน pre-.NET VB คุณสามารถใช้Dim f As FooหรือDim f As New Foo- เพราะไม่มีการใช้งานเกินพิกัดในตัวสร้าง


4
VB ไม่ต้องการรุ่นชวเลข แต่เป็นเพียงตัวย่อ นอกจากนี้คุณยังสามารถเขียนเวอร์ชันที่ยาวขึ้นด้วยประเภทและตัวสร้าง Dim f As Foo = New Foo () ด้วย Option Infer On ซึ่งเป็นสิ่งที่ใกล้กับ C # มากที่สุดคุณสามารถเขียน Dim f = New Foo () และคอมไพเลอร์ทำให้ประเภทของ f
MarkJ

2
... และDim f As Foo()ประกาศอาร์เรย์ของFoos โอ้จอย! :-)
Heinzi

@ MarkJ: ใน vb.net ชวเลขนั้นเทียบเท่า ใน vb6 มันไม่ใช่ ใน vb6 Dim Foo As New Barจะสร้างFooคุณสมบัติที่จะสร้าง a Barถ้ามันถูกอ่านในขณะที่ (เช่นNothing) พฤติกรรมนี้ไม่ได้เกิดขึ้นเพียงครั้งเดียว การตั้งค่าFooไปแล้วอ่านมันจะสร้างใหม่อีกNothing Bar
supercat

4

ฉันชอบคำตอบมากมายและต้องการเพิ่มสิ่งนี้:
ทำให้การอ่านโค้ดง่ายขึ้น
ไม่ใช่ว่าสถานการณ์นี้จะเกิดขึ้นบ่อยครั้ง แต่คุณคิดว่าคุณต้องการวิธีการในนามของคำกริยาที่ใช้ชื่อเดียวกันกับคำนาม ภาษา C # และภาษาอื่น ๆ มีคำobjectสงวนไว้โดยธรรมชาติ แต่ถ้ามันไม่เป็นเช่นนั้นก็จะFoo = object()เป็นผลลัพธ์ของการเรียกเมธอด object หรือมันจะทำให้วัตถุใหม่ หวังว่าการพูดภาษาโดยไม่มีnewคำสำคัญมีการป้องกันสถานการณ์นี้ แต่โดยมีความต้องการของnewคำหลักก่อนที่จะเรียกคอนสตรัคเตอร์ที่คุณอนุญาตให้การดำรงอยู่ของวิธีการที่มีชื่อเดียวกันกับวัตถุ


4
เนื้อหาที่ต้องรู้ว่านี่เป็นสัญญาณที่ไม่ดี
DeadMG

1
@DeadMG:“ Arguably” หมายถึง“ ฉันจะเถียงว่าจนกว่าบาร์จะปิด” …
Donal Fellows

3

มีร่องรอยมากมายในภาษาการเขียนโปรแกรมมากมาย บางครั้งมันอยู่ที่นั่นด้วยการออกแบบ (C ++ ถูกออกแบบมาให้เข้ากันได้กับ C) บางครั้งมันอยู่ที่นั่น สำหรับตัวอย่างที่น่าเกรงขามมากขึ้นให้พิจารณาว่าswitchคำสั่งC ที่เสียหายที่เผยแพร่

ฉันไม่รู้ Javascript และ C # ที่ดีพอที่จะพูด แต่ฉันไม่เห็นเหตุผลnewใน Java ยกเว้น C ++ นั้นมี


ฉันคิดว่า JavaScript ได้รับการออกแบบมาให้ "ดูเหมือน Java มากที่สุด" แม้ว่าจะทำอะไรบางอย่างที่ไม่เหมือนกับ Java ก็ตาม x = new Y()ใน JavaScript ไม่instantiateYชั้นเพราะ JavaScript ไม่ต้องเรียน แต่ดูเหมือนว่า Java ดังนั้นจึงมีnewคำหลักส่งต่อจาก Java ซึ่งแน่นอนว่ามันยกมาจาก C ++
MatrixFrog

+1 สำหรับสวิตช์ที่เสียหาย (หวังว่าคุณจะซ่อมมัน: D)
maaartinus

3

ใน C # อนุญาตประเภทที่มองเห็นได้ในบริบทที่สมาชิกอาจถูกบดบัง ช่วยให้คุณมีคุณสมบัติที่มีชื่อเดียวกันกับประเภทของมัน พิจารณาสิ่งต่อไปนี้

class Address { 
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

class Person {
    public string Name { get; set; }
    public Address Address { get; set; }

    public void ChangeStreet(string newStreet) {
        Address = new Address { 
            Street = newStreet, 
            City = Address.City,
            State = Address.State,
            Zip = Address.Zip
        };
    }
}

หมายเหตุการใช้newอนุญาตให้ชัดเจนว่าAddressเป็นAddressประเภทที่ไม่ใช่Addressสมาชิก สิ่งนี้อนุญาตให้สมาชิกมีชื่อเดียวกับประเภท CAddressโดยไม่ต้องนี้คุณจะต้องคำนำหน้าชื่อของประเภทที่จะหลีกเลี่ยงการปะทะชื่อเช่น นี่เป็นความตั้งใจอย่างยิ่งเนื่องจาก Anders ไม่เคยชอบสัญกรณ์ฮังการีหรืออะไรที่คล้ายกันและต้องการให้ C # ใช้งานได้โดยปราศจากมัน ความจริงที่มันคุ้นเคยก็คือโบนัสสองเท่า


w00t และที่อยู่จะได้รับจากส่วนต่อประสานที่เรียกว่าที่อยู่ .. เท่านั้นไม่สามารถทำได้ ดังนั้นจึงไม่เป็นประโยชน์มากนักสามารถใช้ชื่อเดิมซ้ำและลดความสามารถในการอ่านโค้ดของคุณได้ ดังนั้นโดยการรักษา I สำหรับอินเทอร์เฟซ แต่เอา C ออกจากคลาสพวกเขาเพิ่งสร้างกลิ่นที่น่ารังเกียจสำหรับไม่มีประโยชน์ในทางปฏิบัติ
gbjbaanb

ฉันสงสัยว่าพวกเขาจะไม่ใช้ "ใหม่" แทนที่จะเป็น "ใหม่" บางคนสามารถบอกพวกเขาได้ว่ามีตัวอักษรตัวพิมพ์เล็กด้วยเช่นกันซึ่งเป็นวิธีแก้ปัญหานี้
maaartinus

คำที่สงวนไว้ทั้งหมดในภาษา C ที่ได้รับเช่น C # เป็นตัวพิมพ์เล็ก ไวยากรณ์ต้องการคำสงวนที่นี่เพื่อหลีกเลี่ยงความคลุมเครือดังนั้นการใช้ "ใหม่" แทน "ใหม่"
chuckj

@gbjbaanb ไม่มีกลิ่น เป็นที่ชัดเจนอย่างที่สุดเสมอว่าคุณกำลังอ้างถึงประเภทหรือคุณสมบัติ / สมาชิกหรือฟังก์ชั่น กลิ่นที่แท้จริงคือเมื่อคุณตั้งชื่อเนมสเปซเหมือนกับคลาส MyClass.MyClass
Stephen

0

สิ่งที่น่าสนใจคือการส่งต่อที่สมบูรณ์แบบnewไม่จำเป็นต้องมีตำแหน่งใด ๆ เลยใน C ++ เช่นกัน ดังนั้นจึงไม่จำเป็นต้องใช้ภาษาเหล่านี้อีกต่อไป


4
คุณจะส่งต่ออะไร ท้ายที่สุดstd::shared_ptr<int> foo();จะต้องโทรหาnew intอย่างใด
MSalters

0

ฉันไม่แน่ใจว่านักออกแบบ Java มีสิ่งนี้อยู่ในใจหรือไม่ แต่เมื่อคุณคิดว่าวัตถุเป็นเรคคอร์ดซ้ำคุณสามารถจินตนาการได้ว่าFoo(123)ไม่ส่งคืนวัตถุ แต่ฟังก์ชันที่ fixpoint เป็นวัตถุที่ถูกสร้างขึ้น (เช่นฟังก์ชันที่จะส่งคืน) วัตถุถ้าได้รับเป็นอาร์กิวเมนต์วัตถุที่ถูกสร้างขึ้น) และวัตถุประสงค์ของnewการ "ผูกปม" และกลับ fixpoint นั้น ในคำอื่น ๆnewจะทำให้วัตถุ "เพื่อจะ" selfตระหนักถึงมัน

วิธีการชนิดนี้สามารถช่วยให้การสืบทอดมรดกเป็นทางการตัวอย่างเช่น: คุณสามารถขยายฟังก์ชั่นวัตถุด้วยฟังก์ชั่นวัตถุอื่นและในที่สุดก็ให้พวกเขาร่วมกันselfโดยใช้new:

cp = new (Colored("Blue") & Line(0, 0, 100, 100))

ที่นี่&รวมสองฟังก์ชั่นวัตถุ

ในกรณีนี้newอาจหมายถึง:

def new(objectFunction) {
    actualObject = objectFunction(actualObject)
    return actualObject
}

-2

เพื่ออนุญาตให้ 'ไม่มี'

พร้อมกับการจัดสรรตามฮีป Java ยอมรับการใช้วัตถุศูนย์ ไม่ใช่เพียงแค่สิ่งประดิษฐ์ แต่เป็นคุณสมบัติ เมื่อวัตถุสามารถมีสถานะศูนย์จากนั้นคุณจะต้องแยกการประกาศจากการเริ่มต้น ดังนั้นคำหลักใหม่

ใน C ++ คล้ายกับบรรทัด

Person me;

จะเรียกตัวสร้างเริ่มต้นทันที


4
อืมมีอะไรผิดปกติกับPerson me = NilการPerson meเป็น Nil โดยปริยายและใช้Person me = Person()สำหรับผู้ที่ไม่ใช่ Nil ประเด็นของฉันคือดูเหมือนว่า Nil จะเป็นปัจจัยในการตัดสินใจครั้งนี้ ...
Andres F.

คุณมีประเด็น คนที่ฉัน = Person (); จะทำงานได้ดีเท่าเทียมกัน
Kris Van Bael

@AndresF หรือง่ายกว่าด้วยPerson meการเป็นศูนย์และPerson me()เรียกใช้ตัวสร้างปริยาย ดังนั้นคุณต้องใช้วงเล็บเสมอในการเรียกใช้สิ่งใดก็ตามและกำจัดความผิดปกติหนึ่ง C ++
maaartinus

-2

เหตุผลที่ Python ไม่ต้องการมันเป็นเพราะระบบการพิมพ์ของมัน โดยพื้นฐานแล้วเมื่อคุณเห็นfoo = bar()ใน Python มันไม่สำคัญว่าbar()จะมีวิธีการที่เรียกใช้หรือไม่คลาสที่กำลังสร้างอินสแตนซ์หรือวัตถุ functor ใน Python ไม่มีความแตกต่างพื้นฐานระหว่างฟังก์ชั่นและฟังก์ชั่น (เพราะวิธีการเป็นวัตถุ); และคุณอาจโต้แย้งได้ว่าคลาสที่เป็นอินสแตนซ์เป็นกรณีพิเศษของ functor ดังนั้นจึงไม่มีเหตุผลที่จะสร้างความแตกต่างของสิ่งประดิษฐ์ในสิ่งที่เกิดขึ้น (โดยเฉพาะอย่างยิ่งเมื่อการจัดการหน่วยความจำถูกซ่อนไว้อย่างมากใน Python)

ในภาษาที่มีระบบการพิมพ์ที่แตกต่างกันหรือวิธีการและคลาสที่ไม่ใช่วัตถุมีความเป็นไปได้ของความแตกต่างทางความคิดที่แข็งแกร่งระหว่างการสร้างวัตถุและการเรียกฟังก์ชันหรือ functor ดังนั้นแม้ว่าคอมไพเลอร์ / ล่ามไม่จำเป็นต้องใช้newคำหลักมันเป็นที่เข้าใจได้ว่ามันอาจได้รับการบำรุงรักษาในภาษาที่ไม่ได้ทำลายขอบเขตทั้งหมดที่ Python มี


-4

จริงๆแล้วใน Java มีความแตกต่างเมื่อใช้ Strings:

String myString = "myString";

แตกต่างจาก

String myString = new String("myString");

หาก"myString"ไม่เคยใช้สตริงมาก่อนประโยคคำสั่งแรกจะสร้างวัตถุ String เดี่ยวในกลุ่ม String (พื้นที่พิเศษของฮีป) ในขณะที่คำสั่งที่สองสร้างวัตถุสองรายการหนึ่งรายการในพื้นที่ฮีปปกติสำหรับวัตถุและอื่น ๆ ใน String Pool . เป็นที่ชัดเจนว่าประโยคที่สองนั้นไม่มีประโยชน์ในสถานการณ์เฉพาะนี้ แต่สามารถใช้ได้กับภาษา

ซึ่งหมายความว่าใหม่มั่นใจว่าวัตถุถูกสร้างขึ้นในพื้นที่พิเศษของกองที่จัดสรรสำหรับการสร้างอินสแตนซ์ของวัตถุปกติ แต่อาจมีวิธีอื่นของอินสแตนซ์วัตถุโดยไม่ต้องมัน; ตัวอย่างข้างต้นเป็นตัวอย่างและมีห้องเหลือสำหรับการขยาย


2
แต่นี่ไม่ใช่คำถาม คำถามคือ "ทำไมไม่String myString = String("myString");" (โปรดสังเกตว่าไม่มีnewคำหลัก)
Andres F.

@AndresF ชนิดของ imho ชัดเจน ... มันถูกกฎหมายที่จะมีเมธอดชื่อ String ที่ส่งคืนสตริงในคลาส String และจะต้องมีความแตกต่างระหว่างการเรียกมันและการเรียกคอนสตรัคเตอร์ มีบางอย่างที่เหมือนกันclass MyClass { public MyClass() {} public MyClass MyClass() {return null;} public void doSomething { MyClass myClass = MyClass();}} //which is it, constructor or method?
m3th0dman

3
แต่มันไม่ชัดเจน ก่อนอื่นการมีเมธอดปกติที่มีชื่อว่าStringขัดแย้งกับการจัดวางสไตล์ Java ดังนั้นคุณสามารถสันนิษฐานได้ว่าเมธอดใด ๆ ที่ขึ้นต้นด้วยตัวพิมพ์ใหญ่เป็นตัวสร้าง และอย่างที่สองถ้าเราไม่ได้ถูก จำกัด โดย Java ดังนั้น Scala มี "case classes" ซึ่งตัวสร้างดูเหมือนกับที่ฉันพูด ดังนั้นปัญหาอยู่ที่ไหน
Andres F.

2
ขออภัยฉันไม่ทำตามอาร์กิวเมนต์ของคุณ คุณจะมีประสิทธิภาพการโต้เถียงไวยากรณ์ไม่ความหมายและอยู่แล้วคำถามที่เกี่ยวกับnewสำหรับภาษาที่มีการจัดการ ฉันได้แสดงให้เห็นว่าnewไม่จำเป็นเลย (เช่น Scala ไม่ต้องการมันสำหรับคลาสเคส) และยังไม่มีความกำกวม (เนื่องจากคุณไม่มีวิธีการตั้งชื่อMyClassในคลาสอย่างแน่นอนMyClass) มีความคลุมเครือไม่มีสำหรับString s = String("hello"); มันไม่สามารถเป็นอย่างอื่นได้นอกจากเป็นคอนสตรัคเตอร์ และในที่สุดฉันก็ไม่เห็นด้วย: มีการใช้โค้ดเพื่อปรับปรุงและชี้แจงไวยากรณ์ซึ่งเป็นสิ่งที่คุณโต้เถียงกันอยู่!
Andres F.

1
นั่นคือเหตุผลของคุณ? "ผู้ออกแบบ Java ต้องการnewคำหลักเพราะไม่เช่นนั้นไวยากรณ์ของ Java จะแตกต่าง" หรือไม่? ฉันแน่ใจว่าคุณสามารถเห็นความอ่อนแอของการโต้แย้งนั้น) และใช่คุณพูดคุยเกี่ยวกับไวยากรณ์ไม่ใช่ความหมาย ยังย้อนกลับเข้ากันได้กับอะไร หากคุณกำลังออกแบบภาษาใหม่เช่น Java แสดงว่าคุณเข้ากันไม่ได้กับ C และ C ++!
Andres F.

-8

ใน C # ใหม่เป็นสิ่งสำคัญที่จะแยกแยะระหว่างวัตถุที่สร้างขึ้นในกองซ้อนกับกอง บ่อยครั้งที่เราสร้างวัตถุบนสแต็กเพื่อประสิทธิภาพที่ดีขึ้น ดูว่าเมื่อวัตถุในสแต็คไม่อยู่ในขอบเขตมันจะหายไปทันทีเมื่อสแต็คคลี่คลายเหมือนวัตถุดั่งเดิม ไม่จำเป็นสำหรับตัวรวบรวมขยะเพื่อติดตามมันและไม่มีค่าใช้จ่ายเพิ่มเติมของตัวจัดการหน่วยความจำในการจัดสรรพื้นที่ที่จำเป็นในกอง


5
โชคไม่ดีที่คุณสับสน C # กับ C ++
gbjbaanb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.