Pengembang C # yang mempelajari Java, apa perbedaan terbesar yang mungkin diabaikan? [Tutup]

87

Untuk c # developer yang ingin mempelajari Java, apakah ada perbedaan mendasar yang besar antara kedua bahasa yang harus ditunjukkan?

Mungkin sebagian orang mungkin menganggap hal-hal sama, tetapi ada beberapa aspek impor yang tidak boleh terlewatkan? (atau Anda benar-benar bisa mengacau!)

Mungkin dalam hal konstruksi OOP, cara kerja GC, referensi, terkait penerapan, dll.

mrblah
sumber

Jawaban:

122

Beberapa gotcha di luar kepala saya:

  • Java tidak memiliki tipe nilai kustom (struct) jadi jangan repot-repot mencarinya
  • Enum Java sangat berbeda dengan pendekatan "nomor bernama" dari C #; mereka lebih OO. Mereka dapat digunakan dengan efek yang bagus, jika Anda berhati-hati.
  • byte masuk di Java (sayangnya)
  • Dalam C #, penginisialisasi variabel instance dijalankan sebelum konstruktor kelas dasar melakukannya; di Java mereka berjalan setelah itu (yaitu tepat sebelum badan konstruktor di kelas "ini")
  • Dalam C # metode disegel secara default. Di Java, mereka virtual secara default.
  • Pengubah akses default di C # selalu "akses paling terbatas yang tersedia dalam konteks saat ini"; di Java itu adalah akses "paket". (Ada baiknya membaca tentang pengubah akses tertentu di Java.)
  • Jenis bersarang di Java dan C # bekerja agak berbeda; khususnya mereka memiliki batasan akses yang berbeda, dan kecuali Anda mendeklarasikan tipe bertingkat menjadi staticitu akan memiliki referensi implisit ke sebuah instance dari kelas yang memuatnya.
Jon Skeet
sumber
5
+1 Ini adalah daftar yang bagus untuk pemula.
Jim Schubert
3
@ Jon Skeet: +1, Dan Anda mungkin akan merindukan Lambda dan LINQ hingga Java 7?
Kb.
1
"Dalam C #, penginisialisasi variabel instance dijalankan sebelum konstruktor kelas dasar berjalan; di Java mereka berjalan setelahnya (yaitu tepat sebelum badan konstruktor dalam kelas" ini ")" - Eeer, dapatkah Anda menguraikan ini? Tidak yakin saya benar-benar mengerti apa yang Anda katakan :)
cwap
7
@cwap: Dalam C #, urutan eksekusi adalah "penginisialisasi variabel instance, konstruktor kelas dasar, badan konstruktor". Di Java, ini adalah "konstruktor superclass, penginisialisasi variabel instance, body konstruktor". (Penginisialisasi variabel instans adalah apa yang Anda dapatkan ketika Anda menetapkan nilai ke variabel instans pada titik deklarasi.)
Jon Skeet
1
@cwap: Ya, itulah yang saya maksud - yang terakhir adalah penginisialisasi objek .
Jon Skeet
17

Saya terkejut bahwa tidak ada yang menyebutkan properti, sesuatu yang cukup mendasar di C # tetapi tidak ada di Java. C # 3 dan di atasnya juga telah menerapkan properti secara otomatis. Di Java Anda harus menggunakan metode tipe GetX / SetX.

Perbedaan nyata lainnya adalah ekspresi LINQ dan lambda di C # 3 yang tidak ada di Java.

Ada beberapa hal sederhana namun berguna lainnya yang hilang dari Java seperti string verbatim (@ ""), operator overloading, iterator yang menggunakan hasil dan pra prosesor juga hilang di Java.

Salah satu favorit pribadi saya di C # adalah nama namespace tidak harus mengikuti struktur direktori fisik. Saya sangat menyukai fleksibilitas ini.

softveda
sumber
10

Ada banyak perbedaan, tetapi ini yang terpikir oleh saya:

  • Kurangnya kelebihan beban operator di Jawa. Perhatikan instance Anda.Sama (instance2) versus instance == instance2 (terutama dengan string).
  • Biasakan diri dengan antarmuka yang TIDAK diawali dengan I. Seringkali Anda melihat namespace atau kelas diakhiri dengan Impl.
  • Penguncian yang dicentang ganda tidak berfungsi karena model memori Java.
  • Anda dapat mengimpor metode statis tanpa mengawalinya dengan nama kelas, yang sangat berguna dalam kasus tertentu (DSL).
  • Pernyataan switch di Java tidak memerlukan default, dan Anda tidak dapat menggunakan string sebagai label kasus (IIRC).
  • Obat generik Java akan membuat Anda marah. Java generik tidak ada saat runtime (setidaknya di 1.5), ini adalah trik compiler, yang menyebabkan masalah jika Anda ingin melakukan refleksi pada tipe generik.
Sneal
sumber
4
Terakhir saya periksa, string TIDAK membebani ==, dan saya belum pernah mendengarnya ditambahkan untuk Java 7 juga. Namun, mereka membebani + untuk penggabungan string.
Michael Madsen
3
Ya, membandingkan string dengan == adalah kesalahan yang sangat umum bagi pemula. .equalsadalah apa yang harus Anda gunakan.
Michael Myers
Juga, saya tidak mengerti komentar tentang metode statis. Bukankah hampir semua bahasa mengizinkan metode statis atau yang setara?
Michael Myers
Saya hampir memilih ini, tetapi saya tidak setuju tentang obat generik. Saya suka tipe penghapusan.
finnw
2
"Pernyataan switch di Java tidak memerlukan default" - begitu pula C #.
RenniePet
8

.NET telah membuktikan obat generik; Java telah menghapus obat generik.

Perbedaannya adalah: jika Anda memiliki sebuah ArrayList<String>objek, dalam .NET, Anda dapat mengetahui (pada waktu proses) bahwa objek tersebut memiliki tipe ArrayList<String>, sedangkan di Java, pada waktu proses, objek tersebut bertipe ArrayList; yang Stringbagian yang hilang. Jika Anda memasukkan non- Stringobjek ke dalam ArrayList, sistem tidak dapat memaksakannya, dan Anda hanya akan mengetahuinya setelah Anda mencoba mengekstrak item keluar, dan cast gagal.

Chris Jester-Young
sumber
1
... meskipun perlu ditambahkan bahwa Anda tidak dapat meletakkan non- Stringobjek dalam daftar itu tanpa membuat cast yang tidak dicentang, di suatu tempat , dan kompilator akan memperingatkan Anda dengan benar pada saat itu bahwa kompilator tidak dapat lagi memeriksa batas-batas generik. Selama daftar Anda selalu disimpan dalam variabel List<String>, upaya untuk memasukkan objek non-String ke dalamnya tidak akan dapat dikompilasi.
Andrzej Doyle
"objek non-String ke dalam ArrayList, sistem tidak dapat memaksakannya": Perhatikan bahwa sistem memang memberlakukannya pada waktu kompilasi. Namun Anda dapat menghindari ini dengan mentransmisikan (atau tidak menggunakan obat generik); maka pemeriksaan runtime akan menangkapnya, tetapi hanya saat mengekstrak.
sleske
1
@Andrzej, @sleske: Saya hanya berbicara tentang runtime. Katakanlah Anda mendapatkan objek melalui refleksi, dan menjalankan addmetodenya (sekali lagi, melalui refleksi). Akankah sistem langsung menolak non- Stringobjek, atau hanya saat mentransmisikan hasil get?
Chris Jester-Young
@sleske: Tapi IIRC Anda hanya perlu cast implisit untuk menghindari pemeriksaan jenis.
Niki
@ Yehuda: Saya membatalkan perubahan Anda (ya, setahun setelah fakta), karena Anda tidak dapat memiliki objek bertipe List. Anda dapat memiliki objek berjenis turun dari List, seperti ArrayListdan LinkedList. (Ini penting untuk digunakan Listalih-alih ArrayListsaat membagikannya, tetapi itu tidak mengubah fakta bahwa Anda tidak dapat mengatakannya new List().)
Chris Jester-Young
6

Satu hal yang saya lewatkan di C # dari Java adalah penanganan paksa dari pengecualian yang dicentang. Dalam C #, sangat umum bahwa seseorang tidak menyadari pengecualian yang mungkin dilemparkan metode dan Anda bergantung pada dokumentasi atau pengujian untuk menemukannya. Tidak demikian halnya di Jawa dengan pengecualian yang dicentang.

Sean
sumber
1
FWIW, ini telah dipertimbangkan dalam pengembangan C # dan alasan untuk meninggalkannya adalah nyata. Pertimbangkan artima.com/intv/handcuffs.html . Bukan karena para desainer secara filosofis menentang pengecualian yang dicentang - melainkan, mereka sedang menunggu teknik yang lebih baik yang menawarkan manfaat serupa tanpa semua kekurangan berbulu.
Greg D
Ya, ya, subjek yang sangat kontroversial ...
sleske
2
Saya suka fakta bahwa C # tidak memeriksa pengecualian, tetapi ini adalah pos pertama yang menunjukkan perbedaannya, jadi +1.
Nick
5

Java memiliki autoboxing untuk primitif daripada tipe nilai, jadi meskipun System.Int32[]array nilai dalam C #, Integer[]adalah array referensi ke Integerobjek, dan dengan demikian tidak cocok untuk penghitungan kinerja yang lebih tinggi.

Pete Kirkham
sumber
1
Pete: itu poin yang sangat baik, dan yang saya tidak pernah tahu atau setidaknya tidak pernah dipertimbangkan (menjadi pengembang C # dan baru mengenal Java).
Jim Schubert
4

Tidak ada delegasi atau acara - Anda harus menggunakan antarmuka. Untungnya, Anda dapat membuat kelas dan implementasi antarmuka secara inline, jadi ini bukan masalah besar

kandang
sumber
3
"bukan masalah besar". Baik. Karena x => x.Foovs. new Bar() { public void M(SomeType x) { return x.Foo; } }- siapa yang peduli tentang kode menjadi 10 kali lebih pendek?
Kirk Woll
2

Fungsionalitas tanggal / kalender built-in di Java sangat buruk dibandingkan dengan System.DateTime. Ada banyak info tentang ini di sini: Apa yang salah dengan Java Date & Time API?

Beberapa di antaranya bisa didapatkan untuk pengembang C #:

  • Kelas Tanggal Jawa bisa berubah yang dapat membuat tanggal kembali dan lewat berbahaya.
  • Sebagian besar konstruktor java.util.Date tidak digunakan lagi. Sederhananya, membuat sebuah tanggal cukup bertele-tele.
  • Saya tidak pernah mendapatkan kelas java.util.Date untuk beroperasi dengan baik dengan layanan web. Dalam kebanyakan kasus, tanggal di kedua sisi diubah secara liar menjadi tanggal & waktu lain.

Selain itu, Java tidak memiliki semua fitur yang sama dengan yang dibawa oleh GAC dan rakitan dengan nama kuat. Guci Neraka adalah istilah untuk apa yang salah saat menghubungkan / mereferensikan perpustakaan eksternal.

Sejauh menyangkut pengemasan / penerapan:

  • Mungkin sulit untuk mengemas aplikasi web dalam format EAR / WAR yang benar-benar diinstal dan dijalankan di beberapa server aplikasi yang berbeda (Glassfish, Websphere, dll).
  • menerapkan aplikasi Java Anda sebagai layanan Windows membutuhkan lebih banyak upaya daripada di C #. Sebagian besar rekomendasi yang saya dapatkan untuk ini melibatkan perpustakaan pihak ketiga yang tidak gratis
  • konfigurasi aplikasi tidak semudah memasukkan file app.config dalam proyek Anda. Ada kelas java.util.Properties, tetapi tidak sekuat itu dan menemukan tempat yang tepat untuk melepaskan file .properties Anda bisa membingungkan
intoOrbit
sumber
1

Tidak ada delegasi di Jawa. Oleh karena itu, selain dari semua manfaat yang dibawa oleh delegasi, berbagai acara juga bekerja secara berbeda. Alih-alih hanya menghubungkan metode, Anda perlu mengimplementasikan antarmuka dan melampirkannya.

BFree
sumber
1

Satu hal yang menonjol b / c itu ada di daftar wawancara saya adalah bahwa tidak ada analog kata kunci "baru" di Java untuk metode penyembunyian dan karenanya tidak ada peringatan compiler "Anda harus meletakkan baru di sini". Metode yang tidak disengaja bersembunyi saat Anda bermaksud mengganti prospek ke bug.

(edit misalnya) Contoh, B berasal dari A (menggunakan sintaks C #, Java berperilaku sama terakhir kali saya periksa tetapi tidak mengeluarkan peringatan kompiler). Apakah foo A dipanggil, atau foo B? (A dipanggil, mungkin mengejutkan pengembang yang mengimplementasikan 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();
}
Jim L.
sumber
2
Bagaimana Anda secara tidak sengaja menyembunyikan metode instance di Java? keduanya final - jadi tidak ada penimpaan atau newmetode untuk sengaja disembunyikan - atau non-final jadi diganti daripada disembunyikan.
Pete Kirkham
Contoh tambahan. Saya sudah lama tidak mengujinya di Java, tetapi pertanyaan wawancara awalnya datang dari grup Java dari perusahaan saya sebelumnya. Dalam C #, peringatan kompilator biasanya berarti orang mengubah nama. Saya akui itu kasus yang cukup aneh, tetapi OP sepertinya menanyakan hal-hal yang berpotensi sulit ditemukan masalah saat berpindah bahasa.
Jim L
1
Perbedaannya di sini adalah bahwa di Java semua metode adalah virtual (jadi di Java, B.foo () akan dipanggil karena Java selalu melakukan pengiriman metode dinamis), sedangkan dalam metode C # tidak virtual secara default (dan A.foo () akan dipanggil). Banyak pemeriksa gaya pengkodean untuk Java akan memberi tahu Anda bahwa B harus menggunakan anotasi @Override.
William Billingsley
1

Java tidak memiliki LINQ dan dokumentasinya adalah neraka. Antarmuka pengguna di Java sulit untuk dikembangkan, Anda kehilangan semua hal baik yang diberikan Microsoft kepada kami (WPF, WCF, dll ...) tetapi mendapatkan "API" yang sulit digunakan dan hampir tidak terdokumentasi.

Turing Lengkap
sumber
0

Satu masalah yang saya hadapi sejauh ini ketika bekerja dengan Java yang berasal dari C # adalah Pengecualian dan Kesalahan berbeda.

Misalnya Anda tidak dapat menangkap kesalahan memori menggunakan catch (Exception e).

Lihat berikut ini untuk lebih jelasnya:

why-is-java-lang-outofmemoryerror-java-heap-space-not-catch

Chris Persichetti
sumber
Ini sengaja dirancang seperti itu untuk mencegah pemrogram aplikasi menangkapnya
finnw
Ya saya yakin itu, tapi datang dari sisi C #, di mana yang perlu Anda khawatirkan adalah menangkap pengecualian, lempar saya untuk loop :)
Chris Persichetti
0

Sudah begitu lama sejak saya berada di Java tetapi hal-hal yang saya perhatikan langsung dari kelelawar dalam pengembangan aplikasi adalah model acara C #, C # seret dan lepas vs menggunakan Manajer Tata Letak di Swing (jika Anda melakukan pengembang Aplikasi), dan penanganan pengecualian dengan Java memastikan Anda menangkap pengecualian dan C # tidak diperlukan.

Jason Terlalu Keren Webs
sumber
0

Menanggapi pertanyaan Anda yang sangat langsung dalam judul Anda:

"Pengembang C # yang mempelajari Java, apa perbedaan terbesar yang mungkin diabaikan?"

J: Fakta bahwa Java jauh lebih lambat di Windows.


sumber
4
Saya menjalankan OpenSuSE 64bit dan Windows 7 64bit, dan Eclipse IDE ("tampaknya") lebih cepat di Windows. Apakah jawaban Anda berdasarkan pengamatan pribadi atau tolok ukur aktual?
Jim Schubert
0

Perbedaan yang paling mengganggu bagi saya ketika saya beralih ke java adalah deklarasi stringnya.

di C # string(sebagian besar waktu) di JawaString

Ini cukup sederhana, tetapi percayalah, itu membuat Anda kehilangan begitu banyak waktu ketika Anda memiliki kebiasaan untuk stidak melakukannya S!

iChaib
sumber