นักพัฒนา C # ที่เรียนรู้ Java อะไรคือความแตกต่างที่ใหญ่ที่สุดที่อาจมองข้ามไป? [ปิด]


87

สำหรับนักพัฒนา c # ที่ต้องการเรียนรู้ Java มีความแตกต่างที่สำคัญระหว่างสองภาษาที่ควรระบุหรือไม่?

บางทีบางคนอาจคิดว่าเหมือนกัน แต่มีแง่มุมการนำเข้าที่ไม่ควรมองข้าม? (หรือคุณจะทำผิดจริงๆ!)

อาจเป็นในแง่ของโครงสร้าง OOP วิธีการทำงานของ GC การอ้างอิงการปรับใช้ที่เกี่ยวข้อง ฯลฯ



นอกจากนี้ยังstackoverflow.com/questions/295224/...
Michael Myers

นอกจากนี้ยังมีแนวโน้มที่จะถูกมองข้ามอีกด้วยคือ "คุณลักษณะที่ซ่อนอยู่ของ C #" stackoverflow.com/questions/9033/hidden-features-of-c
John K

คำตอบ:


122

ไม่กี่ gotchas จากด้านบนของหัวของฉัน:

  • Java ไม่มีประเภทค่าที่กำหนดเอง (โครงสร้าง) ดังนั้นอย่ากังวลกับการค้นหา
  • Java enums มีความแตกต่างอย่างมากกับวิธีการ "ระบุชื่อ" ของ C #; พวกเขา OO มากกว่า สามารถใช้เพื่อให้ได้ผลดีเยี่ยมหากคุณระมัดระวัง
  • byte ลงนามใน Java (ขออภัย)
  • ใน C # ตัวเริ่มต้นตัวแปรอินสแตนซ์จะทำงานก่อนที่ตัวสร้างคลาสพื้นฐานจะทำ ใน Java ที่พวกเขาทำงานหลังจากนั้น (เช่นก่อนตัวสร้างตัวสร้างในคลาส "นี้")
  • ในวิธีการ C # ถูกปิดผนึกโดยค่าเริ่มต้น ใน Java เป็นเสมือนโดยค่าเริ่มต้น
  • ตัวปรับการเข้าถึงเริ่มต้นใน C # คือ "การเข้าถึงที่ จำกัด ที่สุดที่มีอยู่ในบริบทปัจจุบันเสมอ"; ใน Java เป็นการเข้าถึงแบบ "แพ็กเกจ" (ควรอ่านข้อมูลเกี่ยวกับตัวปรับการเข้าถึงเฉพาะใน Java)
  • ประเภทที่ซ้อนกันใน Java และ C # ทำงานแตกต่างกันบ้าง โดยเฉพาะอย่างยิ่งพวกเขามีข้อ จำกัด การเข้าถึงที่แตกต่างกันและเว้นแต่คุณจะประกาศประเภทที่ซ้อนกันเป็นstaticมันจะมีการอ้างอิงโดยปริยายไปยังอินสแตนซ์ของคลาสที่มี

5
+1 นี่เป็นรายการที่ยอดเยี่ยมสำหรับผู้เริ่มต้น
Jim Schubert

3
@ Jon Skeet: +1 และคุณอาจจะพลาด Lambda และ LINQ จนถึง Java 7?
Kb.

1
"ใน C # ตัวเริ่มต้นตัวแปรอินสแตนซ์จะทำงานก่อนที่คอนสตรัคคลาสพื้นฐานจะทำงานใน Java จะรันหลังจากนั้น (กล่าวคือก่อนเนื้อหาตัวสร้างในคลาส" นี้ ") - เอียร์คุณช่วยอธิบายให้ละเอียดได้ไหม ไม่แน่ใจว่าฉันเข้าใจที่คุณพูดจริงๆ :)
cwap

7
@cwap: ใน C # ลำดับการดำเนินการคือ "initializers ตัวแปรอินสแตนซ์ตัวสร้างคลาสฐานตัวสร้างตัวสร้าง" ใน Java มันคือ "superclass constructor, instance variable initializers, constructor body" (ตัวเริ่มต้นตัวแปรอินสแตนซ์คือสิ่งที่คุณจะได้รับเมื่อคุณกำหนดค่าให้กับตัวแปรอินสแตนซ์ ณ จุดประกาศ)
Jon Skeet

1
@cwap: ใช่นั่นคือสิ่งที่ฉันหมายถึง - อันหลังคือตัวเริ่มต้นวัตถุ
Jon Skeet


17

ฉันแปลกใจที่ไม่มีใครพูดถึงคุณสมบัติบางอย่างที่เป็นพื้นฐานใน C # แต่ไม่มีใน Java C # 3 ขึ้นไปมีการใช้คุณสมบัติโดยอัตโนมัติเช่นกัน ใน Java คุณต้องใช้เมธอดประเภท GetX / SetX

ความแตกต่างที่ชัดเจนอีกประการหนึ่งคือนิพจน์ LINQ และแลมบ์ดาใน C # 3 ไม่มีใน Java

มีสิ่งอื่น ๆ ที่เรียบง่าย แต่มีประโยชน์ที่ขาดหายไปจาก Java เช่นสตริงคำต่อคำ (@ "") การโอเวอร์โหลดตัวดำเนินการตัววนซ้ำที่ใช้ผลตอบแทนและตัวประมวลผลก่อนขาดใน Java เช่นกัน

หนึ่งในรายการโปรดส่วนตัวของฉันใน C # คือชื่อเนมสเปซไม่จำเป็นต้องเป็นไปตามโครงสร้างไดเร็กทอรีจริง ฉันชอบความยืดหยุ่นนี้มาก


10

มีความแตกต่างมากมาย แต่สิ่งเหล่านี้อยู่ในใจฉัน:

  • ขาดตัวดำเนินการใน Java มากเกินไป ดูอินสแตนซ์ของคุณ Equals (instance2) กับ instance == instance2 (โดยเฉพาะ w / strings)
  • คุ้นเคยกับอินเทอร์เฟซที่ไม่มีคำนำหน้าด้วย I บ่อยครั้งที่คุณเห็นเนมสเปซหรือคลาสที่ต่อท้ายด้วย Impl แทน
  • การล็อกที่ตรวจสอบซ้ำไม่ทำงานเนื่องจากโมเดลหน่วยความจำ Java
  • คุณสามารถอิมพอร์ตเมธอดแบบคงที่โดยไม่ต้องนำหน้าด้วยชื่อคลาสซึ่งมีประโยชน์มากในบางกรณี (DSL)
  • เปลี่ยนคำสั่งใน Java ไม่จำเป็นต้องมีค่าเริ่มต้นและคุณไม่สามารถใช้สตริงเป็นเลเบลเคส (IIRC)
  • ชื่อสามัญของ Java จะทำให้คุณโกรธ Java generics ไม่มีอยู่ในรันไทม์ (อย่างน้อยใน 1.5) เป็นเคล็ดลับคอมไพเลอร์ซึ่งทำให้เกิดปัญหาหากคุณต้องการสะท้อนประเภททั่วไป

4
ล่าสุดฉันตรวจสอบสตริงไม่เกิน == และฉันไม่เคยได้ยินว่ามีการเพิ่มสำหรับ Java 7 ด้วย อย่างไรก็ตามพวกเขาทำ overload + สำหรับการต่อสายอักขระ
Michael Madsen

3
ใช่การเปรียบเทียบสตริงกับ == เป็นข้อผิดพลาดที่พบบ่อยมากสำหรับมือใหม่ .equalsคือสิ่งที่คุณต้องใช้
Michael Myers

นอกจากนี้ฉันไม่เข้าใจความคิดเห็นเกี่ยวกับวิธีการคงที่ ภาษาทั้งหมดไม่ค่อยอนุญาตให้ใช้วิธีการคงที่หรือเทียบเท่า?
Michael Myers

ฉันเกือบจะโหวตเรื่องนี้แล้ว แต่ฉันไม่เห็นด้วยเกี่ยวกับยาชื่อสามัญ ฉันชอบประเภทลบ
finnw

2
"เปลี่ยนคำสั่งใน Java ไม่จำเป็นต้องมีค่าเริ่มต้น" - และ C # ไม่
RenniePet

8

.NET ได้สร้างชื่อสามัญ; Java ได้ลบข้อมูลทั่วไป

ความแตกต่างคือ: ถ้าคุณมีArrayList<String>วัตถุใน .NET คุณสามารถบอก (ที่รันไทม์) ว่าวัตถุที่มีประเภทArrayList<String>ขณะที่ใน Java ที่รันไทม์วัตถุที่เป็นประเภทArrayList; Stringส่วนหนึ่งจะหายไป หากคุณใส่สิ่งที่ไม่ใช่Stringสิ่งของเข้าไปในArrayListระบบจะไม่สามารถบังคับใช้สิ่งนั้นได้และคุณจะรู้ก็ต่อเมื่อคุณพยายามดึงไอเทมออกและการร่ายล้มเหลว


1
... แม้ว่าจะมีมูลค่าเพิ่มที่คุณไม่สามารถใส่Stringวัตถุที่ไม่ใช่ในรายการนั้นได้โดยไม่ต้องทำการแคสต์ที่ไม่ได้ตรวจสอบที่ไหนสักแห่งและคอมไพเลอร์จะเตือนคุณอย่างถูกต้อง ณ จุดนั้นว่าคอมไพเลอร์ไม่สามารถตรวจสอบขอบเขตทั่วไปได้อีกต่อไป ตราบใดที่รายการของคุณมักจะเก็บไว้ในตัวแปรของList<String>ความพยายามที่จะแทรกวัตถุที่ไม่ใช่ String เข้ามันจะไม่ได้รวบรวม
Andrzej Doyle

"ไม่ใช่วัตถุ String เข้า ArrayList ระบบไม่สามารถบังคับใช้ว่า" โปรดทราบว่าระบบไม่บังคับมันที่รวบรวมเวลา อย่างไรก็ตามคุณสามารถหลีกเลี่ยงสิ่งนี้ได้โดยการคัดเลือก (หรือไม่ใช้ยาสามัญ) จากนั้นการตรวจสอบรันไทม์จะตรวจจับ แต่เมื่อแตกไฟล์เท่านั้น
sleske

1
@Andrzej, @sleske: ฉันพูดถึงรันไทม์เท่านั้น สมมติว่าคุณได้รับวัตถุผ่านการสะท้อนและเรียกใช้addวิธีการของมัน(อีกครั้งผ่านการสะท้อน) ระบบจะปฏิเสธสิ่งที่ไม่ใช่Stringวัตถุทันทีหรือเมื่อส่งผลลัพธ์ของget?
Chris Jester-Young

@sleske: แต่ IIRC คุณต้องการเพียงการร่ายโดยปริยายเพื่อหลีกเลี่ยงการตรวจสอบประเภท
Niki

@Judah: ผมย้อนกลับการเปลี่ยนแปลงของคุณ (ใช่ปีหลังจากความจริง) Listเพราะคุณไม่สามารถมีวัตถุประเภท คุณสามารถมีวัตถุประเภทลงมาจากListเหมือนและArrayList LinkedList(สิ่งสำคัญคือต้องใช้ListแทนการArrayListเดินผ่านพวกเขาไปรอบ ๆ แต่มันไม่ได้เปลี่ยนความจริงที่คุณไม่สามารถพูดnew List()ได้)
Chris Jester-Young

6

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


1
FWIW นี่ถือว่าอยู่ใน dev't ของ C # และเหตุผลในการปล่อยให้พวกเขาออกไปนั้นเป็นเรื่องจริง พิจารณาartima.com/intv/handcuffs.html ไม่ใช่ว่านักออกแบบจะไม่เห็นด้วยกับข้อยกเว้นในทางปรัชญา แต่พวกเขากำลังรอเทคนิคที่ดีกว่าซึ่งให้ประโยชน์ที่คล้ายคลึงกันโดยไม่มีข้อเสียที่มีขนดกทั้งหมด
Greg D

ใช่ใช่เรื่องที่ถกเถียงกันมาก ...
sleske

2
ฉันชอบความจริงที่ว่า C # ไม่ได้ตรวจสอบข้อยกเว้น แต่นี่เป็นโพสต์แรกที่ชี้ให้เห็นถึงความแตกต่างดังนั้น +1
นิค

5

Java มี autoboxing สำหรับ primitives แทนที่จะเป็นประเภท value ดังนั้นแม้ว่าSystem.Int32[]จะเป็นอาร์เรย์ของค่าใน C # แต่Integer[]ก็เป็นอาร์เรย์ของการอ้างอิงถึงอIntegerอบเจ็กต์และด้วยเหตุนี้จึงไม่เหมาะสำหรับการคำนวณประสิทธิภาพที่สูงขึ้น


1
Pete: นั่นเป็นจุดที่ยอดเยี่ยมและเป็นสิ่งที่ฉันไม่เคยรู้หรืออย่างน้อยก็ไม่เคยพิจารณา (เป็นนักพัฒนา C # และยังใหม่กับ Java)
Jim Schubert

4

ไม่มีผู้รับมอบสิทธิ์หรือกิจกรรม - คุณต้องใช้อินเทอร์เฟซ โชคดีที่คุณสามารถสร้างคลาสและการใช้งานอินเทอร์เฟซแบบอินไลน์ได้ดังนั้นนี่จึงไม่ใช่เรื่องใหญ่


3
“ ไม่ใช่เรื่องใหญ่”. ขวา. เพราะx => x.Fooกับnew Bar() { public void M(SomeType x) { return x.Foo; } }- ใครสนใจว่าโค้ดจะสั้นกว่า 10 เท่า?
Kirk Woll

2

ฟังก์ชันวันที่ / ปฏิทินในตัวใน Java นั้นแย่มากเมื่อเทียบกับ System.DateTime มีข้อมูลมากมายเกี่ยวกับเรื่องนี้ที่นี่: Java Date & Time API มีอะไรผิดปกติ?

สิ่งเหล่านี้บางส่วนสามารถ gotchas สำหรับนักพัฒนา C #:

  • คลาส Java Date ไม่แน่นอนซึ่งอาจทำให้วันที่ส่งคืนและวันที่ผ่านไปเกิดอันตรายได้
  • ตัวสร้าง java.util.Date ส่วนใหญ่เลิกใช้งานแล้ว เพียงแค่สร้างอินสแตนซ์วันที่ก็ค่อนข้างละเอียด
  • ฉันไม่เคยได้รับคลาส java.util.Date เพื่อให้ทำงานร่วมกันได้ดีกับบริการเว็บ ในกรณีส่วนใหญ่วันที่ทั้งสองข้างถูกเปลี่ยนเป็นวันที่และเวลาอื่นอย่างสิ้นเชิง

นอกจากนี้ Java ยังไม่มีคุณลักษณะทั้งหมดเหมือนกับที่ GAC และแอสเซมบลีที่มีชื่อเรียกอย่างชัดเจน Jar Hellเป็นคำศัพท์สำหรับสิ่งที่อาจผิดพลาดเมื่อเชื่อมโยง / อ้างอิงไลบรารีภายนอก

เท่าที่เกี่ยวข้องกับบรรจุภัณฑ์ / การปรับใช้:

  • อาจเป็นเรื่องยากที่จะจัดแพ็กเกจเว็บแอปพลิเคชันในรูปแบบ EAR / WAR ที่ติดตั้งและรันในแอปพลิเคชันเซิร์ฟเวอร์ต่างๆ (Glassfish, Websphere และอื่น ๆ ) ได้ยาก
  • การปรับใช้แอป Java ของคุณเป็นบริการ Windows ต้องใช้ความพยายามมากกว่าใน C # คำแนะนำส่วนใหญ่ที่ฉันได้รับสำหรับเรื่องนี้เกี่ยวข้องกับไลบรารีของบุคคลที่สามที่ไม่ฟรี
  • การกำหนดค่าแอปพลิเคชันไม่ง่ายเหมือนการรวมไฟล์ app.config ไว้ในโปรเจ็กต์ของคุณ มีคลาส java.util.Properties แต่มันไม่แข็งแกร่งเท่าและการค้นหาจุดที่เหมาะสมในการวางไฟล์. คุณสมบัติของคุณอาจทำให้สับสนได้

1

ไม่มีผู้รับมอบสิทธิ์ใน Java ดังนั้นนอกเหนือจากผลประโยชน์ทั้งหมดที่ผู้ได้รับมอบหมายนำมาสู่โต๊ะแล้วเหตุการณ์ก็แตกต่างกันไปเช่นกัน แทนที่จะเชื่อมต่อกับวิธีการคุณต้องใช้อินเทอร์เฟซและแนบแทน


1

สิ่งหนึ่งที่กระโดดออกมา b / c ในรายการสัมภาษณ์ของฉันคือไม่มีอะนาล็อกคำหลัก "ใหม่" ใน Java สำหรับการซ่อนวิธีการและไม่มีคำเตือนของคอมไพเลอร์ "คุณควรใส่ใหม่ที่นี่" วิธีการโดยบังเอิญซ่อนเมื่อคุณต้องการลบล้างโอกาสในการขายไปสู่จุดบกพร่อง

(แก้ไขตัวอย่าง) ตัวอย่าง B มาจาก A (โดยใช้ไวยากรณ์ C # Java จะทำงานในลักษณะเดียวกันล่าสุดที่ฉันตรวจสอบ แต่ไม่ส่งคำเตือนคอมไพเลอร์) A's foo ถูกเรียกหรือ B's foo? (ถูกเรียกว่า A น่าจะแปลกใจที่ dev ที่ใช้ B)

class A 
{
public void foo() {code}
}

class B:A
{
public void foo() {code}
}    

void SomeMethod()
{
A a = new B(); // variable's type is declared as A, but assigned to an object of B.
a.foo();
}

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

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

1
ความแตกต่างที่นี่คือใน Java วิธีการทั้งหมดเป็นเสมือน (ดังนั้นใน Java จะเป็น B.foo () ที่ถูกเรียกเนื่องจาก Java จะส่งวิธีการแบบไดนามิกเสมอ) ในขณะที่วิธีการ C # จะไม่เสมือนตามค่าเริ่มต้น (และ A.foo () จะเรียกว่า) ตัวตรวจสอบรูปแบบการเข้ารหัสจำนวนมากสำหรับ Java จะบอกคุณว่า B ควรใช้คำอธิบายประกอบ @Override
William Billingsley

1

Java ไม่มี LINQ และเอกสารประกอบคือนรก อินเทอร์เฟซผู้ใช้ใน Java เป็นความเจ็บปวดในการพัฒนาคุณสูญเสียสิ่งดีๆทั้งหมดที่ Microsoft มอบให้เรา (WPF, WCF ฯลฯ ... ) แต่ใช้งานยากแทบจะไม่มีเอกสาร "APIs"


0

ปัญหาหนึ่งที่ฉันพบเมื่อทำงานกับ Java ที่มาจาก C # คือข้อยกเว้นและข้อผิดพลาดแตกต่างกัน

ตัวอย่างเช่นคุณไม่สามารถตรวจจับข้อผิดพลาดหน่วยความจำไม่เพียงพอโดยใช้ catch (Exception e)

ดูรายละเอียดเพิ่มเติมดังต่อไปนี้:

เหตุใดจึงเป็น -Java-lang-outofmemoryerror-java-heap-space-not-caught


ออกแบบมาโดยเจตนาเพื่อกีดกันโปรแกรมเมอร์แอปพลิเคชันจากการจับมัน
finnw

ใช่ฉันแน่ใจว่าเป็นอย่างนั้น แต่มาจากฝั่ง C # ซึ่งสิ่งที่คุณต้องกังวลคือการจับข้อยกเว้นโยนฉันวนไป :)
Chris Persichetti

0

เป็นเวลานานมากแล้วที่ฉันใช้ Java แต่สิ่งที่ฉันสังเกตเห็นได้ทันทีในการพัฒนาแอปพลิเคชันคือ C # event model, C # drag and drop เทียบกับการใช้ Layout Managers ใน Swing (ถ้าคุณทำ App dev) และการจัดการข้อยกเว้นด้วย Java ตรวจสอบให้แน่ใจว่าคุณพบข้อยกเว้นและไม่จำเป็นต้องใช้ C #


0

เพื่อตอบคำถามที่ตรงประเด็นของคุณในชื่อเรื่อง:

"นักพัฒนา C # ที่เรียน Java ความแตกต่างที่ใหญ่ที่สุดที่อาจมองข้ามไปคืออะไร"

ตอบ: ความจริงที่ว่า Java ทำงานช้ากว่าใน Windows มาก


4
ฉันใช้ OpenSuSE 64 บิตและ Windows 7 64 บิตและ Eclipse IDE ("ดูเหมือน") เร็วกว่าใน Windows คำตอบของคุณมาจากการสังเกตส่วนบุคคลหรือจากเกณฑ์มาตรฐานจริงหรือไม่?
Jim Schubert

0

ความแตกต่างที่ชัดเจนที่สุดสำหรับฉันเมื่อฉันเปลี่ยนเป็น java มันคือการประกาศสตริง

ใน C # string(โดยส่วนใหญ่) ใน JavaString

มันค่อนข้างง่าย แต่เชื่อฉันเถอะว่ามันทำให้คุณเสียเวลาไปมากเมื่อคุณมีนิสัยที่จะsไม่ทำS!

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