Lớp tổng hợp trong Java


143

Một lớp tổng hợp trong Java là gì? Tại sao nó nên được sử dụng? Làm thế nào tôi có thể sử dụng nó?


1
Tất cả các câu trả lời "không có trong mã của bạn" đã lỗi thời với Java 8, vì lambdas có thể được triển khai dưới dạng các lớp tổng hợp (không ẩn danh).
OrangeDog

Công bằng mà nói, lambda vẫn không "nghiêm túc" một lớp được định nghĩa rõ ràng trong mã của bạn. Vì vậy, "không có trong mã của bạn" vẫn hợp lệ. Trình biên dịch tạo các lớp tổng hợp cho bạn mà không có định nghĩa rõ ràng trong mã của bạn.
ManoD nhạc

Câu trả lời:


15

Ví dụ: Khi bạn có câu lệnh switch, java sẽ tạo một biến bắt đầu bằng $. Nếu bạn muốn xem một ví dụ về điều này, hãy xem qua phản ánh java của một lớp có câu lệnh chuyển đổi trong đó. Bạn sẽ thấy các biến này khi bạn có ít nhất một câu lệnh switch ở bất cứ đâu trong lớp.

Để trả lời câu hỏi của bạn, tôi không tin rằng bạn có thể truy cập (ngoài phản ánh) các lớp tổng hợp.

Nếu bạn đang phân tích một lớp mà bạn không biết gì về (thông qua sự phản chiếu) và cần biết những điều rất cụ thể và ở mức độ thấp về lớp đó, thì bạn có thể sẽ sử dụng các phương thức phản chiếu Java phải làm với các lớp tổng hợp. "Sử dụng" duy nhất ở đây là lấy thêm thông tin về lớp để sử dụng nó một cách thích hợp trong mã của bạn.

(Nếu bạn đang làm điều này, có lẽ bạn đang xây dựng một khung gồm một số loại mà các nhà phát triển khác có thể sử dụng.)

Mặt khác, nếu bạn không sử dụng sự phản chiếu, thì không có cách sử dụng thực tế nào của các lớp tổng hợp mà tôi biết.


1
Có, mã mẫu sẽ tốt nếu bạn có thể cung cấp một ví dụ /
nanofarad

36
Điều này không trả lời câu hỏi.
Dawood ibn Kareem

Đối với trường hợp chuyển đổi, tôi không chắc liệu điều này có xảy ra với mọi công tắc hay không, nhưng tôi đã quan sát điều này để chuyển đổi với enums; trình biên dịch tạo lớp ẩn danh với trường tĩnh duy nhất cung cấp ánh xạ Enum.ordinal () -> 1, 2, 3 ... (vì vậy một chuỗi không có khoảng trống), và sau đó một lệnh tra cứu chạy công tắc trên chuỗi này, không trực tiếp về chức sắc.
Radim Vansa

106

Java có khả năng tạo các lớp khi chạy. Các lớp này được gọi là Lớp tổng hợp hoặc Proxy động.

Xem http://java.sun.com/j2se/1.5.0/docs/guide/reflection/proxy.html để biết thêm thông tin.

Các thư viện nguồn mở khác, chẳng hạn như CGLIBASM cũng cho phép bạn tạo các lớp tổng hợp và mạnh hơn các thư viện được cung cấp với JRE.

Các lớp tổng hợp được sử dụng bởi các thư viện AOP (Lập trình hướng đối tượng) như Spring AOP và AspectJ, cũng như các thư viện ORM như Hibernate.


6
Proxy động không phải là lớp tổng hợp. Dự án:Proxy.newProxyInstance(Runnable.class.getClassLoader(), new Class[]{Runnable.class}, (proxy, method, args1) -> null).getClass().isSynthetic() == false
Miha_x64

3
Javadoc cho java.lang.reflect.Member#isSyntheticbiết: Trả về true nếu thành viên này được trình biên dịch giới thiệu; trả về sai khác.
Guillaume Husta

Tôi tin rằng javadoc java.lang.reflect.Member#isSynthetickhông liên quan đến câu hỏi ban đầu. Thành viên là các lĩnh vực, nhà xây dựng và phương pháp. Câu hỏi ban đầu là về các lớp tổng hợp , không phải thành viên tổng hợp. Trong Java 8, các biểu thức lambda làm phát sinh các lớp tổng hợp - Tôi không chắc chúng có thể phát sinh trường hợp nào khác.
Cha Jeremy Krieg

54

Vâng, tôi đã tìm thấy câu trả lời cho câu hỏi đầu tiên trên google:

Một lớp có thể được đánh dấu là tổng hợp nếu nó được tạo bởi trình biên dịch, nghĩa là nó không xuất hiện trong mã nguồn.

Đây chỉ là một định nghĩa cơ bản nhưng tôi đã tìm thấy nó trong một chủ đề diễn đàn và không có lời giải thích. Vẫn đang tìm kiếm một thứ tốt hơn ...


15

lớp / phương pháp / trường tổng hợp:

Những điều này rất quan trọng đối với VM. Hãy xem đoạn mã sau:

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 六四 事件, không, chỉ có các phương pháp truy cập tổng hợp.
Miha_x64

8

Theo cuộc thảo luận này , mặc dù đặc tả ngôn ngữ mô tả một proprty "isSyy tổng hợp" cho các lớp, nhưng điều này bị bỏ qua khá nhiều bởi các triển khai và không được sử dụng cho các proxy động hoặc các lớp ẩn danh. Các trường tổng hợp và hàm tạo được sử dụng để triển khai các lớp lồng nhau (không có khái niệm về các lớp lồng nhau trong mã byte, chỉ có trong mã nguồn).

Tôi nghĩ rằng khái niệm về các lớp tổng hợp đơn giản đã được chứng minh là không hữu ích, tức là không ai quan tâm liệu một lớp có phải là tổng hợp hay không. Với các trường và phương thức, có lẽ nó được sử dụng ở một nơi chính xác: để xác định nội dung hiển thị trong chế độ xem cấu trúc lớp IDE - bạn muốn các phương thức và trường bình thường hiển thị ở đó, nhưng không phải là các phương thức tổng hợp được sử dụng để mô phỏng các lớp lồng nhau. OTOH, bạn muốn các lớp ẩn danh xuất hiện ở đó.


@OrangeDog: vâng, đó là những gì tôi đã viết.
Michael Borgwardt

Câu trả lời này dường như đã lỗi thời vì java 8 - lambdas và các tham chiếu phương thức sử dụng tính năng này. Tôi đã thêm một câu trả lời chứng minh rằng
Hulk

7

Chúng được tạo bởi JVM vào thời gian chạy khi chúng gọi các thành viên riêng của lớp bên trong cho mục đích gỡ lỗi

Các phương thức, các trường, lớp được tạo bởi JVM trong thời gian chạy cho mục đích thực thi của nó được gọi là Tổng hợp

http://www.javaworld.com/article/2073578/java-s-sy merg-method.html

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


Tôi đoán bạn có nghĩa là tại thời gian biên dịch, và không phải lúc chạy.
Mostowski sụp đổ

@sathis, ý bạn là javac chứ không phải JVM?
Miha_x64


2

Khi trình biên dịch Java biên dịch các cấu trúc nhất định, chẳng hạn như các lớp bên trong, nó tạo ra các cấu trúc tổng hợp ; đây là các lớp, phương thức, trường và các cấu trúc khác không có cấu trúc tương ứng trong mã nguồn.
Sử dụng: Các cấu trúc tổng hợp cho phép các trình biên dịch Java thực hiện các tính năng ngôn ngữ Java mới mà không cần thay đổi đối với JVM. Tuy nhiên, các cấu trúc tổng hợp có thể khác nhau giữa các triển khai trình biên dịch Java khác nhau, điều đó có nghĩa là các tệp. Class cũng có thể khác nhau giữa các triển khai khác nhau.
tham khảo: docs.oracle.com


2

Như các câu trả lời khác nhau đã chỉ ra, trình biên dịch được phép tạo ra các cấu trúc khác nhau (bao gồm các lớp) không tương ứng trực tiếp với một cái gì đó trong mã souce. Chúng phải được đánh dấu là tổng hợp:

13.1. Hình thức nhị phân

Một biểu diễn nhị phân cho một lớp hoặc giao diện cũng phải chứa tất cả các điều sau đây:
[...]
11. Một cấu trúc được phát ra bởi trình biên dịch Java phải được đánh dấu là tổng hợp nếu nó không tương ứng với một cấu trúc được khai báo rõ ràng hoặc ẩn trong mã nguồn , trừ khi cấu trúc phát ra là một phương thức khởi tạo lớp (JVMS §2.9).
[...]

Như @Holger đã chỉ ra trong một bình luận cho một câu hỏi khác, các ví dụ có liên quan cho các cấu trúc như vậy là các đối tượng Class đại diện cho các tham chiếu phương thức và lambdas:

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

Đầu ra:

true
true

Trong khi điều này không được đề cập rõ ràng, nó diễn ra từ 15.27.4. Đánh giá thời gian thực của biểu thức Lambda :

Giá trị của biểu thức lambda là tham chiếu đến một thể hiện của một lớp với các thuộc tính sau: [...]

và từ ngữ gần như giống hệt nhau cho các tham chiếu phương thức ( 15.13.3. Đánh giá thời gian thực của các tham chiếu phương thức ).

Vì lớp này không được đề cập rõ ràng ở bất cứ đâu trong mã nguồn, nó phải được tổng hợp.


1

Nếu tôi hiểu đúng, một lớp tổng hợp là một lớp được tạo ra một cách nhanh chóng, mà không cần phải đặt cho nó một cái tên rõ ràng. Ví dụ:

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

Điều này tạo ra một lớp con tổng hợp của Thread và ghi đè phương thức run () của nó, sau đó khởi tạo nó và khởi động nó.


3
tôi nghĩ rằng đó là một lớp bên trong vô danh
Kumar Abhinav

2
Tôi phải đồng ý với @KumarAbhinav. Không phải tất cả các lớp bên trong vô danh là tổng hợp. Xem: xinotes.net/notes/note/1339
bvdb

Các lớp bên trong ẩn danh không tạo các lớp tổng hợp trên Oracle JDK 1.8.0_45, chúng tạo các lớp không tổng hợp riêng biệt với các tên loại Outer$1.class.
Ciro Santilli 郝海东 冠状 病 事件

1

Một lớp tổng hợp trong Java là gì?

Một syntheticlớp là một .classtệp được tạo bởi Java Compiler và nó không tồn tại trong mã nguồn.

Ví dụ sử dụng syntheticlớp: Lớp bên trong ẩn danh

  • java.text.DigitList $ 1 là một syntheticlớp và nó là một lớp bên trong ẩn danh bên trong java.text.DigitList
  • Và không có tệp mã nguồn có tên như thế DigitList$1.javanhưng nó là một tệp bên trongDigitList.java

Tại sao nó nên được sử dụng?

Đây là một cơ chế bên trong logic trình biên dịch Java để tạo .classtệp

Làm thế nào tôi có thể sử dụng nó?

Không, nhà phát triển KHÔNG sử dụng nó trực tiếp.

Trình biên dịch Java sử dụng syntheticđể tạo .classtệp và sau đó JVM đọc .classtệp để thực thi logic chương trình.

Thêm chi tiết

  • Bài viết này giải thích syntheticchi tiết về lớp học
  • Liên kết này liệt kê tất cả các syntheticlối thoát lớp trong JDK

những bài viết rất hữu ích, cảm ơn bạn
JasonMing

0

Các cấu trúc tổng hợp là các lớp, phương thức, trường, v.v. không có cấu trúc tương ứng trong mã nguồn. Các cấu trúc tổng hợp cho phép các trình biên dịch Java thực hiện các tính năng ngôn ngữ Java mới mà không cần thay đổi đối với JVM. Tuy nhiên, các cấu trúc tổng hợp có thể khác nhau giữa các triển khai trình biên dịch Java khác nhau, điều đó có nghĩa là các tệp. Class cũng có thể khác nhau giữa các triển khai khác nhau.


1
-1. Văn bản tương tự, nguyên văn, đã được đăng trong câu trả lời được đưa ra một năm trước [ stackoverflow.com/a/24271953/1144395] , và hơn nữa câu trả lời đó đã trích dẫn thêm tài liệu tham khảo chính thức nơi văn bản bắt nguồn và cung cấp định dạng để dễ đọc hơn . Xin đừng tham lam những câu hỏi spam với câu trả lời trùng lặp rõ ràng.
naki

0

Một lớp tổng hợp không xuất hiện trong mã của bạn: nó được tạo bởi trình biên dịch. Ví dụ: Một phương thức cầu được tạo bởi trình biên dịch trong java thường là tổng hợp.

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

Sử dụng lệnh javap -verbose DateInterval, bạn có thể thấy một phương thức cầu nối:

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

Điều này đã được tạo ra bởi trình biên dịch; nó không xuất hiện trong mã của bạn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.