Một yếu tố tổng hợp là bất kỳ yếu tố đó hiện diện trong một tập tin lớp biên soạn nhưng không phải trong mã nguồn của nó được biên dịch từ. Bằng cách kiểm tra một phần tử cho nó là tổng hợp, bạn cho phép phân biệt các yếu tố như vậy cho các công cụ xử lý mã phản chiếu. Đây là khóa học đầu tiên liên quan đến các thư viện sử dụng sự phản chiếu nhưng nó cũng phù hợp với các công cụ khác như IDE không cho phép bạn gọi các phương thức tổng hợp hoặc làm việc với các lớp tổng hợp. Cuối cùng, nó cũng quan trọng đối với trình biên dịch Java để xác minh mã trong quá trình biên dịch của nó để không bao giờ trực tiếp sử dụng các phần tử tổng hợp. Các phần tử tổng hợp chỉ được sử dụng để làm cho thời gian chạy Java hạnh phúc mà chỉ đơn giản là xử lý (và xác minh) mã được phân phối, nơi nó xử lý các phần tử tổng hợp giống với bất kỳ phần tử nào khác.
Bạn đã đề cập các lớp bên trong là một ví dụ nơi các yếu tố tổng hợp được chèn bởi trình biên dịch Java, vì vậy chúng ta hãy nhìn vào một lớp học như:
class Foo {
private String foo;
class Bar {
private Bar() { }
String bar() {
return foo;
}
}
Bar bar() {
return new Bar();
}
}
này biên dịch hoàn toàn tốt đẹp nhưng không có các yếu tố tổng hợp, nó sẽ là từ chối bởi một JVM không biết gì về các lớp bên trong. Trình biên dịch Java desugares lớp trên để một cái gì đó như sau:
class Foo {
private String foo;
String access$100() { // synthetic method
return foo;
}
Foo$Bar bar() {
return new Foo$Bar(this, (Foo$1)null);
}
Foo() { } // NON-synthetic, but implicit!
}
class Foo$Bar {
private final Foo $this; // synthetic field
private Foo$Bar(Foo $this) { // synthetic parameter
this.$this = $this;
}
Foo$Bar(Foo $this, Foo$1 unused) { // synthetic constructor
this($this);
}
String bar() {
return $this.access$100();
}
}
class Foo$1 { /*empty, no constructor */ } // synthetic class
Như đã nói, JVM không biết về các lớp bên nhưng thực thi truy cập tin của các thành viên, tức là một lớp bên trong sẽ không thể truy cập các thuộc tính riêng của các lớp kèm theo. Do đó, trình biên dịch Java cần phải thêm cái gọi là bộ truy xuất đến một lớp truy cập để vạch trần tính chất không nhìn thấy được của nó:
Trường foo
là tư nhân và có thể do đó chỉ có thể được truy cập từ bên trong Foo
. Phương thức access$100
cho thấy trường này với gói của nó, trong đó lớp bên trong luôn luôn được tìm thấy. Phương thức này là tổng hợp vì nó được trình biên dịch thêm vào.
Nhà xây dựng Bar
là riêng tư và do đó chỉ có thể được gọi từ bên trong lớp của chính nó. Để khởi tạo một thể hiện của Bar
, một hàm tạo (tổng hợp) khác cần trưng ra việc xây dựng một cá thể. Tuy nhiên, các nhà xây dựng có một tên cố định (nội bộ, tất cả chúng được gọi là <init>
), do đó chúng tôi không thể áp dụng kỹ thuật cho các trình truy cập phương thức mà chúng tôi chỉ đặt tên cho chúng là access$xxx
. Thay vào đó, chúng tôi tạo các trình tạo hàm tạo duy nhất bằng cách tạo kiểu tổng hợp Foo$1
.
Để truy cập thể hiện bên ngoài của nó, lớp bên trong cần lưu trữ tham chiếu đến trường hợp này được lưu trữ trong trường tổng hợp $this
. Tham chiếu này cần phải được trao cho cá thể bên trong bằng một tham số tổng hợp trong hàm tạo.
ví dụ khác cho các yếu tố tổng hợp các lớp học mà đại diện cho biểu thức lambda, phương pháp cầu khi trọng phương pháp với một kiểu khác nhau chữ ký, việc tạo ra các Proxy
lớp hoặc các lớp học được tạo ra bởi các công cụ khác như Maven xây dựng hoặc mã runtime máy phát điện như Byte Buddy (phích cắm không biết xấu hổ).
Nguồn
2014-09-26 08:43:25
Cảm ơn gợi ý. Tôi đã cập nhật câu hỏi cho phù hợp. –
@PeterKofler Đã cập nhật. –
nói "Thành viên lớp không xuất hiện trong mã nguồn phải được đánh dấu bằng thuộc tính Tổng hợp". Điều đó có nghĩa là một thành viên tổng hợp cũng được đánh dấu bằng công cụ sửa đổi truy cập '0x1000' (trong' u2 access_flags')? Nó không rõ ràng. –