1. 程式人生 > 其它 >idea檢視某個類的所有實現類_如何獲取某個類的所有子類

idea檢視某個類的所有實現類_如何獲取某個類的所有子類

技術標籤:idea檢視某個類的所有實現類

a224530b2982948eb6c35ad80809aebb.png

引言

在我們寫工廠類的時候,可能會根據不同的型別(type)生成不同的物件。但在工廠類初始化的時候,我們需要將某個型別的所有類全部初始化才能達到我們的目的。

舉個例子,我們定義了很多動物(Animal),我們需要一個AnimalFactory根據動物型別(type)去構建不同的動物例項。如下程式碼所示:

我們先構建一個動物基礎型別,包含兩個方法:

- getType:獲取動物型別

- train:訓練動物

public interface IAnimal {/** * 獲取動物種類 * @return */int getType();/** * 訓練動作 */void train();}

然後我們定義了多個動物實現IAnimal介面

public class TDog implements IAnimal {/** * 獲取動物種類 * * @return */@Overridepublic int getType() {return 1;}/** * 訓練動作 */@Overridepublic void train() {System.out.println("握手");}}
public class TLion implements IAnimal{/** * 獲取動物種類 * * @return */@Overridepublic int getType() {return 1;}/** * 訓練動作 */@Overridepublic void train() {System.out.println("鑽火圈");}}

接下來我們定義一個工廠類(TAnimalFactory),用來建立不同的動物

@Servicepublic class TAnimalFactory {private static List> animalLists = Lists.newArrayList();private static Map> animalMaps = Maps.newHashMap();static {animalLists.add(TDog.class);animalLists.add(TLion.class);}@PostConstructpublic void init() throws IllegalAccessException, InstantiationException {for (Class extends IAnimal> clazz : animalLists){IAnimal obj = clazz.newInstance();animalMaps.put(obj.getType(), clazz);}}/** * 構建動物類 * @param type * @return */IAnimal build(int type) throws IllegalAccessException, InstantiationException {return animalMaps.get(type).newInstance();}}

有了工廠類,我們就可以根據動物型別獲取不同的動物例項。

存在的問題

上述工廠類可以解決我們大部分問題,但是當我們新增一種動物型別時(Cat),我們不但要建立一個動物類,還需要再工廠類(AnimalFactory)裡進行註冊

public class TCat implements IAnimal {/** * 獲取動物種類 * * @return */@Overridepublic int getType() {return 3;}/** * 訓練動作 */@Overridepublic void train() {System.out.println("打滾");}}

在工廠類裡註冊這種型別

static { animalLists.add(TDog.class); animalLists.add(TLion.class); //註冊新型別 animalLists.add(TCat.class); }

如果我們忘記註冊了,通過工廠類就無法獲取該動物

解決方案(獲取基礎與IAnimal的所有子類)

我們可以通過Reflections獲取繼承IAnimal的所有子類,這樣我們新增一個動物就無需再進行註冊。

如下程式碼所示:

@Servicepublic class TAnimalFactory {private static List> animalLists = Lists.newArrayList();private static Map> animalMaps = Maps.newHashMap();static { //獲取該路徑下所有類Reflections reflections = new Reflections("com.lanxing.day.daylearning.animal.newT"); //獲取繼承了IAnimal的所有類Set> classSet = reflections.getSubTypesOf(IAnimal.class);animalLists.addAll(classSet);}@PostConstructpublic void init() throws IllegalAccessException, InstantiationException {for (Class extends IAnimal> clazz : animalLists){IAnimal obj = clazz.newInstance();animalMaps.put(obj.getType(), clazz);}}/** * 構建動物類 * @param type * @return */IAnimal build(int type) throws IllegalAccessException, InstantiationException {return animalMaps.get(type).newInstance();}}

我們通過Reflections獲取某個路徑下的所有類,並通過getSubTypesOf方法獲取某個類的所有子類資訊。這樣,後續我們再增加新的動物,只要保證在原先的路徑下,就不需要再手動進行註冊。

缺陷:

- Reflections只能掃描某個包下邊的所有類,所以所有的子類必須放到同一個路徑下

- getSubTypesOf裡的引數必須是所有類都繼承的最近層級子類,因為返回的結果裡包含了所有該類的子類,不一定是最後一個子類。例如我們還定義了一個抽象類繼承IAnimal

public abstract class AbsAnimal implements IAnimal{void beforeTrain(){System.out.println("做準備");}}

那麼通過getSubTypesOf獲取的返回結果裡也包含AbsAnimal類,但其並沒有實現getType介面,所以就會報錯。

總結

Reflections是基於Java反射的一個工具類,其提供了很多有意思的方法,有興趣的同學可以研究下https://static.javadoc.io/org.reflections/reflections/0.9.10/org/reflections/Reflections.html