คลาสสังเคราะห์ใน Java


143

คลาสสังเคราะห์ใน Java คืออะไร ทำไมจึงควรใช้ ฉันจะใช้มันได้อย่างไร


1
คำตอบ "ไม่ใช่ในรหัสของคุณ" ล้าสมัยกับ Java 8 เนื่องจาก lambdas สามารถนำไปใช้เป็นคลาสสังเคราะห์ (ไม่ใช่แบบไม่ระบุชื่อ) ได้
OrangeDog

เพื่อความเป็นธรรมแลมบ์ดายังไม่ "เคร่งครัด" คลาสที่กำหนดไว้อย่างชัดเจนภายในรหัสของคุณ ดังนั้น "ไม่ใช่ในรหัสของคุณ" จึงยังคงใช้ได้ คอมไพเลอร์สร้างคลาสสังเคราะห์ให้คุณโดยไม่มีคำจำกัดความที่ชัดเจนในรหัสของคุณ
ManoDestra

คำตอบ:


15

ตัวอย่างเช่นเมื่อคุณมีคำสั่ง switch, java จะสร้างตัวแปรที่ขึ้นต้นด้วย $ หากคุณต้องการดูตัวอย่างของสิ่งนี้ให้มองเข้าไปในการสะท้อน java ของคลาสที่มีคำสั่ง switch อยู่ คุณจะเห็นตัวแปรเหล่านี้เมื่อคุณมีคำสั่งสวิตช์อย่างน้อยหนึ่งคำสั่งที่ใดก็ได้ในชั้นเรียน

เพื่อตอบคำถามของคุณฉันไม่เชื่อว่าคุณสามารถเข้าถึง (นอกเหนือจากการสะท้อน) ชั้นสังเคราะห์

หากคุณกำลังวิเคราะห์คลาสที่คุณไม่ทราบอะไรเกี่ยวกับ (ผ่านการสะท้อนกลับ) และจำเป็นต้องรู้สิ่งที่เฉพาะเจาะจงและระดับต่ำเกี่ยวกับคลาสนั้นคุณอาจสิ้นสุดด้วยการใช้ Java reflection method ที่เกี่ยวข้องกับคลาสสังเคราะห์ "ใช้" เท่านั้นที่นี่รับข้อมูลเพิ่มเติมเกี่ยวกับชั้นเรียนเพื่อใช้ในรหัสของคุณอย่างเหมาะสม

(ถ้าคุณทำเช่นนี้คุณอาจสร้างกรอบบางประเภทที่ผู้พัฒนารายอื่นสามารถใช้)

มิฉะนั้นถ้าคุณไม่ได้ใช้การสะท้อนก็ไม่มีประโยชน์ในการใช้คลาสสังเคราะห์ที่ฉันรู้จัก


1
ใช่โค้ดตัวอย่างจะดีถ้าคุณสามารถให้ตัวอย่าง /
nanofarad

36
สิ่งนี้ไม่ตอบคำถาม
Dawood ibn Kareem

สำหรับกรณีสวิตช์ฉันไม่แน่ใจว่าสิ่งนี้เกิดขึ้นกับสวิตช์ทุกอันหรือไม่ แต่ฉันสังเกตเห็นว่าสวิตช์นั้นมี enums อยู่หรือไม่ คอมไพเลอร์สร้างคลาสแบบไม่ระบุชื่อด้วยฟิลด์สแตติกเดียวที่ให้การแมป Enum.ordinal () -> 1, 2, 3 ... (ดังนั้นลำดับโดยไม่มีช่องว่าง) จากนั้นคำสั่ง lookupswitch จะเรียกใช้สวิตช์บนลำดับนี้ไม่ใช่โดยตรง ตามลำดับ
Radim Vansa

106

Java มีความสามารถในการสร้างคลาสที่รันไทม์ คลาสเหล่านี้เรียกว่า Synthetic Classes หรือ Dynamic Proxies

ดูhttp://java.sun.com/j2se/1.5.0/docs/guide/reflection/proxy.htmlสำหรับข้อมูลเพิ่มเติม

ไลบรารีโอเพ่นซอร์สอื่น ๆ เช่นCGLIBและASMยังอนุญาตให้คุณสร้างคลาสสังเคราะห์และมีประสิทธิภาพมากกว่าไลบรารีที่จัดเตรียมไว้พร้อมกับ JRE

คลาสสังเคราะห์ถูกใช้โดยไลบรารี AOP (Aspect Oriented Programming) เช่น Spring AOP และ AspectJ รวมถึงไลบรารี ORM เช่น Hibernate


6
พร็อกProxy.newProxyInstance(Runnable.class.getClassLoader(), new Class[]{Runnable.class}, (proxy, method, args1) -> null).getClass().isSynthetic() == false
ซี่

3
javadoc สำหรับjava.lang.reflect.Member#isSyntheticพูดว่า: คืนค่าจริงถ้าสมาชิกนี้ได้รับการแนะนำโดยคอมไพเลอร์; ผลตอบแทนที่ผิดพลาดเป็นอย่างอื่น
Guillaume Husta

ฉันเชื่อว่า javadoc สำหรับjava.lang.reflect.Member#isSyntheticนั้นไม่เกี่ยวข้องกับคำถามเดิม สมาชิกคือเขตข้อมูลผู้สร้างและวิธีการ คำถามเดิมเป็นเรื่องเกี่ยวกับคลาสสังเคราะห์ไม่ใช่สมาชิกสังเคราะห์ ใน Java 8 นิพจน์แลมบ์ดาทำให้เกิดคลาสสังเคราะห์ขึ้น - ฉันไม่แน่ใจว่าสถานการณ์อื่น ๆ ที่พวกเขาสามารถเกิดขึ้นได้
Fr Jeremy Krieg

54

ฉันพบคำตอบสำหรับคำถามแรกใน google:

ชั้นอาจถูกทำเครื่องหมายเป็นสังเคราะห์ถ้ามันถูกสร้างขึ้นโดยคอมไพเลอร์นั่นคือมันจะไม่ปรากฏในรหัสที่มา

นี่เป็นเพียงคำจำกัดความพื้นฐาน แต่ฉันพบในกระทู้ในฟอรัมและไม่มีคำอธิบาย ยังคงมองหาสิ่งที่ดีกว่า ...


15

คลาสสังเคราะห์ / วิธี / ฟิลด์:

สิ่งเหล่านี้มีความสำคัญสำหรับ VM ดูตัวอย่างโค้ดต่อไปนี้:

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() {
    }
  }
}

2
@CiroSantilli 烏坎事件 2016 六四事件法轮功, ไม่ใช่, วิธีการสังเคราะห์สังเคราะห์เท่านั้น
Miha_x64

8

จากการอภิปรายนี้แม้ว่าข้อกำหนดทางภาษาจะอธิบายถึง "isSynthetic" สำหรับคลาส แต่ก็ไม่สนใจการใช้งานและไม่ได้ใช้สำหรับพร็อกซีแบบไดนามิกหรือคลาสที่ไม่ระบุชื่อ ฟิลด์สังเคราะห์และคอนสตรัคเตอร์ใช้เพื่อสร้างคลาสที่ซ้อนกัน (ไม่มีแนวคิดของคลาสที่ซ้อนในโค้ดไบต์เฉพาะในซอร์สโค้ด)

ฉันคิดว่าแนวคิดของคลาสสังเคราะห์ได้พิสูจน์แล้วว่าไม่มีประโยชน์นั่นคือไม่มีใครใส่ใจว่าคลาสนั้นเป็นสังเคราะห์หรือไม่ ด้วยเขตข้อมูลและวิธีการก็อาจใช้ในที่เดียว: เพื่อกำหนดสิ่งที่จะแสดงในมุมมองโครงสร้างคลาส IDE - คุณต้องการวิธีการปกติและสาขาที่จะปรากฏขึ้นที่นั่น แต่ไม่ใช่คนสังเคราะห์ที่ใช้ในการจำลองชั้นเรียนที่ซ้อนกัน OTOH คุณต้องการให้คลาสนิรนามปรากฏขึ้นที่นั่น


@ OrangeDog: ใช่นั่นคือสิ่งที่ฉันเขียน
Michael Borgwardt

คำตอบนี้ดูเหมือนจะล้าสมัยตั้งแต่ java 8 - lambdas และการอ้างอิงวิธีการใช้ประโยชน์จากคุณลักษณะนี้ ฉันได้เพิ่มคำตอบที่แสดงให้เห็นว่า
ฮัลค์

7

พวกเขาถูกสร้างขึ้นโดย JVM ในเวลาทำงานเมื่อพวกเขาเรียกสมาชิกส่วนตัวของชั้นในสำหรับวัตถุประสงค์ในการแก้จุดบกพร่อง

เมธอดฟิลด์คลาสที่สร้างโดย JVM ระหว่างเวลารันเพื่อวัตถุประสงค์ในการเรียกใช้งานเรียกว่า Synthetic

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

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


ฉันเดาว่าคุณหมายถึงเวลารวบรวมไม่ใช่เวลารันไทม์
Mostowski ยุบ

@sathis คุณหมายถึง javac ไม่ใช่ JVM หรือเปล่า
Miha_x64

3

นอกจากนี้ Synthetic Classes หรือ Dynamic Proxies จะถูกใช้โดย EasyMock เพื่อสร้างการใช้งานของอินเตอร์เฟสหรือคลาสนามธรรมที่รันไทม์

http://www.easymock.org/


2

เมื่อคอมไพเลอร์ Java รวบรวมโครงสร้างบางอย่างเช่นการเรียนภายในจะสร้างโครงสร้างสังเคราะห์ ; นี่คือคลาสวิธีการฟิลด์และโครงสร้างอื่น ๆ ที่ไม่มีโครงสร้างที่สอดคล้องกันในซอร์สโค้ด
ใช้: โครงสร้างสังเคราะห์เปิดใช้งานคอมไพเลอร์ Java เพื่อใช้คุณลักษณะภาษา Java ใหม่โดยไม่เปลี่ยนแปลง JVM อย่างไรก็ตามโครงสร้างสังเคราะห์อาจแตกต่างกันระหว่างการใช้งานคอมไพเลอร์ Java ที่แตกต่างกันซึ่งหมายความว่าไฟล์. class สามารถแตกต่างกันระหว่างการใช้งานที่แตกต่างกันเช่นกัน
การอ้างอิง: docs.oracle.com


2

ตามคำตอบที่หลากหลายได้ชี้ให้เห็นแล้วคอมไพเลอร์ได้รับอนุญาตให้สร้างโครงสร้างต่าง ๆ (รวมถึงคลาส) ที่ไม่ตรงกับบางสิ่งบางอย่างในรหัส souce สิ่งเหล่านี้จะต้องมีการทำเครื่องหมายเป็นสังเคราะห์:

13.1 รูปแบบของไบนารี

การเป็นตัวแทนไบนารีสำหรับคลาสหรือส่วนต่อประสานต้องประกอบด้วยสิ่งต่อไปนี้ทั้งหมด:
[... ]
11. โครงสร้างที่ปล่อยออกมาโดยคอมไพเลอร์ Java จะต้องทำเครื่องหมายเป็นสังเคราะห์ถ้าไม่สอดคล้องกับโครงสร้างที่ประกาศอย่างชัดเจนหรือโดยปริยายในซอร์สโค้ด ยกเว้นว่าการสร้างที่ปล่อยออกมาเป็นวิธีการเริ่มต้นเรียน (JVMS §2.9)
[ ... ]

ตามที่ระบุโดย@Holgerในความคิดเห็นคำถามอื่นตัวอย่างที่เกี่ยวข้องสำหรับการสร้างดังกล่าวเป็นวัตถุคลาสที่แสดงวิธีการอ้างอิงและ lambdas:

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

เอาท์พุท:

true
true

แม้ว่าสิ่งนี้จะไม่ได้กล่าวถึงอย่างชัดเจน แต่ก็มีตั้งแต่ 15.27.4 การประเมินเวลาทำการของแลมบ์ดานิพจน์ :

ค่าของนิพจน์แลมบ์ดาเป็นการอ้างอิงถึงอินสแตนซ์ของคลาสที่มีคุณสมบัติต่อไปนี้: [... ]

และถ้อยคำที่เกือบเหมือนกันสำหรับการอ้างอิงวิธีการ ( 15.13.3. การประเมินเวลาทำงานของการอ้างอิงวิธีการ )

เนื่องจากคลาสนี้ไม่ได้กล่าวถึงอย่างชัดเจนทุกที่ในซอร์สโค้ดจึงต้องมีการสังเคราะห์


1

ถ้าฉันทำให้ถูกต้องคลาสสังเคราะห์เป็นคลาสที่สร้างขึ้นโดยไม่ต้องตั้งชื่อให้ชัดเจน ตัวอย่างเช่น:

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

สิ่งนี้สร้างคลาสย่อยสังเคราะห์ของ Thread และแทนที่เมธอด run () ของมันจากนั้นเริ่มต้นอินสแตนซ์และเริ่มต้นมัน


3
ฉันคิดว่ามันเป็นชั้นในแบบไม่ระบุชื่อ
Kumar Abhinav

2
ฉันต้องเห็นด้วยกับ @ KumarAbhinav คลาสภายในที่ไม่ระบุชื่อทั้งหมดนั้นเป็นของสังเคราะห์ ดู: xinotes.net/notes/note/1339
bvdb

เรียนภายในที่ไม่ระบุชื่อไม่ได้สร้างการเรียนการสังเคราะห์ใน Oracle JDK 1.8.0_45 Outer$1.classพวกเขาสร้างการเรียนไม่ใช่สังเคราะห์แยกต่างหากที่มีชื่อของประเภท
Ciro Santilli 郝海东冠状病六四事件法轮功

1

คลาสสังเคราะห์ไม่ปรากฏในรหัสของคุณ: ประกอบด้วยคอมไพเลอร์ เช่นวิธีการบริดจ์ที่สร้างขึ้นโดยคอมไพเลอร์ใน Java มักจะสังเคราะห์

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");
    }
}

ใช้คำสั่งjavap -verbose DateIntervalคุณสามารถดูวิธีการสะพาน:

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

สิ่งนี้ถูกสร้างขึ้นโดยคอมไพเลอร์; มันไม่ปรากฏในรหัสของคุณ


1

คลาสสังเคราะห์ใน Java คืออะไร

syntheticระดับเป็น.classไฟล์ที่สร้างโดยJava คอมไพเลอร์และมันไม่ได้อยู่ในรหัสที่มา

ตัวอย่างการใช้syntheticคลาส: คลาสภายในที่ไม่ระบุชื่อ

  • java.text.DigitList $ 1เป็นsyntheticคลาสและเป็นคลาสภายในแบบไม่ระบุชื่อในjava.text.DigitList
  • และไม่มีไฟล์ซอร์สโค้ดชื่อเหมือนDigitList$1.javaแต่มันเป็นไฟล์ภายในDigitList.java

ทำไมจึงควรใช้

มันเป็นกลไกภายในตรรกะของคอมไพเลอร์ Java เพื่อสร้าง.classไฟล์

ฉันจะใช้มันได้อย่างไร

ไม่นักพัฒนาไม่ได้ใช้งานโดยตรง

คอมไพเลอร์ Java ใช้syntheticเพื่อสร้าง.classไฟล์จากนั้น JVM จะอ่าน.classไฟล์เพื่อดำเนินการตรรกะของโปรแกรม

รายละเอียดเพิ่มเติม

  • นี้บทความอธิบายถึงsyntheticการเรียนในรายละเอียด
  • ลิงค์นี้แสดงรายการการsyntheticออกจากคลาสทั้งหมดในJDK

บทความเป็นประโยชน์อย่างมากขอขอบคุณ
JasonMing

0

โครงสร้างแบบสังเคราะห์คือคลาส, วิธีการ, ฟิลด์อื่น ๆ ที่ไม่มีโครงสร้างที่สอดคล้องกันในซอร์สโค้ด โครงสร้างแบบซินเทติกเปิดใช้งานคอมไพเลอร์ Java เพื่อใช้งานคุณสมบัติภาษา Java ใหม่โดยไม่มีการเปลี่ยนแปลงกับ JVM อย่างไรก็ตามโครงสร้างสังเคราะห์อาจแตกต่างกันระหว่างการใช้งานคอมไพเลอร์ Java ที่แตกต่างกันซึ่งหมายความว่าไฟล์. class สามารถแตกต่างกันระหว่างการใช้งานที่แตกต่างกันเช่นกัน


1
-1 คำต่อคำที่เหมือนกันมากถูกโพสต์ไว้ในคำตอบที่ให้ไว้หนึ่งปีก่อนหน้าคุณ [ stackoverflow.com/a/24271953/1144395]และเพิ่มเติมจากนั้นคำตอบนั้นยังอ้างถึงการอ้างอิงอย่างเป็นทางการที่ข้อความนั้นมาและจัดรูปแบบเพื่อให้อ่านง่ายขึ้น . โปรดอย่าตั้งคำถามสแปมอย่างตะกละตะกลามพร้อมคำตอบที่ซ้ำกันอย่างชัดเจน
naki
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.