Apakah Java mempromosikan pemisahan antara definisi dan implementasi kelas, seperti halnya C ++?

10

Saya memiliki tugas pekerjaan rumah dan saya perlu mengevaluasi pendekatan mana yang lebih baik menurut GRASP "Variasi yang Dilindungi". Saya menemukan pertanyaan tentang Stack Overflow tentang pemisahan file header dan kode di C ++ .

Namun, apa yang saya ingin tahu mengapa Java tidak mengikuti C ++ dalam mempromosikan pemisahan antara definisi kelas dan implementasi kelas. Apakah ada keuntungan dengan metode Java, lebih dari metode C ++?

Etienne Noël
sumber
Jika Anda ingin bertanya "Mengapa Java tidak menggunakan file header", maka tanyakan saja dan hilangkan hal-hal "mana yang lebih baik" - seperti yang Anda lihat, kami alergi terhadap hal itu;) Juga cari, saya Saya cukup yakin ini (atau setidaknya pertanyaan yang berhubungan erat) telah diajukan sebelumnya.
Ups, tautannya tidak berfungsi. Saya akan merumuskan kembali, apa yang ingin saya ketahui pada dasarnya, adalah perbedaan antara keduanya dan mana yang cenderung lebih mudah untuk menggunakan kembali kode atau untuk diperpanjang.
Etienne Noël
1
C (dan dengan ekstensi C ++) benar-benar tidak punya pilihan selain untuk memisahkan file header dari file implementasi, karena terbatasnya teknologi kompiler satu-pass pada saat C dibuat.
Channel72
2
Java dapat memiliki Antarmuka yang dapat memisahkan definisi kelas dan implementasi kelas, jika kelas yang bersangkutan mengimplementasikan antarmuka. Tidak persis sama dengan C ++.
FrustratedWithFormsDesigner
1
Juga, file header C ++ mengekspos implementasi yang jauh lebih banyak daripada yang saya suka, kecuali jika Anda menggunakan idiom PIMPL. Penting untuk mendaftar semua anggota data, bahkan jika private, jadi implementasinya akan mengetahui ukurannya, dan privatefungsi anggota juga.
David Thornley 8/11

Jawaban:

13

Berapa banyak baris kode dalam program berikut?

#include <iostream>

int main()
{
   std::cout << "Hello, world!\n";
   return 0;
}

Anda mungkin menjawab 7 (atau 6 jika Anda tidak menghitung garis kosong, atau 4 jika Anda tidak menghitung kawat gigi).

Namun kompiler Anda melihat sesuatu yang sangat berbeda:

~$ cpp hello.cpp | wc
  18736   40822  437015

Ya, itu 18,7 KLOC hanya untuk "Halo, dunia!" program. Kompilator C ++ harus menguraikan semua itu. Ini adalah alasan utama mengapa kompilasi C ++ memakan waktu begitu lama dibandingkan dengan bahasa lain, dan mengapa bahasa modern menghindari file header.

Pertanyaan yang lebih baik adalah

Mengapa tidak C ++ memiliki file header?

C ++ dirancang untuk menjadi superset dari C, jadi ia harus menyimpan file header untuk kompatibilitas.

OK, jadi mengapa C memiliki file header?

Karena model kompilasi terpisah yang primitif. File objek yang dihasilkan oleh kompiler C tidak menyertakan informasi tipe apa pun, jadi untuk mencegah kesalahan tipe Anda perlu memasukkan informasi ini dalam kode sumber Anda.

~$ cat sqrtdemo.c 
int main(void)
{
    /* implicit declaration int sqrt(int) */
    double sqrt2 = sqrt(2);
    printf("%f\n", sqrt2);
    return 0;
}

~$ gcc -Wall -ansi -lm -Dsqrt= sqrtdemo.c
sqrtdemo.c: In function main’:
sqrtdemo.c:5:5: warning: implicit declaration of function printf [-Wimplicit-function-declaration]
sqrtdemo.c:5:5: warning: incompatible implicit declaration of built-in function printf [enabled by default]
~$ ./a.out 
2.000000

Menambahkan deklarasi tipe yang tepat memperbaiki bug:

~$ cat sqrtdemo.c 
#undef printf
#undef sqrt

int printf(const char*, ...);
double sqrt(double);

int main(void)
{
    double sqrt2 = sqrt(2);
    printf("%f\n", sqrt2);
    return 0;
}

~$ gcc -Wall -ansi -lm sqrtdemo.c
~$ ./a.out 
1.414214

Perhatikan bahwa tidak ada #includes. Tetapi ketika Anda menggunakan sejumlah besar fungsi eksternal (yang sebagian besar program akan), secara manual menyatakan mereka menjadi membosankan dan rentan kesalahan. Jauh lebih mudah menggunakan file header.

Bagaimana bahasa modern dapat menghindari file header?

Dengan menggunakan format file objek berbeda yang menyertakan informasi jenis. Misalnya, format file Java * .class menyertakan "deskriptor" yang menentukan jenis bidang dan parameter metode.

Ini bukan penemuan baru. Sebelumnya (1987), ketika Borland menambahkan "unit" yang dikompilasi secara terpisah ke Turbo Pascal 4.0, ia memilih untuk menggunakan *.TPUformat baru daripada Turbo C *.OBJuntuk menghapus kebutuhan file header.

dan04
sumber
Meskipun menarik, saya cukup yakin bahwa Anda dapat mengatur Turbo Pascal untuk menampilkan OBJfile daripada TPU...
a CVn
7

Java memiliki antarmuka untuk menentukan kontrak. Ini memberikan tingkat abstraksi yang lebih tinggi dari apa yang dibutuhkan penelepon dan implementasi yang sebenarnya. yaitu penelepon tidak perlu tahu kelas pelaksana, hanya perlu tahu kontrak yang didukungnya.

Katakanlah Anda ingin menulis metode yang memperlambat semua kunci / nilai dalam Peta.

public static <K,V> void printMap(Map<K,V> map) {
    for(Entry<K,V> entry: map.entrySet())
        System.out.println(entry);
}

Metode ini dapat memanggil entrySet () pada antarmuka abstrak yang dihapus dari kelas yang mengimplementasikannya. Anda dapat memanggil metode ini dengan.

printMap(new TreeMap());
printMap(new LinkedHashMap());
printMap(new ConcurrentHashMap());
printMap(new ConcurrentSkipListMap());
Peter Lawrey
sumber
1
Selamat datang di Programmer di sana Peter - pikir saya mengenali namanya :-). Saya akan menambahkan bahwa beberapa orang akan berpendapat bahwa kelas dasar abstrak di Jawa juga mendefinisikan kontrak - tapi itu mungkin argumen untuk utas terpisah.
Martijn Verburg
Halo @ MartijnVerburg, Tambahan yang bagus. Saya pikir kelas abstrak mengaburkan perbedaan antara antarmuka tanpa implementasi dan kelas konkret. Metode penyuluhan akan mengaburkan perbedaan lebih jauh. Saya cenderung lebih suka menggunakan antarmuka jika saya bisa karena mereka lebih sederhana.
Peter Lawrey
Ya Jawa akan mulai menuju ke jalan Scala memiliki beberapa cara untuk menentukan kontrak publik - Saya tidak yakin itu hal yang baik atau belum :-)
Martijn Verburg
-1 Ini dimungkinkan di C ++ juga, dengan sederhana #define interface class.
Sjoerd
@ Sojerd Saya tidak tahu metode C ++ tidak perlu lagi menggunakan virtualkata kunci untuk mendapatkan polimorfisme dan ini tidak memiliki penalti kinerja jika Anda hanya menggunakan satu atau dua jenis beton, seperti yang ada di Jawa. Bisakah Anda mengarahkan saya ke dokumentasi tentang cara kerjanya di C ++?
Peter Lawrey
5

Terus terang, header ada sebagai kecelakaan historis. Ini adalah sistem yang sangat buruk, tidak ada bahasa lain yang begitu mengerikan, dan siapa pun yang tidak harus berurusan dengan mereka harus bersukacita.

DeadMG
sumber
3

Header ada untuk memungkinkan kompilasi terpisah. Dengan #termasuk header, compiler tidak perlu tahu apa-apa tentang struktur biner dari kode C ++ yang dikompilasi, dan dapat meninggalkan pekerjaan itu ke linker terpisah. Java tidak menggunakan linker terpisah dengan kompilernya, dan karena file .class didefinisikan secara ketat, kompiler dapat membacanya untuk menentukan semua anggotanya dengan semua tipenya, tanpa perlu mendeklarasikan ulang mereka di setiap unit kompilasi.

Anda dapat memasukkan semua implementasi dalam header C ++, tetapi hal itu menyebabkan kompilator mengkompilasi ulang setiap kali #include, memaksa linker untuk memilah dan membuang salinan duplikat.

Chuck Adams
sumber
0

Java mempromosikan pemisahan definisi dan implementasi kelas, itu hanya tergantung dari mana Anda melihat.

Ketika Anda penulis kelas Java, Anda bisa melihat definisi kelas serta implementasinya dalam satu file. Ini menyederhanakan proses pengembangan karena Anda hanya perlu pergi ke satu tempat untuk mempertahankan kelas, Anda tidak perlu beralih di antara dua file (.h dan .cpp seperti yang Anda lakukan di C ++). Namun, ketika Anda adalah konsumen kelas Anda hanya berurusan dengan definisi, melalui file .class yang dikemas dalam .jar atau .class mandiri

C ++ memungkinkan Anda untuk memisahkan definisi dan implementasi, tetapi bersifat ad-hoc. Misalnya, tidak ada yang menghentikan Anda menulis metode inline di dalam file header, dan untuk kelas template ini wajib. File header juga mencantumkan variabel anggota apa pun, yang terlihat oleh siapa saja yang melihat file header, meskipun mereka adalah detail implementasi dari kelas dan tidak relevan bagi konsumen.

Sean
sumber