2013-03-04 42 views
16

Tôi có lớp học Outer có lớp học private Inner.Java: lớp xây dựng tổng hợp nội bộ riêng tư

Trong phương pháp lớp Outer của tôi, tôi nhanh chóng lớp Inner như sau:

Outer outer = new Outer(); 
Inner inner = outer.new Inner(); 

Trình biên dịch chuyển mã này vào:

Outer outer = new Outer(); 
Inner inner = new Inner(outer, null); 

Sử dụng phản ánh cho thấy lớp Inner có sau đây tổng hợp nhà thầu:

private Outer$Inner(Outer) 
Outer$Inner(Outer,Outer$Inner) 

Vì lớp Innerprivate, trình biên dịch cho biết thêm rằng private hàm tạo nên nó không ai có thể khởi tạo lớp đó. Nhưng rõ ràng là lớp Outer sẽ có thể khởi tạo nó, do đó trình biên dịch thêm rằng xây dựng gói riêng tư khác mà lần lượt gọi hàm tạo riêng. Ngoài ra, vì hàm tạo riêng tư của gói có tên là $ trong tên của nó, mã Java bình thường không thể gọi nó.

Câu hỏi: tại sao tổng hợp một trình xây dựng riêng tư và một gói riêng tư? Tại sao không tổng hợp chỉ constructor gói-tư nhân và được thực hiện với nó?

+0

@Noofiz các nhà xây dựng này được tạo ra bởi trình biên dịch, mà bạn không mã hóa rõ ràng cho chúng; do đó tôi gọi chúng là tổng hợp. – shrini1000

+0

@Noofiz Nếu bạn không hiểu câu hỏi tôi đề nghị bạn để nó cho những người làm. – EJP

+0

Là 'Bên ngoài $ bên trong (Bên ngoài, Bên ngoài $ bên trong) 'thực sự chính xác? Hàm khởi tạo nhận một cá thể của cùng một lớp làm đối số? Tại sao trình biên dịch lại thêm tham số như vậy. –

Trả lời

13

Nếu bạn viết đoạn code như thế nào,

public class Outer { 
     private class Inner {} 
} 

Bạn sẽ lưu ý rằng chỉ có một constructor private Outer$Inner(Outer)

constructor này là yêu cầu của Mục 8.8.9 of the JLS, mà nói rằng nếu không có constructor được định nghĩa một mặc định hàm tạo phải được tạo và trong trường hợp này hàm tạo mặc định phải là riêng tư,

Trong loại lớp, nếu lớp là tuyên bố công khai, khi đó hàm khởi tạo mặc định được ngầm định cho công cụ sửa đổi truy cập công khai (§6.6); nếu lớp được tuyên bố là được bảo vệ, thì hàm khởi tạo mặc định là ngầm định cho phép trình sửa đổi truy cập được bảo vệ (§6.6); nếu lớp là được khai báo riêng, thì hàm khởi tạo mặc định ngầm được cấp riêng cho biến tố truy cập riêng (§6.6); nếu không, hàm tạo mặc định có quyền truy cập mặc định được ngụ ý bởi không có công cụ sửa đổi truy cập.

Tuy nhiên, khi bạn bạn nhanh chóng một thể hiện của Inner bên ngoài với các mã như,

public class Outer { 
    private class Inner {} 
     public String foo() { 
      return new Inner().toString(); 
     } 
} 

Trình biên dịch có để tạo ra một constructor mà Outer có thể gọi một cách hợp pháp (bạn không thể gọi một cách hợp pháp các tin constructor mặc định vì nó là private). Vì vậy, một nhà xây dựng tổng hợp mới phải được tạo ra bởi trình biên dịch.Các nhà xây dựng mới phải được tổng hợp, theo section 13.1 of the JLS

Bất kỳ cấu trúc được giới thiệu bởi các biên dịch mà không có một tương ứng xây dựng trong các mã nguồn phải được đánh dấu là tổng hợp, trừ trường hợp nhà xây dựng mặc định và lớp khởi phương pháp.

Hàm tạo thứ hai này không có cấu trúc tương ứng trong mã nguồn, do đó hàm tạo mới này phải là tổng hợp. Phương thức khởi tạo riêng đầu tiên vẫn phải được tạo ra, vì JLS yêu cầu một hàm tạo mặc định riêng.

+0

Tại sao lại bất hợp pháp để khởi tạo một thể hiện mới của Inner? Bên ngoài vẫn có thể làm điều đó, phải không? Ngoài ra, vì hàm tạo riêng này được tạo bởi trình biên dịch, tại sao nó không phải là một hàm tạo tổng hợp? – shrini1000

+0

Trả lời câu trả lời của tôi. – sbridges

+0

Điều này hiện đã rõ. Cám ơn! – shrini1000

2

Câu trả lời có khả năng nhất là tôn trọng những gì bạn đã khai báo trong mã nguồn của mình. Làm điều này vẫn cho phép sử dụng hàm tạo riêng bằng cách phản chiếu như bạn đã khai báo nó.

Điều này cũng tránh kiểm tra xem hàm tạo riêng tư có thực sự được gọi trong lớp Inner hay không.

3

Đây không phải là câu trả lời, mà tôi cho rằng đã được bao phủ bởi sbridges. Nó chỉ đơn giản là một ví dụ làm việc để tạo ra hành vi mà bạn mô tả:

public class Outer { 
    private class Inner { 
    } 

    public static void main(String[] args) { 
     printConstructors(); 

     //only one constructor is printed but two would appear if you 
     //uncommented the line below 

     //new Outer().new Inner(); 
    } 

    private static void printConstructors() { 
     Constructor[] constructors = Outer.Inner.class.getDeclaredConstructors(); 
     for (Constructor c : constructors) { 
      System.out.println(c.toGenericString()); 
     } 
    } 
} 
Các vấn đề liên quan