System.out.println("lambdaisrun") sebenarnya adalah penubuhan Bagaimana pula dengan kelas dalaman? Sebenarnya, ini adalah ungkapan Lambda yang paling mudah"/> System.out.println("lambdaisrun") sebenarnya adalah penubuhan Bagaimana pula dengan kelas dalaman? Sebenarnya, ini adalah ungkapan Lambda yang paling mudah">

Rumah  >  Artikel  >  Java  >  Bagaimana untuk membaca kod sumber Lambda dalam Java

Bagaimana untuk membaca kod sumber Lambda dalam Java

王林
王林ke hadapan
2023-05-13 11:10:061365semak imbas

Bagaimana untuk membaca kod sumber Lambda dalam Java


1. Demo

Mula-mula kita melihat tunjuk cara ekspresi Lambda, seperti yang ditunjukkan di bawah:

Bagaimana untuk membaca kod sumber Lambda dalam Java

Kod ini agak mudah, cuma mulakan utas baharu dan cetak ayat, tetapi untuk gambar () -> System.out.println (“ lambda dijalankan “) ini Dianggarkan ramai pelajar keliru tentang kod jenis ini Bagaimana Java mengenal pasti kod jenis ini?

Jika kita menukar tulisan kepada kelas dalaman tanpa nama, ia akan menjadi sangat jelas dan semua orang boleh memahaminya, seperti yang ditunjukkan di bawah:

Bagaimana untuk membaca kod sumber Lambda dalam Java

Adakah itu bermakna ( ) -> System.out.println (“ lambda dijalankan “) Adakah bentuk kod ini sebenarnya mencipta kelas dalam? Sebenarnya, ini adalah ungkapan Lambda yang paling mudah Kami tidak dapat melihat kod sumber dan struktur asasnya melalui IDEA Di sini kami akan memperkenalkan beberapa cara untuk melihat pelaksanaan asasnya.

2. Kaedah penghakiman pengecualian

Kami boleh secara aktif membuang pengecualian semasa pelaksanaan kod dan mencetak timbunan akan menerangkan trajektori berjalan Secara amnya, kaedah ini adalah mudah dan cekap, dan anda pada dasarnya boleh melihat Mari cuba kod tersembunyi dalam banyak kes, seperti yang ditunjukkan di bawah:

Bagaimana untuk membaca kod sumber Lambda dalam Java

Dari timbunan pengecualian, kita dapat melihat bahawa JVM secara automatik mencipta kelas dalaman untuk semasa class ($ muncul beberapa kali dalam timbunan ralat menunjukkan kelas dalaman semasa pelaksanaan kod kelas dalaman, pengecualian dilemparkan, tetapi kod yang ditunjukkan di sini adalah Sumber Tidak Diketahui, jadi kami tidak boleh menyahpepijatnya dalam keadaan biasa , pengecualian Kedua-dua kaedah boleh mendedahkan laluan pelaksanaan kod Kami boleh menetapkan titik putus dan berjalan semula Namun, untuk ungkapan Lambda, melalui kaedah penghakiman pengecualian, kami hanya tahu bahawa terdapat kelas dalaman, tetapi kami tidak dapat melihat kod sumber dalam dalaman. kelas.

3. Kaedah arahan javap

javap ialah alat yang disertakan dengan Java untuk melihat fail bytecode kelas Komputer yang telah memasang persekitaran asas Java boleh terus melaksanakan arahan javap, seperti yang ditunjukkan di bawah:

Bagaimana untuk membaca kod sumber Lambda dalam Java

Antara pilihan arahan, kami terutamanya menggunakan perintah -v -verbose untuk mengeluarkan sepenuhnya kandungan fail bytecode.

Seterusnya kami menggunakan arahan javap untuk melihat fail Lambda.class Semasa penerangan, kami akan membawa sedikit pengetahuan tentang fail kelas.

Kami mencari lokasi Lambda.class dalam tetingkap arahan, jalankan arahan: javap -verbose Lambda.class, dan kemudian anda akan melihat senarai panjang perkara, ini dipanggil arahan pemasangan, mari lakukannya seterusnya Biar saya jelaskan (semua bahan rujukan datang daripada Spesifikasi Mesin Maya Java, tiada petikan satu demi satu diperlukan):

Dalam arahan pemasangan, kita boleh mencari senarai panjang jenis dengan mudah bermula dengan Constant pool. Kami memanggilnya sebagai kumpulan malar Ia dipanggil Run-Time Constant Pool dalam bahasa Inggeris. Kami hanya memahaminya sebagai jadual yang diisi dengan pemalar padang, dsb. Setiap elemen dalam jadual dipanggil cpmaklumat cp terdiri daripada pengecam unik (teg) + nama Pada masa ini, terdapat sejumlah jenis teg:

Bagaimana untuk membaca kod sumber Lambda dalam Java

Siarkan beberapa gambar yang kami huraikan:

Bagaimana untuk membaca kod sumber Lambda dalam Java

  1. Perkataan Kolam Malar dalam gambar bermaksud maklumat semasa ialah kolam malar;

  2. Setiap baris ialah

    dan #1 dalam lajur pertama mewakili kedudukan yang ditandakan sebagai 1 dalam kumpulan malar; Lajur kedua bagi setiap baris ialah Pengecam unik (teg) cp_info, sebagai contoh, Methodref sepadan dengan CONSTANT_Methodref dalam jadual di atas (nilai dalam jadual di atas sepadan dengan teg 10), yang bermaksud bahawa baris semasa mewakili maklumat perihalan kaedah, seperti nama kaedah, Makna khusus jenis parameter input, jenis parameter output, dll. boleh didapati dalam Spesifikasi Mesin Maya Java Tangkapan skrin Methodref adalah seperti berikut:

  3. cp_info
    Nombor setiap baris Tiga lajur Jika ia adalah nilai tertentu, nilai khusus akan dipaparkan secara langsung Jika ia adalah nilai kompleks, rujukan Bagaimana untuk membaca kod sumber Lambda dalam Java akan dipaparkan Contohnya, bertanda merah 2 dalam gambar merujuk kepada dua

    pada kedudukan 13 dan 14. , 13 bermakna nama kaedah ialah init, 14 bermakna kaedah itu tidak mempunyai nilai pulangan, dan gabungannya daripada nama kaedah dan jenis pulangan ialah pembina tanpa parameter;
  4. cp_infoUntuk jenis cp_info yang lebih penting, kami menerangkan maksudnya: cp_info

    1. InvokeDynamic mewakili kaedah panggilan dinamik, yang akan kami terangkan secara terperinci kemudian; jenis medan;

    2. NameAndType ialah penerangan bagi medan dan jenis kaedah; kaedah, kami tidak tahu yang khusus pada masa penyusunan Kaedah itu, tetapi anda pasti akan tahu kaedah mana yang dipanggil semasa menjalankan

    3. MethodType jenis kaedah dinamik, anda hanya akan tahu apa; jenis kaedahnya ialah apabila berjalan secara dinamik.

    4. Daripada 3 tempat yang ditandakan dengan warna merah dalam gambar di atas, kami menemui kod Ljava/lang/invoke/MethodHandles$Lookup, java/lang/invoke/LambdaMetafactory.metafactory yang serupa dengan ini, MethodHandles dan LambdaMetafactory ialah kaedah penting di bawah pakej java.lang.invoke terutamanya melaksanakan fungsi bahasa dinamik , dsb. telah ditentukan , dan invoke melaksanakan bahasa dinamik, yang bermaksud bahawa jenis kelas, kaedah dan medan tidak diketahui semasa menyusun, dan hanya diketahui semasa dijalankan.

    5. Contohnya, baris kod ini: Runnable runnable = () -> System.out.println(“lambda is run”); does , hanya apabila berjalan anda akan tahu bahawa ini mewakili kaedah Runnable.run(). Banyak kelas dalam pakej invoke direka untuk mewakili ini (), yang kami panggil kaedah mengendalikan (MethodHandler, pengkompil hanya tahu bahawa ini adalah kaedah pengendalian, dan tidak tahu kaedah yang sebenarnya saya lakukan). tidak tahu sehingga masanya, jadi persoalannya ialah, apabila JVM melaksanakan, bagaimanakah ia tahu bahawa pengendalian kaedah () sebenarnya melaksanakan kaedah Runnable.run()?
    6. Pertama, mari kita lihat arahan pemasangan kaedah mudah:

    Daripada gambar di atas, anda boleh melihat () -> Sistem dalam kaedah mudah Kod () dalam out.println("lambda is run") sebenarnya ialah kaedah Runnable.run.

    Kami menjejak kembali ke kolam pemalar #2, iaitu 1 merah dalam gambar di atas menunjukkan bahawa ini ialah panggilan dinamik ialah cp_info daripada dua kumpulan malar. 0:#37 Kami Melihat ke bawah untuk #37, yang bermaksud // run:()Ljava/lang/Runnable Ini menunjukkan bahawa apabila JVM sebenarnya dilaksanakan, kaedah Runnable.run() perlu dipanggil secara dinamik arahan pemasangan, kita boleh melihat bahawa () Sebenarnya, ia adalah Runnable.run(). Mari kita nyahpepijat di bawah untuk membuktikannya.

    Kami menemui perkataan LambdaMetafactory.metafactory di 3 tempat dalam gambar di atas Dengan menyoal dokumentasi rasmi, kami mengetahui bahawa kaedah ini adalah kunci untuk memautkan kod sebenar semasa pelaksanaan, jadi kami menaipnya di dalam. kaedah metafactory. Nyahpepijat dengan titik putus, seperti yang ditunjukkan di bawah:

    Bagaimana untuk membaca kod sumber Lambda dalam Java

    pemanggil parameter input kaedah metafaktor mewakili lokasi sebenar panggilan dinamik, invokedName mewakili nama kaedah panggilan, dan invokedType mewakili berbilang input bagi Parameter panggilan dan parameter output, samMethodType mewakili parameter pelaksana khusus, implMethod mewakili pelaksana sebenar dan instantiatedMethodType adalah bersamaan dengan implMethod.

    Ringkasan perkara di atas:

    1: Daripada kaedah mudah arahan pemasangan, kita dapat melihat bahawa kaedah Runnable.run akan dilaksanakan

    Bagaimana untuk membaca kod sumber Lambda dalam Java2: Dalam operasi sebenar Apabila JVM menemui arahan invokedynamic bagi kaedah mudah, ia akan secara dinamik memanggil kaedah LambdaMetafactory.metafactory dan melaksanakan kaedah Runnable.run tertentu.

    Jadi pelaksanaan khusus nilai ekspresi Lambda boleh dikaitkan dengan arahan JVM invokedynamic Ia adalah tepat kerana arahan ini walaupun anda tidak tahu apa yang perlu dilakukan semasa menyusun, anda boleh menemui pelaksanaan khusus. apabila berjalan secara dinamik.

    Kemudian mari kita lihat pada penghujung output arahan pemasangan Kami mendapati kelas dalaman ditemui dalam kaedah penghakiman pengecualian, seperti yang ditunjukkan di bawah:

    Dalam gambar di atas Terdapat banyak anak panah, dan semua maklumat kelas dalaman semasa dinyatakan dengan jelas lapisan demi lapisan.

Atas ialah kandungan terperinci Bagaimana untuk membaca kod sumber Lambda dalam Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam