前言
泛型相信大家都不陌生,經常都會用到,像在一些集合類啊,一些開源框架啊,這種東西隨處可見,如果不能好好理解的話,看起源碼來也會增加了一點兒複雜度。
泛型的好處,擴展性強,低耦合業務內容,大幅度的減少重複代碼。
本篇文章,基於對泛型有一定了解,想更進一步運用的朋友。
泛型的運用
場景一
當我們寫了一個採用泛型的類,但是怎麼獲取到這個類上的泛型呢,直接 run 一段簡短的代碼看下。
/**
* @author: wangqp
* @create: 2020-11-18 15:02
*/
public class GenericApply<T,U> {
public T apply(T t){
return t;
}
public List<String> getGenericClassName(){
List<String> ret = new ArrayList<>();
Type genericSuperclass = getClass().getGenericSuperclass();
Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
Stream.of(actualTypeArguments).forEach(type -> {
ret.add(((Class)type).getName());
});
return ret;
}
public static void main(String[] args) {
// 匿名的子類實現
GenericApply genericApply = new GenericApply<Integer,Boolean>() {};
System.out.println(genericApply.getGenericClassName());
}
}
1234567891011121314151617181920212223242526
運行結果:
可以看到,GenericApply 這類上有兩個泛型參數,使用上面的方法後,咱們可以得到全面的泛型全類名。
注意:類上加泛型,最好使用在抽象類上或者接口類上。
場景二
泛型在抽象類和接口類上,我們怎麼運用獲取呢,展示下代碼。
這裏劃分了三個類,接口類、抽象類、實現類。
接口類
public interface IGeneric<I> {
void process(I i);
}
123
抽象類
public abstract class AbstractGeneric<T> {
// 當前泛型真實類型的Class
private final Class<T> modelClass;
public AbstractGeneric(){
ParameterizedType parameterizedType = (ParameterizedType)this.getClass().getGenericSuperclass();
modelClass = (Class<T>)parameterizedType.getActualTypeArguments()[0];
}
public Class<T> getGeneric(){
return modelClass;
}
}
1234567891011121314
實現類
public class GenericImpl extends AbstractGeneric<String> implements IGeneric<Boolean>{
@Override
public void process(Boolean param) {
}
public static void main(String[] args) {
GenericImpl generic = new GenericImpl();
System.out.println("抽象類上的泛型全類名 "+generic.getGeneric().getName()+"\n");
Type[] genericInterfaces = generic.getClass().getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
Type[] actualTypeArguments = ((ParameterizedType) genericInterface).getActualTypeArguments();
Stream.of(actualTypeArguments).forEach(type -> {
System.out.println("接口類上的泛型全類名 "+((Class) type).getName());
});
}
}
}
123456789101112131415161718192021
運行結果:
看到運行結果可以打印出抽象類上後者接口上的泛型,這種應該是咱們經常使用的方式。
場景三
還有種更高級的用法,這種用法是和註解一起用的。用於標記泛型。
咱們在上面可以看到泛型參數返回來的是個數組,也就是咱們必須知道這個類的泛型位置,才能找到數組上對應位置的泛型類。
有沒有一種辦法,我不通過數組下標呢。其實是有的,咱們可以通過註解的方式,標定我們的泛型類,不是很複雜,咱們可以一起來看下。直接簡單看下代碼。
註解類
//相當於標註,找到註解爲 value 值的 泛型類
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_PARAMETER,ElementType.TYPE_USE})
public @interface MyAxis {
String value() default "";
}
123456
接口泛型類
//相當於標註,找到註解爲 value 值的 泛型類
public interface IMultiParamInterface<@MyAxis(FIRST) T extends String,@MyAxis(SECONDE) U extends Integer> {
String FIRST="FIRST";
String SECONDE="SECONDE";
void process();
}
1234567
實現類
public class MultiParamsImpl implements IMultiParamInterface<String,Integer>{
@Override
public void process() {
System.out.println("MultiParamsImpl is invoke process");
}
//測試
public static void main(String[] args) {
Class<MultiParamsImpl> multiParamsClass = MultiParamsImpl.class;
//得到這個接口上的 所有泛型
Map<TypeVariable<?>, Type> typeArguments = TypeUtils.getTypeArguments(multiParamsClass, IMultiParamInterface.class);
for (Map.Entry<TypeVariable<?>, Type> typeVariableTypeEntry : typeArguments.entrySet()) {
TypeVariable<?> key = typeVariableTypeEntry.getKey();
MyAxis annotation = AnnotationUtils.getAnnotation(key, MyAxis.class);
Type value = typeVariableTypeEntry.getValue();
System.out.println("名稱爲:"+ annotation.value() +" 泛型類全限定名: "+value.getTypeName());
}
}
}
1234567891011121314151617181920
上面就是接口上有多個泛型,分別被標註爲不同的名字,便於正確獲取到想要的泛型類型。
運行結果:
總結
上面列舉了泛型與抽象列,接口,註解在一起的多種運用和獲取方式。泛型還是很重要的,希望我上面列舉的對朋友們有點兒幫助。另外幫忙多點點讚唄,有什麼疑問,大家可以評論區指出。
作者:vicoqi