2009-12-07 37 views
23

Có cách nào để có danh sách các phương thức có thể truy cập được (không nhất thiết là công khai) bởi một lớp nhất định không? Mã được đề cập sẽ nằm trong một lớp hoàn toàn khác.Lấy danh sách các phương pháp có thể truy cập cho một lớp học đã cho qua sự phản chiếu

Ví dụ:

public class A { 
    public void methodA1(); 
    protected void methodA2(); 
    void methodA3(); 
    private void methodA4(); 
} 

public class B extends A { 
    public void methodB1(); 
    protected void methodB2(); 
    private void methodB3(); 
} 

Đối với lớp B Tôi muốn nhận được:

  • tất cả các phương pháp riêng của mình
  • methodA1methodA2 từ lớp A
  • methodA3 khi và chỉ nếu lớp B có cùng gói với A

methodA4 không bao giờ được đưa vào kết quả vì không thể truy cập được vào lớp B. Để làm rõ một lần nữa, mã cần tìm và trả về các phương thức trên sẽ nằm trong một gói/gói hoàn toàn khác.

Hiện tại, Class.getMethods() chỉ trả về các phương thức công khai và do đó sẽ không làm những gì tôi muốn; Class.getDeclaredMethods() chỉ trả về các phương thức cho lớp hiện tại. Trong khi tôi chắc chắn có thể sử dụng thứ hai và đi bộ phân cấp lớp lên kiểm tra các quy tắc hiển thị bằng tay, tôi không muốn nếu có một giải pháp tốt hơn. Tôi có thiếu thứ gì đó rõ ràng ở đây không?

Trả lời

29

Sử dụng Class.getDeclaredMethods() để nhận danh sách tất cả các phương pháp (riêng tư hoặc khác) từ lớp hoặc giao diện.

Class c = ob.getClass(); 
for (Method method : c.getDeclaredMethods()) { 
    if (method.getAnnotation(PostConstruct.class) != null) { 
    System.out.println(method.getName()); 
    } 
} 

Lưu ý: này không bao gồm các phương pháp di truyền. Sử dụng Class.getMethods() cho điều đó. Nó sẽ trả về tất cả các phương thức công khai công khai (được kế thừa hay không).

Để làm một danh sách toàn diện về mọi thứ mà một lớp có thể truy cập (bao gồm cả các phương pháp kế thừa), bạn sẽ cần phải đi qua cây của các lớp mà nó mở rộng. Vì vậy:

Class c = ob.getClass(); 
for (Class c = ob.getClass(); c != null; c = c.getSuperclass()) { 
    for (Method method : c.getDeclaredMethods()) { 
    if (method.getAnnotation(PostConstruct.class) != null) { 
     System.out.println(c.getName() + "." + method.getName()); 
    } 
    } 
} 
+1

Điều đó vẫn không làm những gì tôi muốn vì nó cũng trả về phương thức riêng tư/gói riêng. Mã của bạn hoàn toàn hợp lý cho việc tìm kiếm các phương thức được chú thích; những gì tôi cần là tìm hiểu tại thời gian chạy tất cả các phương thức mà thể hiện 'B' có thể gọi ra. Như tôi đã nói, tôi có thể viết mã để làm như vậy (tương tự như những gì bạn đăng cộng với một vài ifs ném vào để kiểm tra khả năng truy cập) nhưng tôi đã tự hỏi nếu có một cách tốt hơn. – ChssPly76

+0

Cũng không có chức năng API tiêu chuẩn để làm điều đó vì vậy bạn đang viết nó cho mình. Đó là nó. Bạn đang làm những gì có phần là một yêu cầu bất thường. Thông thường với sự phản ánh bạn chỉ quan tâm đến những gì là ** công khai ** có thể truy cập, do đó getMethods() và đó là lý do tại sao chức năng trợ giúp đó tồn tại. Không có trình trợ giúp (chuẩn) nào tồn tại cho những gì bạn muốn, do đó bạn tự viết nó. – cletus

+0

Tôi biết không có API chuẩn; Tôi đã hy vọng ai đó đã có một vấn đề tương tự và tìm thấy một giải pháp - nhưng tôi đoán là không. Tôi không thấy bất cứ điều gì liên quan đến điều này ở những nơi rõ ràng như đậu/javassist/etc ... hoặc. Mã số đã kết thúc được phần nào tham gia, thực sự - phải đối phó với các phương thức tổng hợp trong các lớp lồng nhau, v.v ... – ChssPly76

2

Chắc chắn bạn sẽ phải đi lên các lớp siêu hạng để có được những gì bạn muốn. Sau khi tất cả, đó là những gì getMethods() đang làm với getDeclaredMethods() gọi nội bộ (loại: nó thực sự gọi một phiên bản riêng để lọc ra các phương thức không công khai nhưng nó đi qua cây lớp để xây dựng danh sách đầy đủ).

Tò mò tại sao một thứ như vậy lại là cần thiết.

5

Vì cletus và PSpeed ​​đã trả lời - bạn cần phải duyệt qua cây thừa kế của các lớp.

Đây là cách tôi làm điều đó, nhưng không xử lý gói phương pháp riêng:

public static Method[] getAccessibleMethods(Class clazz) { 
    List<Method> result = new ArrayList<Method>(); 

    while (clazz != null) { 
     for (Method method : clazz.getDeclaredMethods()) { 
     int modifiers = method.getModifiers(); 
     if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) { 
      result.add(method); 
     } 
     } 
     clazz = clazz.getSuperclass(); 
    } 

    return result.toArray(new Method[result.size()]); 
} 

Tôi đang sử dụng nó trong một trình kiểm tra tương thích ngược mà tôi biết rằng các lớp học mà có thể bị ảnh hưởng sẽ không được ở cùng một gói.

0

Một điểm về câu trả lời của Cletus (Tôi không thể nhận xét vì tôi không có đủ danh tiếng).Dù sao, mã Cletus đã không làm việc cho tôi (Eclipse cũng được phàn nàn về nó), có lẽ do sự thay đổi trong Java kể từ năm 2009.

Dòng:

for (Class c = ob.getClass(); c != null; c = c.getSuperclass()) { 

phải được thay đổi để:

for (Class<?> c = ob.getClass(); c != null; c = c.getSuperclass()) { 

để nhận bất kỳ đầu ra nào. Vì vậy, mã hoàn chỉnh cho tôi là (bao gồm các loại đối số đầu vào, công cụ sửa đổi và kiểu trả về):

for (Class<?> c = scanner.getClass(); c != null; c = c.getSuperclass()) { 
     System.out.println(c.getName());   
     for (Method method : c.getMethods()) { 
      System.out.println("\t" + Modifier.toString(method.getModifiers()) 
      + " " + method.getName()); 
      for (Class<?> param: method.getParameterTypes()) { 
       System.out.println("\t\t" + param.getName()); 
      } 
      System.out.println("\t\t == returns ==> " + method.getReturnType().getName()); 
     } 
    }   
Các vấn đề liên quan