2008-12-07 36 views

回答

1

另外,如果你正在編寫一個IDE插件(你試圖做的事情比較常見),那麼IDE通常會爲你提供更有效的方法來訪問當前的類層次結構用戶代碼的狀態。

20

一般來說,這樣做很昂貴。要使用反射,該類必須加載。如果要加載類路徑中的每個類,則需要時間和內存,不建議使用。

如果你想避免這種情況,你需要實現你自己的類文件解析器,它可以更高效地運行,而不是反射。一個字節碼工程庫可能有助於這種方法。

Service Provider mechanism是列舉可插拔服務實現的常規手段。在Java 6中使用ServiceLoader,或者在早期版本中實現您自己的。我在另一個答案中提供了an example

+1

不幸的是,服務提供者機制要求您列出可能位於感興趣列表中的類別,這些類別通常不可行。 – averasko 2015-05-31 15:41:17

+2

編寫實現接口,編譯和部署接口的源代碼是可行的,但不可行的是在實現的FQN中包含文本文件?這種情況很少,如果有的話。幾乎「經常」。 – erickson 2017-03-12 16:45:04

23

埃裏克森說了些什麼,但如果你仍然想這樣做,那麼看看Reflections。從他們的網頁:

使用的反思,您可以查詢您的元數據:

  • 得到一些類型
  • 的所有亞型得到了一些註解
  • 讓所有類型的標註有一些註釋所有類型註釋,包括匹配的註釋參數
  • 獲取用一些註釋的所有方法
+8

更具體:`新的思考(「my.package」)。getSubTypesOf(MyInterface.class)` – zapp 2013-03-16 13:12:35

4

埃裏克森說的是最好的。這裏有一個相關的問題和答案 - http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html

Apache BCEL庫允許您在不加載它們的情況下讀取類。我相信它會更快,因爲您應該可以跳過驗證步驟。使用類加載器加載所有類的另一個問題是您將遭受巨大的內存影響,並且無意中運行您可能不想執行的任何靜態代碼塊。

Apache的BCEL庫鏈接 - http://jakarta.apache.org/bcel/

23

我一直在尋找了一會兒,似乎有不同的方法,這裏是一個總結:

  1. reflections庫,如果很受歡迎你不介意添加依賴項。它應該是這樣的:

    Reflections reflections = new Reflections("firstdeveloper.examples.reflections"); 
    Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class); 
    
  2. 的ServiceLoader(按照埃裏克森的答案),它是這樣的:

    ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class); 
    for (Pet implClass : loader) { 
        System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat 
    } 
    

    注意,對於這個工作,你需要定義Pet作爲ServiceProviderInterface(SPI)並聲明其實現。你這樣做,用的名字examples.reflections.Pet創造resources/META-INF/services一個文件,並在

    examples.reflections.Dog 
    examples.reflections.Cat 
    
  3. 包級別的註解申報Pet所有實現。這裏有一個例子:

    Package[] packages = Package.getPackages(); 
    for (Package p : packages) { 
        MyPackageAnnotation annotation = p.getAnnotation(MyPackageAnnotation.class); 
        if (annotation != null) { 
         Class<?>[] implementations = annotation.implementationsOfPet(); 
         for (Class<?> impl : implementations) { 
          System.out.println(impl.getSimpleName()); 
         } 
        } 
    } 
    

    和註釋定義:

    @Retention(RetentionPolicy.RUNTIME) 
    @Target(ElementType.PACKAGE) 
    public @interface MyPackageAnnotation { 
        Class<?>[] implementationsOfPet() default {}; 
    } 
    

    ,你必須聲明在一個名爲package-info.java該包內文件的包級別註解。這裏有樣本內容:

    @MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class}) 
    package examples.reflections; 
    

    注意,只有那些已知的ClassLoader當時包將通過調用加載到Package.getPackages()

此外,還有基於URLClassLoader的其他方法,將永遠被限制在已經被加載,除非你做一個基於目錄的搜索類。

0

我遇到了同樣的問題。我的解決方案是使用反射來檢查ObjectFactory類中的所有方法,消除那些不是返回一個綁定POJO實例的createXXX()方法的方法。如此發現的每個類都被添加到Class []數組中,然後將其傳遞給JAXBContext實例化調用。這表現良好,只需加載即將需要的ObjectFactory類。我只需要維護ObjectFactory類,一個手工執行的任務(在我的情況下,因爲我開始使用POJO並使用schemagen),或者可以根據需要由xjc生成。無論哪種方式,它都是高性能,簡單和有效的。

4

Spring有一個非常簡單的方法來達致這:

public interface ITask { 
    void doStuff(); 
} 

@Component 
public class MyTask implements ITask { 
    public void doStuff(); 
} 

然後你就可以自動裝配ITask類型和Spring的列表將與所有的實現來填充它:

@Service 
public class TaskService { 

    @Autowired 
    private List<ITask> tasks; 
} 
相關問題