2015-09-08 36 views
10

Đoạn mã dưới đây là một ví dụ nhỏ dễ dàng tái tạo vấn đề. Vì vậy, tôi có biến loại String, trên đó một giá trị mặc định được thiết lập. Tôi có 3 phương pháp:Java Introspection - hành vi kỳ lạ

  • getter
  • setter
  • phương pháp thuận tiện có thể chuyển đổi chuỗi để boolean

Các mẫn không trả lại getter như readMethod và setter như writeMethod. Thay vào đó nó trả về phương thức isTest() làm readMethod. Setter rỗng.

Từ tài liệu, tôi hiểu rằng nếu loại đó là boolean, phương thức "is" có ưu tiên cao hơn so với get, nhưng kiểu là String, do đó không có ý nghĩa gì khi tìm kiếm "is-xxx " phương pháp?

public class Test { 
    public class Arguments { 
     private String test = Boolean.toString(true); 

     public boolean isTest() { 
      return Boolean.parseBoolean(test); 
     } 

     public String getTest() { 
      return test; 
     } 

     public void setTest(String test) { 
      this.test = test; 
     } 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) throws IntrospectionException { 
     BeanInfo info = Introspector.getBeanInfo(Arguments.class); 
     System.out.println("Getter: " + info.getPropertyDescriptors()[1].getReadMethod()); 
     System.out.println("Setter: " + info.getPropertyDescriptors()[1].getWriteMethod()); 
     PropertyDescriptor descr = new PropertyDescriptor("test", Arguments.class); 
     System.out.println("T"); 
    } 

} 

Có ai có hiểu biết về điều này không?

thông tin bổ sung:

  1. Trình tự không thay đổi kết quả. Phương thức isTest() luôn được xem là readMethod
  2. Trong trường hợp tôi chỉ cần đổi tên hàm isTest() thành bsTest(), nó chọn getter và setter là readMethod và writeMethod. Vì vậy, nó có cái gì để làm với "is-xxx".
+0

Điều gì sẽ xảy ra nếu bạn khai báo phương thức 'isTest' ở cuối lớp? Nó có thể là nó được công nhận là boolean bởi vì đó là lần xuất hiện đầu tiên, và do đó setter không khớp với kiểu String. –

+0

Không, nó không có ý nghĩa, nhưng rõ ràng đó là những gì họ quyết định (hoặc đó là một lỗi). Bạn không thể làm gì nhiều về điều này, ngoại trừ việc dừng để biểu diễn các boolean bằng các chuỗi: D – Dici

+0

Tôi đã thêm một số thông tin khác trong văn bản ban đầu. Thứ tự không có ảnh hưởng đến kết quả. – Quirexx

Trả lời

4

Kết quả bạn nhận được thực sự là kết quả mong đợi, theo số JavaBeans specification.

Trích dẫn đoạn 8.3.1 cho thuộc tính đơn giản:

Nếu chúng tôi phát hiện ra một cặp kết hợp của get<PropertyName>set<PropertyName> phương pháp rằng mất và trở về cùng loại, sau đó chúng tôi coi những phương pháp như xác định một đọc-ghi thuộc tính có tên là <propertyName>.

Sau đó, trích dẫn đoạn 8.3.2 cho thuộc tính boolean:

phương pháp is<PropertyName> này có thể được cung cấp thay vì một phương pháp get<PropertyName>, hoặc nó có thể được cung cấp thêm vào một phương pháp get<PropertyName>.

Trong cả hai trường hợp, nếu phương pháp is<PropertyName> có mặt cho thuộc tính boolean thì chúng tôi sẽ sử dụng phương thức is<PropertyName> để đọc giá trị thuộc tính.

Từ ví dụ của bạn, Introspector đang phát hiện cả hai phương pháp isTestgetTest. Vì isTest có mức độ ưu tiên hơn getTest, nó sử dụng isTest để xác định loại thuộc tính testboolean. Nhưng sau đó, Introspector hy vọng setter có chữ ký void setTest(boolean test) và nó không tìm thấy nó, do đó, phương thức setter là null.

Điều quan trọng cần lưu ý là Introspector không đọc các trường. Nó sử dụng chữ ký của các phương thức getter/setter để xác định các trường nào có mặt và các kiểu tương ứng của chúng. isTest chữ ký phương thức chỉ định cho thuộc tính có tên test loại boolean, vì vậy, bất kể loại thực tế là test, Introspector sẽ xem xét rằng lớp của bạn có thuộc tính boolean test.

Trong thực tế, đối với tất cả các Introspecter là có liên quan, tài sản test thậm chí có thể không tồn tại! Bạn có thể thuyết phục chính mình về điều đó bằng mã sau:

class Test { 

    public class Arguments { 
     public boolean isTest() { 
      return true; 
     } 
    } 

    public static void main(String[] args) throws IntrospectionException { 
     BeanInfo info = Introspector.getBeanInfo(Arguments.class); 
     System.out.println("Getter: " + info.getPropertyDescriptors()[1].getReadMethod()); 
     System.out.println("Name of property: " + info.getPropertyDescriptors()[1].getName()); 
    } 

} 
+0

Tôi đồng ý với Tunaki, và nếu bạn đang làm một số lập trình meta, bạn có thể buộc nó hoạt động như bạn muốn với một số tham số: 'PropertyDescriptor descr = new PropertyDescriptor (" test ", Arguments.class," getTest "," setTest ") ; ' –

+0

Bạn đề cập đến" nó sử dụng isTest để xác định loại thuộc tính thử nghiệm là boolean ", nhưng loại thử nghiệm được xác định rõ ràng là Chuỗi. Hay là nó định nghĩa kiểu Boolean vì giá trị trả về của phương thức là Boolean? – Quirexx

+0

@Quirexx Introspector không đọc các trường. Nó sử dụng chữ ký của phương thức getter/setter để xác định các trường nào có mặt và các kiểu tương ứng của chúng. Chữ ký 'isTest' chỉ định cho một thuộc tính có tên" test "của kiểu boolean, bất kể loại thực thi" test " – Tunaki

2

Thành viên thực sự hoàn toàn không liên quan đến Introspector. Ví dụ, bạn có thể có phương thức getName() chỉ trả lại số String và Introspector cố định sẽ tìm thấy nó làm trình lấy cho một thành viên có tên "tên". Bạn thậm chí có thể có một setter nếu thành viên không tồn tại. Bạn thậm chí có thể cung cấp Giao diện cho Introspector và nó sẽ xác định các thuộc tính từ đó, ngay cả khi không thể có bất kỳ thành viên thực sự nào.

Nói cách khác, các thuộc tính được xác định bởi sự tồn tại của các phương thức getter và setter chứ không phải bằng cách thực sự tìm kiếm các biến.