Saya perlu menemukan penelepon metode. Apakah mungkin menggunakan stacktrace atau refleksi?
java
stack-trace
Sathish
sumber
sumber
DontNameYourMethodFooException
jika metode panggilan bernama foo.Jawaban:
Menurut Javadocs:
Sebuah
StackTraceElement
memilikigetClassName()
,getFileName()
,getLineNumber()
dangetMethodName()
.Anda harus bereksperimen untuk menentukan indeks mana yang Anda inginkan (mungkin
stackTraceElements[1]
atau[2]
).sumber
Solusi alternatif dapat ditemukan dalam komentar untuk permintaan peningkatan ini . Ia menggunakan
getClassContext()
metode kustomSecurityManager
dan tampaknya lebih cepat daripada metode jejak tumpukan.Program berikut menguji kecepatan berbagai metode yang disarankan (bit paling menarik adalah di kelas batin
SecurityManagerMethod
):Contoh output dari 2,4 GHz Intel Core 2 Duo MacBook saya yang menjalankan Java 1.6.0_17:
Metode Refleksi internal jauh lebih cepat daripada yang lain. Mendapatkan jejak stack dari yang baru dibuat
Throwable
lebih cepat daripada mendapatkannya dari saat iniThread
. Dan di antara cara-cara non-internal untuk menemukan kelas pemanggil kebiasaanSecurityManager
tampaknya menjadi yang tercepat.Memperbarui
Seperti yang ditunjukkan oleh lyomi dalam komentar ini ,
sun.reflect.Reflection.getCallerClass()
metode ini telah dinonaktifkan secara default di Java 7 pembaruan 40 dan dihapus sepenuhnya di Java 8. Baca lebih lanjut tentang ini dalam masalah ini di database bug Java .Perbarui 2
Seperti yang ditemukan zammbi , Oracle terpaksa mundur dari perubahan yang menghapus
sun.reflect.Reflection.getCallerClass()
. Ini masih tersedia di Java 8 (tetapi sudah usang).Perbarui 3
3 tahun setelah: Pembaruan tepat waktu dengan JVM saat ini.
sumber
Kedengarannya seperti Anda mencoba menghindari melewatkan referensi ke
this
dalam metode. Melewatithis
lebih baik daripada menemukan penelepon melalui jejak tumpukan saat ini. Refactoring ke desain yang lebih OO bahkan lebih baik. Anda tidak perlu tahu penelepon. Lewati objek panggilan balik jika perlu.sumber
LoggerFactory.getLogger(MyClass.class)
mana saya tidak harus lulus dalam literal kelas. Masih jarang hal yang benar untuk dilakukan.INotifyPropertyChanged
antarmuka .NET . Meskipun contoh khusus ini tidak ada di Jawa, masalah yang sama dapat muncul dengan sendirinya ketika mencoba memodelkan bidang / getter sebagai string untuk Reflection.Java 9 - JEP 259: Stack-Walking API
JEP 259 menyediakan API standar yang efisien untuk tumpukan berjalan yang memungkinkan penyaringan mudah, dan akses malas ke, informasi dalam jejak tumpukan. Sebelum Stack-Walking API, cara umum mengakses frame stack adalah:
Menggunakan API ini biasanya tidak efisien:
Untuk menemukan kelas pemanggil langsung, pertama-tama dapatkan
StackWalker
:Kemudian panggil
getCallerClass()
:atau
walk
yangStackFrame
s dan yang pertama sebelumnyaStackFrame
:sumber
Oneliner :
Perhatikan bahwa Anda mungkin perlu mengganti 2 dengan 1.
sumber
Metode ini melakukan hal yang sama tetapi sedikit lebih sederhana dan mungkin sedikit lebih berkinerja dan jika Anda menggunakan refleksi, ia melompati frame-frame itu secara otomatis. Satu-satunya masalah adalah itu mungkin tidak hadir dalam JVM non-Sun, meskipun itu termasuk dalam kelas runtime dari JRockit 1.4 -> 1.6. (Intinya, ini bukan kelas publik ).
Sejauh apa
realFramesToSkip
nilainya, versi Sun 1.5 dan 1.6 VMjava.lang.System
, ada metode paket terproteksi yang disebut getCallerClass () yang memanggilsun.reflect.Reflection.getCallerClass(3)
, tetapi di kelas utilitas pembantu saya, saya menggunakan 4 karena ada bingkai tambahan dari kelas pembantu doa.sumber
Misalnya, jika Anda mencoba untuk mendapatkan garis metode pemanggilan untuk tujuan debug, Anda harus melewati kelas Utilitas tempat Anda mengkode metode statis tersebut:
(kode java1.4 lama, hanya untuk menggambarkan potensi penggunaan StackTraceElement)
sumber
Saya pernah melakukan ini sebelumnya. Anda bisa membuat pengecualian baru dan ambil jejak tumpukan tanpa membuangnya, lalu periksa jejak tumpukan tersebut. Seperti jawaban lain mengatakan, itu sangat mahal - jangan lakukan itu dalam lingkaran yang ketat.
Saya telah melakukannya sebelumnya untuk utilitas pencatatan pada aplikasi yang kinerjanya tidak terlalu berarti (Kinerja jarang penting sama sekali, sebenarnya - selama Anda menampilkan hasilnya pada tindakan seperti klik tombol dengan cepat).
Itu sebelum Anda bisa mendapatkan jejak stack, pengecualian baru saja. PrintStackTrace () jadi saya harus mengarahkan System.out ke aliran kreasi saya sendiri, lalu (Pengecualian baru ()). PrintStackTrace (); Redirect System.out kembali dan parsing aliran. Hal menyenangkan.
sumber
sumber
Berikut adalah bagian dari kode yang saya buat berdasarkan petunjuk yang ditunjukkan dalam topik ini. Semoga ini bisa membantu.
(Jangan ragu untuk membuat saran untuk meningkatkan kode ini, tolong beri tahu saya)
Penghitung:
Dan obyeknya:
sumber
ATAU
sumber
gunakan metode ini: -
Kode contoh metode penelepon ada di sini: -
sumber