JAVA類的頂層Type抽象和繼承關係

Mr. ChanKong發表於2020-10-07

type的繼承關係

  • Type是java對於型別的高階抽象,是所有型別的父親
Type的子型別用途舉例
引數化型別(ParameterizedType)用來描述泛型,泛型定義只能在class、construct、method上List<T>、Map<K,V>等帶有引數化的物件
泛型陣列(GenericArrayType)描述泛型陣列List<String>[] 、T[]等;注意Integer[],int[] 等不屬於GenericArrayType,而屬於普通型別(Class,isArray()方法返回true)
型別變數(TypeVariable)描述<>裡面內容,描述泛型的具體型別Class<T>中的T
萬用字元變數(WidecardType)描述<>裡面內容,描述泛型的萬用字元Class<?>中的?
原始型別(Class)java物件的class,包括類、美劇、陣列、註解Integer.class、Object.class
基本型別(Class)java的8種基本型別的class基本型別的class,如 int.class

在這裡插入圖片描述

ParameterizedType

介面說明

public interface ParameterizedType extends Type {}

方法用途舉例
Type[] getActualTypeArguments();獲取泛型<T,U>的內容,若無泛型則返回空陣列對於Map<String,Integer>返回的Type[]為String和Integer
Type getRawType();獲取<>前面的類對於Map<String,Integer>返回的Type為Map
Type getOwnerType();獲取<>前面的類(記為A)的擁有者,如果A是頂層類,那麼此方法返回nullif this type is {@code O<T>.I<S>}, return a representation of {@code O<T>}

用法

public class ParameterizedTypeTest {
    public static class GenericType<T,U> {
    }

    public static interface GenericResult<R> {
    }

    public static class Instance<T,U,R> extends GenericType<T,U> implements GenericResult<R> {
    }

    public static void main(String[] args) {
        Instance<String, Double, Integer> instance = new Instance<>();
        // 型別是ParameterizedType:只有一個元素GenericResult<R>
        Type[] types = instance.getClass().getGenericInterfaces();
        // 型別是ParameterizedType:表示GenericType<T, U>
        Type type = instance.getClass().getGenericSuperclass();

        ParameterizedType parameterizedType = (ParameterizedType) type;
        // 型別是TypeVariable:兩個元素T, U
        Type[] actualTypes = parameterizedType.getActualTypeArguments();
        // 型別是class : 不論GenericType是內部類,還是靜態內部類,其父類都是Test.class
        Type ownerType = parameterizedType.getOwnerType();
        // 型別是class : GenericType
        Type rawType = parameterizedType.getRawType();
        // GenericType.toString() : Test$GenericType<T, U>
        String typeName = parameterizedType.getTypeName();
        // 型別是class : class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
        Class<? extends ParameterizedType> clazz = parameterizedType.getClass();
    }
}

GenericArrayType

介面說明

public interface GenericArrayType extends Type {}

方法用途舉例
Type getGenericComponentType();獲取陣列的門面型別List<?>[]得到的是List<?>

用法

@FieldNameConstants
public class GenericArrayTypeTest<T> {
    private List<String>[] stringListArray;
    private List<?>[] noBoundListArray;
    private T[] tArray;
    private int[] intArray;

    public static void main(String[] args) {
        handle(GenericArrayTypeTest.FIELD_STRING_LIST_ARRAY);
        handle(GenericArrayTypeTest.FIELD_NO_BOUND_LIST_ARRAY);
        handle(GenericArrayTypeTest.FIELD_T_ARRAY);
        handle(GenericArrayTypeTest.FIELD_INT_ARRAY);
    }

    @SneakyThrows
    private static void handle(String fieldName) {
        Field field = GenericArrayTypeTest.class.getDeclaredField(fieldName);
        /**
         * <ul>
         *     <li>stringListArray : 型別GenericArrayType : List<String>[]是泛型陣列</li>
         *     <li>noBoundListArray : 型別GenericArrayType : List<?>[]是泛型陣列</li>
         *     <li>tArray : 型別GenericArrayType : T[]是泛型陣列</li>
         *     <li>intArray : 不是泛型陣列, 解析報錯</li>
         * </ul>
         */
        Type genericType = field.getGenericType();
        GenericArrayType genericArrayType = (GenericArrayType) genericType;
        /**
         * <ul>
         *     <li>stringListArray : 型別是ParameterizedType : List<String></li>
         *     <li>noBoundListArray : 型別是ParameterizedType : List<?></li>
         *     <li>tArray : 型別是型別TypeVariable : T</li>
         *     <li>intArray : 不是泛型陣列, 解析報錯</li>
         * </ul>
         */
        Type genericComponentType = genericArrayType.getGenericComponentType();
        System.out.println(genericComponentType);   // java.util.List<java.lang.String>
    }
}

TypeVariable

介面說明

public interface TypeVariable extends Type, AnnotatedElement {}

方法用途舉例
Type[] getBounds();獲取泛型的上界,無顯示定義extends定義上界,則預設上界為Object
D getGenericDeclaration();Java中可以宣告泛型變數的地方有三個class,contructor和method。此方法就是獲取到宣告型別變數的語法元素(指向哪個class,哪個class的哪個構造方法,哪個class的哪個方法)
String getName();獲取名稱,即K,V
AnnotatedType[] getAnnotatedBounds();

用法

// 型別TypeVariable : 返回A,B
        TypeVariable<Class<GenericType>>[] typeVariables = GenericType.class.getTypeParameters();
        // 型別Class : Serializable
        Type[] aBoundType = typeVariables[0].getBounds();
        // 型別Class : Object
        Type[] bBoundType = typeVariables[1].getBounds();

        // 型別String : A
        String aName = typeVariables[0].getTypeName();
        // 型別String : B
        String bName = typeVariables[1].getTypeName();

        // 型別Class : 定義泛型A,B的類TypeVariableTest$GenericType
        typeVariables[0].getGenericDeclaration();
        // 型別Class : 定義泛型A,B的類TypeVariableTest$GenericType
        typeVariables[1].getGenericDeclaration();

WildcardType

介面說明

public interface TypeVariable extends Type, AnnotatedElement {}

方法用途舉例
Type[] getUpperBounds();獲取?的上界,預設上界為Object
Type[] getLowerBounds();獲取?的下界。若無下界則返回空陣列

用法

public static class GenericType {
    public String print(List<? extends String> aList, List<? super Integer> bList) throws Exception {
        return aList.toString();
    }

    @SneakyThrows
    public static void main(String[] args) {
        // 獲取 String print(List<? extends String> aList, List<? super Integer> bList) throws Exception
        Method method = GenericType.class.getDeclaredMethod("print", List.class, List.class);
        // 獲取形參 List<? extends String> aList, List<? super Integer> bList
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        // 獲取泛型萬用字元 ? extends String
        Type aListWildcard = ((ParameterizedType) genericParameterTypes[0]).getActualTypeArguments()[0];
        WildcardType aListWildcardType = (WildcardType) aListWildcard;
        // 列印[class java.lang.String]
        System.out.println(Arrays.toString(aListWildcardType.getUpperBounds()));
        // 列印[]
        System.out.println(Arrays.toString(aListWildcardType.getLowerBounds()));

        // 獲取泛型萬用字元? super Integer
        Type bListWildcard = ((ParameterizedType) genericParameterTypes[1]).getActualTypeArguments()[0];
        WildcardType bListWildcardType = (WildcardType) bListWildcard;
        // 列印[class java.lang.Object]
        System.out.println(Arrays.toString(bListWildcardType.getUpperBounds()));
        // 列印[class java.lang.Integer]
        System.out.println(Arrays.toString(bListWildcardType.getLowerBounds()));
    }
}

Class

在這裡插入圖片描述

方法說明

類和物件的關係判斷

  1. instanceof
  • 用法 Object instanceof Class
  • instanceof是Java中的二元運算子,左邊是物件,右邊是類;當物件是右邊類或子類所建立物件時,返回true;否則,返回false
  • 左邊不能是基礎型別
  • null用instanceof跟任何型別比較時都是false
  1. Class.isInstanceof(Object)
  • 與instanceof功能等價
  1. Class.isAssignableFrom(Class)
  • 類和類的關係判斷,如果左側是右側的父類或本類,則返回true
public static class Father { }

    public static class Son extends Father { }

    public static void main(String[] args) {
        Father father = new Father();
        Son son = new Son();

        System.out.println(father instanceof Father);// true
        System.out.println(son instanceof Father);// true
        
        System.out.println(Father.class.isInstance(father));// true
        System.out.println(Father.class.isInstance(son));// true

        System.out.println(Father.class.isAssignableFrom(Father.class));// true
        System.out.println(Father.class.isAssignableFrom(Son.class));// true
        System.out.println(Son.class.isAssignableFrom(Father.class));// false
    }

獲取名稱

  1. getName()
    獲取全路徑類名
public String getName() {
   String name = this.name;
    if (name == null)
        this.name = name = getName0();
    return name;
}
private native String getName0();

如果是基本型別,則返回byte、void等
如果是物件型別,則返回全路徑(包名+類名)
如果是陣列型別,則按照下面的格式返回
在這裡插入圖片描述
2. getTypeName()
和getName()區別在於陣列型別,對陣列型別的展示方法進行優化,轉換符合java語法的形式

public String getTypeName() {
   if (isArray()) {
         try {
             Class<?> cl = this;
             int dimensions = 0;
             while (cl.isArray()) {
                 dimensions++;
                 cl = cl.getComponentType();
             }
             StringBuilder sb = new StringBuilder();
             sb.append(cl.getName());
             for (in t i = 0; i < dimensions; i++) {
                 sb.append("[]");
             }
             return sb.toString();
         } catch (Throwable e) { /*FALLTHRU*/ }
     }
     return getName();
 }
System.out.println((new Object[3]).getClass().getName());//[Ljava.lang.Object;
System.out.println((new Object[3]).getClass().getTypeName());//java.lang.Object[]
System.out.println((new int[3][4][5][6][7][8][9]).getClass().getName());//[[[[[[[I
System.out.println((new int[3][4][5][6][7][8][9]).getClass().getTypeName());//int[][][][][][][]
  1. getCanonicalName()
  • 和getTypeName()區別在於內部類,對於普通內部類,返回符合java語言書寫規範的全路徑。
    對於匿名內部類則返回null
public class ClassTest {
    public static class Father { }

    public static class Son extends Father { }

    public static void main(String[] args) {
        // 普通類
        Father father = new Father();
        System.out.println("----普通類----");
        System.out.println(father.getClass().getName());//ClassTest$Father
        System.out.println(father.getClass().getTypeName());//ClassTest$Father
        System.out.println(father.getClass().getCanonicalName());//ClassTest.Father
        System.out.println(father.getClass().getSimpleName());
    }
}
  1. getSimpleName()
  • 獲取簡單類名,在getCanonicalName()的基礎上,去掉package路徑

對於不同型別,以上方法的返回值

public class ClassTest {
    public static class Father { }

    public static void main(String[] args) {
        // 普通類
        Father father = new Father();
        System.out.println("----普通類----");
        System.out.println(father.getClass().getName());//ClassTest$Father
        System.out.println(father.getClass().getTypeName());//ClassTest$Father
        System.out.println(father.getClass().getCanonicalName());//ClassTest.Father
        System.out.println(father.getClass().getSimpleName());//Father

        // 匿名類
        Father inner = new Father(){};
        System.out.println("----內部類----");
        System.out.println(inner.getClass().getName());//ClassTest$1
        System.out.println(inner.getClass().getTypeName());//ClassTest$1
        System.out.println(inner.getClass().getCanonicalName());//null
        System.out.println(inner.getClass().getSimpleName());//空字串

        // 陣列
        Father[] array = new Father[1];
        System.out.println("----物件陣列類----");
        System.out.println(array.getClass().getName());//[LClassTest$Father;
        System.out.println(array.getClass().getTypeName());//ClassTest$Father[]
        System.out.println(array.getClass().getCanonicalName());//ClassTest.Father[]
        System.out.println(array.getClass().getSimpleName());//Father[]

        // 基本型別陣列
        int[] rawArray = new int[1];
        System.out.println("----基本型別陣列類----");
        System.out.println(rawArray.getClass().getName());//[I
        System.out.println(rawArray.getClass().getTypeName());//int[]
        System.out.println(rawArray.getClass().getCanonicalName());//int[]
        System.out.println(rawArray.getClass().getSimpleName());//int[]
    }
}
  1. class.getDeclaringClass()和field.getDeclaringClass()方法的用途
@FieldNameConstants
public class ClassTest {
    private Father father;

    public ClassTest() {
        this.father = new Father();
    }

    public static class Father {
    }

    @SneakyThrows
    public static void main(String[] args) {
        ClassTest classTest = new ClassTest();
		// class ClassTest
        System.out.println(classTest.father.getClass().getDeclaringClass());

		// class ClassTest
        Field field = ClassTest.class.getDeclaredField(ClassTest.FIELD_FATHER);
        System.out.println(field.getDeclaringClass());
	}
}
  1. 獲取class的註解資訊
    class註解操作(AnnotatedElement)
    Spring註解工具類AnnotatedElementUtils和AnnotationUtils

參考

Spring工具類

相關文章