Apakah ada destruktor untuk Java? Sepertinya saya tidak dapat menemukan dokumentasi tentang ini. Jika tidak ada, bagaimana saya bisa mendapatkan efek yang sama?
Untuk membuat pertanyaan saya lebih spesifik, saya menulis sebuah aplikasi yang berkaitan dengan data dan spesifikasinya mengatakan bahwa harus ada tombol 'reset' yang membawa aplikasi kembali ke keadaan semula yang baru diluncurkan. Namun, semua data harus 'hidup' kecuali jika aplikasi ditutup atau tombol reset ditekan.
Menjadi biasanya seorang programmer C / C ++, saya pikir ini akan sepele untuk diimplementasikan. (Dan karenanya saya berencana untuk mengimplementasikannya paling akhir.) Saya menyusun program saya sedemikian rupa sehingga semua objek yang 'dapat-reset' berada di kelas yang sama sehingga saya dapat menghancurkan semua objek 'hidup' ketika tombol reset ditekan.
Saya berpikir jika yang saya lakukan hanyalah merapikan data dan menunggu pengumpul sampah mengumpulkannya, bukankah akan ada kebocoran memori jika pengguna saya berulang kali memasukkan data dan menekan tombol reset? Saya juga berpikir karena Jawa cukup matang sebagai bahasa, harus ada cara untuk mencegah hal ini terjadi atau menangani masalah ini dengan anggun.
Jawaban:
Karena Java adalah bahasa sampah yang dikumpulkan, Anda tidak dapat memprediksi kapan (atau bahkan jika) suatu objek akan dihancurkan. Karenanya tidak ada padanan langsung dari destruktor.
Ada metode warisan yang disebut
finalize
, tetapi ini disebut sepenuhnya atas kebijakan pengumpul sampah. Jadi untuk kelas yang perlu merapikan secara eksplisit, konvensi adalah untuk mendefinisikan metode tutup dan hanya menggunakan penyelesaian untuk pemeriksaan kewarasan (yaitu jika dekat belum dipanggil lakukan sekarang dan catat kesalahan).Ada pertanyaan yang melahirkan diskusi mendalam tentang penyelesaian baru-baru ini, sehingga harus memberikan lebih mendalam jika diperlukan ...
sumber
finalize
metode ini sudah tidak digunakan lagi di Jawa 9.Lihatlah pernyataan coba-dengan-sumber daya . Sebagai contoh:
Di sini sumber daya yang tidak lagi dibutuhkan dibebaskan dalam
BufferedReader.close()
metode. Anda dapat membuat kelas Anda sendiri yang mengimplementasikanAutoCloseable
dan menggunakannya dengan cara yang serupa.Pernyataan ini lebih terbatas daripada
finalize
dalam hal penataan kode, tetapi pada saat yang sama membuat kode lebih mudah untuk dipahami dan dipelihara. Juga, tidak ada jaminan bahwa suatufinalize
metode dipanggil sama sekali selama masa pakai aplikasi.sumber
try
danfinally
digunakan untuk memaksa panggilanobj.finalize()
. Dan bahkan pengaturan ini tidak menyelesaikan masalah yang ditimbulkan oleh OP: penghancuran objek pada pertengahan program yang dipicu oleh tombol "reset".Tidak, tidak ada destruktor di sini. Alasannya adalah bahwa semua objek Java dialokasikan tumpukan dan sampah dikumpulkan. Tanpa deallokasi eksplisit (yaitu operator penghapusan C ++) tidak ada cara yang masuk akal untuk mengimplementasikan destruktor nyata.
Java mendukung finalizer, tetapi mereka dimaksudkan untuk digunakan hanya sebagai pengamanan untuk objek yang memegang pegangan ke sumber daya asli seperti soket, pegangan file, pegangan jendela, dll. Ketika pengumpul sampah mengumpulkan objek tanpa finalizer, ia hanya menandai memori wilayah bebas dan hanya itu. Ketika objek memiliki finalizer, pertama-tama disalin ke lokasi sementara (ingat, kami mengumpulkan sampah di sini), kemudian enqueued menjadi antrian yang menunggu untuk diselesaikan dan kemudian benang Finalizer memilah antrian dengan prioritas sangat rendah dan menjalankan finalizer.
Ketika aplikasi keluar, JVM berhenti tanpa menunggu objek yang tertunda diselesaikan, sehingga praktis tidak ada jaminan bahwa finalizer Anda akan pernah berjalan.
sumber
Penggunaan metode finalisasi () harus dihindari. Mereka bukan mekanisme yang dapat diandalkan untuk pembersihan sumber daya dan dimungkinkan untuk menyebabkan masalah dalam pengumpul sampah dengan menyalahgunakan mereka.
Jika Anda memerlukan panggilan deallokasi di objek Anda, katakan untuk melepaskan sumber daya, gunakan panggilan metode eksplisit. Konvensi ini dapat dilihat di API yang ada (mis. Closeable , Graphics.dispose () , Widget.dispose () ) dan biasanya dipanggil via try / akhirnya.
Upaya untuk menggunakan objek yang dibuang harus membuang pengecualian runtime (lihat IllegalStateException ).
EDIT:
Secara umum, semua yang perlu Anda lakukan adalah referensi objek - setidaknya, ini adalah cara yang seharusnya bekerja. Jika Anda khawatir tentang pengumpulan sampah, periksa Java SE 6 HotSpot [tm] Tuning Pengumpulan Sampah Mesin Virtual (atau dokumen yang setara untuk versi JVM Anda).
sumber
class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
Dengan Java 1.7 dirilis, Anda sekarang memiliki opsi tambahan untuk menggunakan
try-with-resources
blok. Sebagai contoh,Jika Anda menjalankan kelas ini,
c.close()
akan dieksekusi ketikatry
blok dibiarkan, dan sebelumcatch
danfinally
blok dieksekusi. Berbeda dengan dalam halfinalize()
metode,close()
dijamin akan dieksekusi. Namun, tidak perlu mengeksekusi secara eksplisit dalamfinally
klausa.sumber
finalize()
eksekusiSaya sepenuhnya setuju dengan jawaban lain, mengatakan tidak bergantung pada eksekusi penyelesaian.
Selain blok coba-tangkap-akhirnya, Anda dapat menggunakan Runtime # addShutdownHook (diperkenalkan di Java 1.3) untuk melakukan pembersihan akhir dalam program Anda.
Itu tidak sama dengan destruktor , tetapi orang mungkin menerapkan hook shutdown yang memiliki objek pendengar terdaftar yang metode pembersihan (tutup koneksi database persisten, hapus kunci file, dan sebagainya) dapat dipanggil - hal-hal yang biasanya dilakukan di penghancur . Sekali lagi - ini bukan pengganti destruktor tetapi dalam beberapa kasus, Anda dapat mendekati fungsionalitas yang diinginkan dengan ini.
Keuntungan dari ini adalah memiliki perilaku dekonstruksi yang longgar digabungkan dari sisa program Anda.
sumber
Tidak,
java.lang.Object#finalize
adalah yang terdekat yang bisa Anda dapatkan.Namun, kapan (dan jika) itu disebut, tidak dijamin.
Lihat:
java.lang.Runtime#runFinalizersOnExit(boolean)
sumber
Pertama, perhatikan bahwa karena Jawa adalah pengumpulan sampah, jarang perlu melakukan apa pun tentang penghancuran objek. Pertama karena Anda biasanya tidak memiliki sumber daya yang dikelola untuk dibebaskan, dan kedua karena Anda tidak dapat memprediksi kapan atau jika itu akan terjadi, jadi tidak pantas untuk hal-hal yang perlu Anda lakukan "segera setelah tidak ada yang menggunakan objek saya lagi ".
Anda dapat diberi tahu setelah objek dihancurkan menggunakan java.lang.ref.PhantomReference (sebenarnya, mengatakan itu telah dihancurkan mungkin sedikit tidak akurat, tetapi jika referensi hantu untuk itu di-antri maka itu tidak lagi dapat dipulihkan, yang biasanya berjumlah hal yang sama). Penggunaan umum adalah:
Ada juga finalize (), yang terlihat seperti destruktor tetapi tidak berperilaku seperti itu. Ini biasanya bukan pilihan yang baik.
sumber
Itu
finalize()
fungsi destruktor.Namun, seharusnya tidak digunakan secara normal karena dipanggil setelah GC dan Anda tidak bisa tahu kapan itu akan terjadi (jika pernah).
Selain itu, dibutuhkan lebih dari satu GC untuk mendelokasi objek yang dimiliki
finalize()
.Anda harus mencoba untuk membersihkan tempat-tempat logis dalam kode Anda menggunakan
try{...} finally{...}
pernyataan!sumber
Saya setuju dengan sebagian besar jawabannya.
Anda tidak harus bergantung sepenuhnya pada salah satu
finalize
atauShutdownHook
menyelesaikan
JVM tidak menjamin kapan
finalize()
metode ini akan dipanggil.finalize()
dipanggil hanya sekali oleh utas GC. Jika suatu objek pulih dari metode penyelesaian, makafinalize
tidak akan dipanggil lagi.Dalam aplikasi Anda, Anda mungkin memiliki beberapa objek hidup, tempat pengumpulan sampah tidak pernah dipanggil.
Apa pun
Exception
yang dilemparkan dengan metode finalisasi diabaikan oleh utas GCSystem.runFinalization(true)
danRuntime.getRuntime().runFinalization(true)
metode meningkatkan kemungkinanfinalize()
metode pemanggilan tetapi sekarang kedua metode ini telah usang. Metode ini sangat berbahaya karena kurangnya keamanan benang dan kemungkinan pembuatan jalan buntu.shutdownHooks
Mesin virtual Java dimatikan sebagai respons terhadap dua jenis peristiwa:
System.exit
) dipanggil, atauKait mati juga harus menyelesaikan pekerjaan mereka dengan cepat. Ketika sebuah program memanggil keluar harapan adalah bahwa mesin virtual akan segera dimatikan dan keluar.
Tetapi bahkan dokumentasi Oracle mengutipnya
Ini terjadi ketika mesin virtual diakhiri secara eksternal, misalnya dengan
SIGKILL
sinyal pada Unix atauTerminateProcess
panggilan pada Microsoft Windows. Mesin virtual juga dapat dibatalkan jika metode asli berjalan salah dengan, misalnya, merusak struktur data internal atau mencoba mengakses memori yang tidak ada. Jika mesin virtual batal, maka tidak ada jaminan yang dapat dibuat tentang apakah ada shutdown hooks yang akan dijalankan.Kesimpulan : gunakan
try{} catch{} finally{}
blok dengan tepat dan lepaskan sumber daya penting dalamfinally(}
blok. Selama pelepasan sumber daya difinally{}
blok, tangkapException
danThrowable
.sumber
Jika hanya ingatan yang Anda khawatirkan, jangan. Hanya percaya pada GC itu melakukan pekerjaan yang layak. Saya benar-benar melihat sesuatu tentang hal itu menjadi sangat efisien sehingga bisa lebih baik untuk kinerja untuk membuat banyak objek kecil daripada menggunakan array besar dalam beberapa kasus.
sumber
Mungkin Anda bisa menggunakan percobaan ... akhirnya memblokir untuk menyelesaikan objek dalam aliran kontrol di mana Anda menggunakan objek. Tentu saja itu tidak terjadi secara otomatis, tetapi tidak juga kerusakan di C ++. Anda sering melihat penutupan sumber daya di blok akhirnya.
sumber
Ada anotasi @Cleanup di Lombok yang sebagian besar menyerupai penghancur C ++:
Saat memprosesnya (pada waktu kompilasi), Lombok menyisipkan
try-finally
blok yang sesuai sehinggaresource.close()
dipanggil, ketika eksekusi meninggalkan ruang lingkup variabel. Anda juga dapat menentukan secara eksplisit metode lain untuk melepaskan sumber daya, misalnyaresource.dispose()
:sumber
@Cleanup
Setara terdekat dengan destruktor di Jawa adalah metode finalize () . Perbedaan besar pada destruktor tradisional adalah Anda tidak dapat memastikan kapan akan dipanggil, karena itu adalah tanggung jawab pengumpul sampah. Saya sangat merekomendasikan membaca ini dengan cermat sebelum menggunakannya, karena pola RAIA khas Anda untuk menangani file dan seterusnya tidak akan bekerja dengan baik dengan finalize ().
sumber
Banyak jawaban bagus di sini, tetapi ada beberapa informasi tambahan tentang mengapa Anda harus menghindari menggunakan finalize () .
Jika JVM keluar karena
System.exit()
atauRuntime.getRuntime().exit()
, finalizers tidak akan dijalankan secara default. Dari Javadoc untuk Runtime.exit () :Anda dapat menelepon
System.runFinalization()
tetapi itu hanya membuat "upaya terbaik untuk menyelesaikan semua finalisasi yang beredar" - bukan jaminan.Ada sebuah
System.runFinalizersOnExit()
metode, tetapi jangan menggunakannya - itu tidak aman, sudah usang sejak lama.sumber
Jika Anda menulis Java Applet, Anda dapat mengganti metode Applet "destroy ()". Ini...
Jelas bukan yang Anda inginkan, tetapi mungkin apa yang dicari orang lain.
sumber
Hanya memikirkan pertanyaan asli ... yang, saya pikir kita dapat menyimpulkan dari semua jawaban yang dipelajari lainnya, dan juga dari Jawa Efektif yang penting dari Bloch , butir 7, "Hindari finalizer", mencari solusi untuk pertanyaan yang sah dengan cara yang tidak pantas untuk bahasa Jawa ...:
... bukankah solusi yang cukup jelas untuk melakukan apa yang sebenarnya diinginkan OP adalah menjaga semua objek Anda yang perlu diatur ulang dalam semacam "playpen", yang semua objek non-reset memiliki referensi hanya melalui semacam objek accessor ...
Dan kemudian ketika Anda perlu "mengatur ulang" Anda lepaskan playpen yang ada dan buat yang baru: semua web objek di playpen dilemparkan terpaut, tidak pernah kembali, dan suatu hari akan dikumpulkan oleh GC.
Jika salah satu dari objek ini adalah
Closeable
(atau tidak, tetapi memilikiclose
metode), Anda dapat meletakkannya diBag
dalam playpen saat dibuat (dan mungkin dibuka), dan tindakan terakhir dari pengakses sebelum memotong playpen adalah pergi melalui semuaCloseables
penutupan mereka ...?Kode mungkin akan terlihat seperti ini:
closeCloseables
mungkin akan menjadi metode pemblokiran, mungkin melibatkan kait (misalnyaCountdownLatch
), untuk berurusan dengan (dan menunggu sesuai kebutuhan) setiapRunnables
/Callables
di setiap utas yang spesifik untukPlaypen
diakhiri sebagaimana mestinya, khususnya di utas JavaFX.sumber
Meskipun ada banyak kemajuan dalam teknologi GC Java, Anda masih perlu memperhatikan referensi Anda. Banyak kasus pola referensi yang tampaknya sepele yang sebenarnya adalah sarang tikus di bawah tenda.
Dari posting Anda itu tidak terdengar seperti Anda mencoba menerapkan metode reset untuk tujuan penggunaan kembali objek (benar?). Apakah objek Anda memegang sumber daya jenis apa pun yang perlu dibersihkan (yaitu, aliran yang harus ditutup, benda yang dikumpulkan atau dipinjam yang harus dikembalikan)? Jika satu-satunya hal yang Anda khawatirkan adalah memori dealloc maka saya akan mempertimbangkan kembali struktur objek saya dan mencoba untuk memverifikasi bahwa objek saya adalah struktur mandiri yang akan dibersihkan pada waktu GC.
sumber
Tidak ada kelas destruktor persis di Jawa, kelas dihancurkan di java secara otomatis oleh pengumpul sampah. tetapi Anda bisa melakukannya menggunakan di bawah satu tetapi itu tidak persis sama:
menyelesaikan()
Ada pertanyaan yang melontarkan diskusi mendalam tentang finalisasi , sehingga Anda harus mendapatkan lebih mendalam jika diminta ...
sumber
Tidak ada Java tidak memiliki destruktor. Alasan utama di baliknya di Jawa adalah Pengumpul Sampah yang secara pasif selalu bekerja di latar belakang dan semua objek dibuat dalam memori tumpukan, itu adalah tempat di mana GC bekerja. Di c ++ di sana kami harus secara eksplisit memanggil fungsi hapus karena tidak ada pengumpul sampah seperti itu.
sumber
Saya biasanya berurusan dengan C ++ dan itulah yang membawa saya ke pencarian destructor juga. Saya banyak menggunakan JAWA sekarang. Apa yang saya lakukan, dan itu mungkin bukan kasus terbaik untuk semua orang, tapi saya menerapkan destruktor saya sendiri dengan mengatur ulang semua nilai ke 0 atau di sana default melalui fungsi.
Contoh:
Idealnya ini tidak akan bekerja untuk semua situasi, tetapi di mana ada variabel global itu akan berfungsi selama Anda tidak memiliki banyak dari mereka.
Saya tahu saya bukan programmer Java terbaik, tetapi tampaknya bekerja untuk saya.
sumber