Kelas Sintetis di Jawa

143

Apa itu kelas sintetis di Jawa? Mengapa harus digunakan? Bagaimana saya bisa menggunakannya?

danHapp
sumber
1
Semua jawaban "tidak ada dalam kode Anda" sudah kedaluwarsa dengan Java 8, karena lambdas dapat diimplementasikan sebagai kelas sintetis (bukan anonim).
OrangeDog
Agar adil, lambda masih tidak "secara ketat" kelas yang didefinisikan secara eksplisit dalam kode Anda. Jadi, "tidak ada dalam kode Anda" masih valid. Kompiler menghasilkan kelas sintetis untuk Anda tanpa definisi eksplisit dalam kode Anda.
ManoDestra

Jawaban:

15

Sebagai contoh, Ketika Anda memiliki pernyataan switch, java membuat variabel yang dimulai dengan $. Jika Anda ingin melihat contoh ini, mengintip ke refleksi java dari kelas yang memiliki pernyataan switch di dalamnya. Anda akan melihat variabel-variabel ini ketika Anda memiliki setidaknya satu pernyataan switch di mana saja di kelas.

Untuk menjawab pertanyaan Anda, saya tidak percaya Anda dapat mengakses (selain refleksi) kelas sintetis.

Jika Anda menganalisis kelas yang tidak Anda ketahui (melalui refleksi) dan perlu mengetahui hal-hal yang sangat spesifik dan tingkat rendah tentang kelas itu, Anda mungkin berakhir menggunakan metode refleksi Java yang ada hubungannya dengan kelas sintetis. Satu-satunya "penggunaan" di sini adalah mendapatkan informasi lebih lanjut tentang kelas untuk menggunakannya secara tepat dalam kode Anda.

(Jika Anda melakukan ini, Anda mungkin sedang membangun semacam kerangka yang bisa digunakan pengembang lain.)

Kalau tidak, jika Anda tidak menggunakan refleksi, tidak ada kegunaan praktis dari kelas sintetis yang saya tahu.

Milhous
sumber
1
Ya, kode sampel akan baik jika Anda dapat memberikan contoh /
nanofarad
36
Ini tidak menjawab pertanyaan.
Dawood ibn Kareem
Untuk case switch, saya tidak yakin apakah ini terjadi untuk setiap switch, tetapi saya telah mengamati ini untuk switch dengan enums; kompiler menghasilkan kelas anonim dengan bidang statis tunggal yang menyediakan pemetaan Enum.ordinal () -> 1, 2, 3 ... (jadi urutan tanpa celah), dan kemudian instruksi pencarian menjalankan switch pada urutan ini, tidak secara langsung tentang tata cara.
Radim Vansa
106

Java memiliki kemampuan untuk membuat kelas saat runtime. Kelas-kelas ini dikenal sebagai Kelas Sintetis atau Proxy Dinamis.

Lihat http://java.sun.com/j2se/1.5.0/docs/guide/reflection/proxy.html untuk informasi lebih lanjut.

Pustaka sumber terbuka lainnya, seperti CGLIB dan ASM juga memungkinkan Anda untuk menghasilkan kelas sintetis, dan lebih kuat daripada perpustakaan yang disediakan dengan JRE.

Kelas sintetis digunakan oleh pustaka AOP (Aspect Oriented Programming) seperti Spring AOP dan AspectJ, serta pustaka ORM seperti Hibernate.

Andrew Newdigate
sumber
6
Proxy Dinamis bukan Kelas Sintetis. Bukti:Proxy.newProxyInstance(Runnable.class.getClassLoader(), new Class[]{Runnable.class}, (proxy, method, args1) -> null).getClass().isSynthetic() == false
Miha_x64
3
Javadoc untuk java.lang.reflect.Member#isSyntheticmengatakan: Mengembalikan nilai true jika anggota ini diperkenalkan oleh kompiler; mengembalikan false jika tidak.
Guillaume Husta
Saya percaya bahwa javadoc untuk java.lang.reflect.Member#isSynthetictidak relevan dengan pertanyaan awal. Anggota adalah bidang, konstruktor dan metode. Pertanyaan aslinya adalah tentang kelas sintetis , bukan anggota sintetis. Di Jawa 8, ekspresi lambda memunculkan kelas sintetis - Saya tidak yakin keadaan apa yang bisa muncul.
Pater Jeremy Krieg
54

Yah saya menemukan jawaban untuk pertanyaan pertama di google:

Kelas dapat ditandai sebagai sintetis jika dihasilkan oleh kompiler, yaitu, itu tidak muncul dalam kode sumber.

Ini hanya definisi dasar tapi saya menemukannya di utas forum dan tidak ada penjelasan. Masih mencari yang lebih baik ...

danHapp
sumber
15

kelas / metode / bidang sintetis:

Hal-hal ini penting untuk VM. Lihat cuplikan kode berikut:

class MyOuter {

  private MyInner inner;

  void createInner() {
    // The Compiler has to create a synthetic method
    // to construct a new MyInner because the constructor
    // is private.
    // --> synthetic "constructor" method
    inner = new MyInner();

    // The Compiler has to create a synthetic method
    // to doSomething on MyInner object because this
    // method is private.
    // --> synthetic "doSomething" method
    inner.doSomething();
  }

  private class MyInner {
    // the inner class holds a syntetic ref_pointer to
    // the outer "parent" class
    // --> synthetic field
    private MyInner() {
    }
    private void doSomething() {
    }
  }
}
Vinay W
sumber
2
@CiroSantilli 烏坎 事件 2016 六四 事件 法轮功, tidak, hanya metode pengakses sintetis.
Miha_x64
8

Menurut diskusi ini , meskipun spesifikasi bahasa menggambarkan proprty "isSynthetic" untuk kelas, ini cukup diabaikan oleh implementasi dan tidak digunakan untuk proxy dinamis atau kelas anonim. Bidang sintetik dan konstruktor digunakan untuk mengimplementasikan kelas bertingkat (tidak ada konsep kelas bertingkat dalam kode byte, hanya dalam kode sumber).

Saya pikir konsep kelas sintetis terbukti tidak berguna, yaitu tidak ada yang peduli apakah kelas sintetis. Dengan bidang dan metode, ini mungkin digunakan tepat di satu tempat: untuk menentukan apa yang akan ditampilkan dalam tampilan struktur kelas IDE - Anda ingin metode dan bidang normal muncul di sana, tetapi bukan yang sintetis yang digunakan untuk mensimulasikan kelas bersarang. OTOH, Anda TIDAK ingin kelas anonim muncul di sana.

Michael Borgwardt
sumber
@OrangeDog: ya, itulah yang saya tulis.
Michael Borgwardt
Jawaban ini tampaknya sudah usang karena java 8 - lambdas dan referensi metode memanfaatkan fitur ini. Saya telah menambahkan jawaban yang menunjukkan bahwa
Hulk
7

Mereka dibuat oleh JVM pada saat run time ketika mereka memanggil anggota pribadi kelas dalam untuk tujuan debugging

Metode, bidang, kelas yang dibuat oleh JVM selama waktu berjalan untuk tujuan pelaksanaannya disebut Sintetis

http://www.javaworld.com/article/2073578/java-s-synthetic-methods.html

http://javapapers.com/core-java/java-synthetic-class-method-field/

sathis
sumber
Saya kira maksud Anda pada waktu kompilasi, dan bukan pada saat runtime.
Mostowski Collapse
@sathis, maksudmu javac, bukan JVM?
Miha_x64
3

Juga Kelas Sintetis atau Proxy Dinamis digunakan oleh EasyMock untuk membuat implementasi antarmuka atau kelas abstrak saat runtime.

http://www.easymock.org/

pengguna2427
sumber
2

Ketika kompiler Java mengkompilasi konstruksi tertentu, seperti kelas dalam, itu membuat konstruksi sintetis ; ini adalah kelas, metode, bidang, dan konstruk lain yang tidak memiliki konstruk yang sesuai dalam kode sumber.
Penggunaan: Konstruksi sintetik memungkinkan kompiler Java untuk mengimplementasikan fitur-fitur bahasa Java baru tanpa perubahan pada JVM. Namun, konstruksi sintetik dapat bervariasi di antara implementasi Java compiler yang berbeda, yang berarti bahwa file .class dapat bervariasi di antara implementasi yang berbeda juga.
referensi: docs.oracle.com

anavaras lamurep
sumber
2

Seperti yang telah ditunjukkan oleh berbagai jawaban, kompiler diperbolehkan untuk menghasilkan berbagai konstruk (termasuk kelas) yang tidak secara langsung berhubungan dengan sesuatu dalam kode sumber. Ini harus ditandai sebagai sintetis:

13.1. Bentuk Biner

Representasi biner untuk kelas atau antarmuka juga harus mengandung semua hal berikut:
[...]
11. Sebuah konstruk yang dipancarkan oleh kompiler Java harus ditandai sebagai sintetis jika tidak sesuai dengan konstruk yang dinyatakan secara eksplisit atau implisit dalam kode sumber. , kecuali konstruk yang dipancarkan adalah metode inisialisasi kelas (JVMS §2.9).
[...]

Seperti yang ditunjukkan oleh @ Holger dalam komentar untuk pertanyaan lain, contoh yang relevan untuk konstruksi tersebut adalah objek Kelas yang mewakili referensi metode dan lambda:

System.out.println(((Runnable) System.out::println).getClass().isSynthetic());
System.out.println(((Runnable) () -> {}).getClass().isSynthetic());

Keluaran:

true
true

Meskipun ini tidak disebutkan secara eksplisit, ini mengikuti dari 15.27.4. Evaluasi Run-Time dari Ekspresi Lambda :

Nilai ekspresi lambda adalah referensi ke instance kelas dengan properti berikut: [...]

dan kata-kata yang hampir identik untuk referensi metode ( 15.13.3. Evaluasi Run-Time dari Metode Referensi ).

Karena kelas ini tidak disebutkan secara eksplisit di mana pun dalam kode sumber, itu harus sintetis.

Hulk
sumber
1

Jika saya melakukannya dengan benar, kelas sintetis dihasilkan dengan cepat, tanpa harus memberikannya nama eksplisit. Sebagai contoh:

//...
Thread myThread = new Thread() {
         public void run() {
           // do something ...
         }
       };
myThread.start();
//...

Ini membuat subclass sintetis dari Thread dan menimpa metode run (), lalu instantiate dan mulai.

Ivan
sumber
3
Saya pikir itu adalah kelas batin anonim
Kumar Abhinav
2
Saya harus setuju dengan @KumarAbhinav. Tidak semua kelas batin anonim adalah sintetis. Lihat: xinotes.net/notes/note/1339
bvdb
Kelas dalam anonim tidak menghasilkan kelas sintetis pada Oracle JDK 1.8.0_45, mereka menghasilkan kelas non-sintetis terpisah dengan nama tipe Outer$1.class.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1

Kelas sintetis tidak muncul di kode Anda: itu dibuat oleh kompiler. Misalnya, metode jembatan yang dibuat oleh kompiler di java biasanya sintetis.

public class Pair<T> {
    private T first;
    private T second;
    public void setSecond(T newValue) {
        second = newValue;
    }
}


public class DateInterval extends Pair<String> {
    public void setSecond(String second) {
        System.out.println("OK sub");
    }

    public static void main(String[] args) throws NoSuchFieldException, SecurityException {
        DateInterval interval = new DateInterval();
        Pair pair = interval;
        pair.setSecond("string1");
    }
}

Menggunakan perintah javap -verbose DateInterval, Anda dapat melihat metode jembatan:

public void setSecond(java.lang.Object);
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC

Ini dibuat oleh kompiler; itu tidak muncul dalam kode Anda.

JavaFresher
sumber
1

Apa itu kelas sintetis di Jawa?

Sebuah synthetickelas adalah .classfile yang dihasilkan oleh Java Compiler dan itu tidak ada dalam kode sumber.

Contoh penggunaan synthetickelas: Kelas batin anonim

  • java.text.DigitList $ 1 adalah synthetickelas dan itu adalah kelas batin anonim di dalam java.text.DigitList
  • Dan tidak ada file kode sumber bernama seperti DigitList$1.javatetapi itu adalah file dalamDigitList.java

Mengapa harus digunakan?

Ini adalah mekanisme di dalam logika kompiler Java untuk menghasilkan .classfile

Bagaimana saya bisa menggunakannya?

Tidak, pengembang TIDAK menggunakannya secara langsung.

Java compiler digunakan syntheticuntuk menghasilkan .classfile, dan kemudian JVM membaca .classfile tersebut untuk menjalankan logika program.

Keterangan lebih lanjut

  • Artikel ini menjelaskan synthetickelas secara detail
  • Tautan ini mencantumkan semua syntheticpintu keluar kelas di JDK
Senang
sumber
yang artikel yang sangat berguna, terima kasih
JasonMing
0

Konstruk sintetik adalah kelas, metode, bidang dll yang tidak memiliki konstruk yang sesuai dalam kode sumber. Konstruksi sintetik memungkinkan kompiler Java untuk mengimplementasikan fitur-fitur bahasa Java baru tanpa perubahan pada JVM. Namun, konstruksi sintetik dapat bervariasi di antara implementasi Java compiler yang berbeda, yang berarti bahwa file .class dapat bervariasi di antara implementasi yang berbeda juga.

Anoop Dixith
sumber
1
-1. Teks yang sama, kata demi kata, telah diposting dalam jawaban yang diberikan satu tahun sebelum Anda [ stackoverflow.com/a/24271953/1144395] , dan lebih jauh lagi, jawaban itu juga mengutip referensi resmi dari mana teks itu berasal, dan menyediakan format untuk memudahkan pembacaan . Tolong jangan rakus pertanyaan spam dengan jawaban duplikat jelas.
naki