目? 錄
一、反射 Class 的 Method
1.反編譯?String 類的方法簽名
2.通過反射調用方法
3.反編譯 String 類的構造方法簽名
4.通過反射調用構造方法
?二、類加載過程
1.裝載(Loading)
(1)說明
(2)雙親委派機制
2.鏈接(Linking)?
(1)驗證(Verify)
(2)準備(Prepare)?
(3)解析(Resolve)
3.初始化(initialization)?
三、類加載器獲取 Class
1.說明
2.與 Class.forName() 比較
?四、反射的泛型
1.父類的泛型
2.接口的泛型?
3.屬性的泛型
4.方法參數的泛型
5.方法返回值的泛型
6.構造方法參數的泛型
一、反射 Class 的 Method
1.反編譯?String 類的方法簽名
public class MethodTest {public static void main(String[] args) throws ClassNotFoundException {// 獲取類信息Class<?> aClass = Class.forName("java.lang.String");// 獲取類修飾符String classMod = Modifier.toString(aClass.getModifiers());// 獲取簡單類名String className = aClass.getSimpleName();// 獲取簡單父類名String classSupName = aClass.getSuperclass().getSimpleName();// 獲取父類接口Class<?>[] classInterfaces = aClass.getInterfaces();// 獲取所有方法Method[] declaredMethods = aClass.getDeclaredMethods();// 字符串拼接StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(classMod);stringBuilder.append(" class ");stringBuilder.append(className);stringBuilder.append(" extends ");stringBuilder.append(classSupName);if (classInterfaces.length > 0) {stringBuilder.append(" implements ");for (int i = 0; i < classInterfaces.length; i++) {stringBuilder.append(classInterfaces[i].getSimpleName());if (i != classInterfaces.length - 1) {stringBuilder.append(", ");}}}stringBuilder.append(" {\n");for (Method declaredMethod : declaredMethods) {stringBuilder.append("\t");// 獲取方法修飾符String methodMod = Modifier.toString(declaredMethod.getModifiers());stringBuilder.append(methodMod);stringBuilder.append(" ");// 獲取方法返回值類型Class<?> returnType = declaredMethod.getReturnType();stringBuilder.append(returnType.getSimpleName());stringBuilder.append(" ");// 獲取方法名String methodName = declaredMethod.getName();stringBuilder.append(methodName);// 獲取方法參數類型stringBuilder.append(" (");Parameter[] parameters = declaredMethod.getParameters();for (int i = 0; i < parameters.length; i++) {Parameter parameter = parameters[i];// 獲取參數類型Class<?> parType = parameter.getType();stringBuilder.append(parType.getSimpleName());// 獲取參數名String parName = parameter.getName();stringBuilder.append(" ");stringBuilder.append(parName);// 添加逗號分隔符,最后一個參數不加逗號if (i < parameters.length - 1) {stringBuilder.append(", ");}}stringBuilder.append(") {}\n");}stringBuilder.append("}");System.out.println(stringBuilder);}
}
2.通過反射調用方法
- ?四要素:對象、方法、參數、值。缺一不可;
- 若方法不是 public 的,運行會報【java.lang.IllegalAccessException】異常,需要通過 setAccessible(true) 打破封裝;
public class Person {public String name;private int age;protected String sex;public static String country;public static final String job = "程序員";public Person() {}public Person(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public static String getCountry() {return country;}public static void setCountry(String country) {Person.country = country;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}private void test(String s) {System.out.println("test(" + s + ")方法執行完畢!");}
}
public class UseMethod {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {Person person = new Person();Class<? extends Person> aClass = person.getClass();// 獲取方法Method test = aClass.getDeclaredMethod("test", String.class);// 設置方法可訪問test.setAccessible(true);// 調用方法Object o = test.invoke(person, "參數列表");}
}
3.反編譯 String 類的構造方法簽名
public class MethodTest2 {public static void main(String[] args) throws ClassNotFoundException {// 獲取類Class<?> aClass = Class.forName("java.lang.String");// 獲取類修飾符String classMod = Modifier.toString(aClass.getModifiers());// 獲取簡單類名String className = aClass.getSimpleName();// 獲取簡單父類名String classSupName = aClass.getSuperclass().getSimpleName();// 獲取父類接口Class<?>[] classInterfaces = aClass.getInterfaces();// 獲取構造方法Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();// 拼接字符串StringBuilder stringBuilder = new StringBuilder();stringBuilder.append(classMod);stringBuilder.append(" class ");stringBuilder.append(className);stringBuilder.append(" extends ");stringBuilder.append(classSupName);if (classInterfaces.length > 0) {stringBuilder.append(" implements ");for (int i = 0; i < classInterfaces.length; i++) {stringBuilder.append(classInterfaces[i].getSimpleName());if (i != classInterfaces.length - 1) {stringBuilder.append(", ");}}}stringBuilder.append(" {\n");for (Constructor<?> declaredConstructor : declaredConstructors) {// 獲取構造方法修飾符String constructorMod = Modifier.toString(declaredConstructor.getModifiers());stringBuilder.append("\t");stringBuilder.append(constructorMod);// 獲取構造方法名String constructorName = declaredConstructor.getName().replaceAll("java.lang.", "");stringBuilder.append(" ");stringBuilder.append(constructorName);// 獲取構造方法參數Parameter[] parameters = declaredConstructor.getParameters();stringBuilder.append(" (");if (parameters.length > 0) {for (int i = 0; i < parameters.length; i++) {// 獲取參數類型String paraType = parameters[i].getType().getSimpleName();stringBuilder.append(paraType);// 獲取參數名String paraName = parameters[i].getName();stringBuilder.append(" ");stringBuilder.append(paraName);if (i != parameters.length - 1) {stringBuilder.append(", ");}}}stringBuilder.append(") {}\n");}stringBuilder.append("}");System.out.println(stringBuilder);}
}
4.通過反射調用構造方法
public class Person {public String name;private int age;protected String sex;public static String country;public static final String job = "程序員";public Person() {}public Person(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public static String getCountry() {return country;}public static void setCountry(String country) {Person.country = country;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}
}
public class UseConstructor {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Person person = new Person();// 獲取Class對象Class<? extends Person> aClass = person.getClass();// 獲取無參構造方法Constructor<? extends Person> c1 = aClass.getDeclaredConstructor();System.out.println(c1);Person p1 = c1.newInstance();System.out.println(p1);// 獲取有參構造方法Constructor<? extends Person> c2 = aClass.getDeclaredConstructor(String.class, int.class, String.class);System.out.println(c2);Person p2 = c2.newInstance("孔明", 18, "男");System.out.println(p2);}
}
?二、類加載過程
1.裝載(Loading)
(1)說明
- 類加載器負責將類的 class 文件讀入內存;
- 低版本 JDK 類加載器:
- 引導 / 啟動 類加載器:負責加載 rt.jar,即核心類庫;
- 擴展 類加載器:負責加載 ext/*.jar ;
- 系統 類加載器:負責加載 classpath 中的 class 文件。
- jdk 9 之后的 JDK 類加載器:
- BootstrapClassLoader(引導 / 啟動 類加載器);
- PlatformClassLoader(平臺類加載器);
- AppClassLoader(應用類加載器)。
- 高版本 JDK 中引入模塊化;
- 可以自定義類加載器,只要符合規范即可;
- 可以通過 getParent() 方法獲取 當前 類加載器 的 父 類加載器。
public class ClassLoaderTest {public static void main(String[] args) {// 獲取應用類加載器ClassLoader cl1 = Person.class.getClassLoader();System.out.println(cl1);ClassLoader cl2 = ClassLoader.getSystemClassLoader();System.out.println(cl2);ClassLoader cl3 = Thread.currentThread().getContextClassLoader();System.out.println(cl3);// 獲取平臺類加載器ClassLoader cl1Parent = cl1.getParent();System.out.println(cl1Parent);ClassLoader cl2Parent = cl2.getParent();System.out.println(cl2Parent);ClassLoader cl3Parent = cl3.getParent();System.out.println(cl3Parent);// 獲取啟動類加載器,啟動類加載器負責加載核心類庫,名稱讀不到,直接輸出 nullClassLoader cl1GrandParent = cl1Parent.getParent();System.out.println(cl1GrandParent);ClassLoader cl2GrandParent = cl2Parent.getParent();System.out.println(cl2GrandParent);ClassLoader cl3GrandParent = cl3Parent.getParent();System.out.println(cl3GrandParent);}
}
(2)雙親委派機制
- 某個類加載器接收到加載類的任務時,通常委托給【父 類加載器】完成加載;
- 頂級【父 類加載器】無法加載時,逐層向下委派加載任務;
- 這樣做的原因是,可以保證程序的安全,也可以防止類加載重復。
2.鏈接(Linking)?
(1)驗證(Verify)
? ? ? ? 確保類加載信息符合 JVM 規范。
(2)準備(Prepare)?
- 正式為靜態變量在方法區開辟存儲空間并賦默認值;
- 舉例如下:
- public static int i = 1;? ? ? ? // 實際上,賦默認值 0?
- public static final int i = 1;? ? ? ? // 此時賦值 1
(3)解析(Resolve)
? ? ? ? 將虛擬機常量池中的符號引用替換為直接引用,即替換為地址。?
3.初始化(initialization)?
- 為靜態變量賦值;
- 執行靜態代碼塊。
三、類加載器獲取 Class
1.說明
? ? ? ? 上一節談到,通過類加載器的方式可以獲取 Class 。下面將做出詳細解釋:
public class ReflectLoader {public static void main(String[] args) throws ClassNotFoundException {// 獲取 系統類 / 應用類 加載器,負責加載 classpath 中的 class 文件ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println(systemClassLoader);// 加載 class,只是完成了類加載過程中的裝載與鏈接,還沒有初始化Class<?> aClass = systemClassLoader.loadClass("reflecttest.Person");System.out.println(aClass);// 在這個類第一次被真正使用的時候,才會初始化這個類}
}
public class Person {public String name;private int age;protected String sex;public static String country;public static final String job = "程序員";static {System.out.println("Person類靜態代碼塊執行了");}public Person() {}public Person(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public static String getCountry() {return country;}public static void setCountry(String country) {Person.country = country;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}
}
2.與 Class.forName() 比較
? ? ? ? Class.forName() 會完成類加載的全部過程,如果使用類加載器的方式,可以看出沒有執行靜態代碼塊,也就是沒有執行初始化的過程。而使用 Class.forName() 的方式,可以看到靜態代碼塊執行了。
public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException {Class<?> aClass = Class.forName("reflecttest.Person");System.out.println(aClass);}
}
?四、反射的泛型
1.父類的泛型
public class Animal<A, B, C> {
}
public class Dog extends Animal<String, Integer, Boolean> {
}
public class Test {public static void main(String[] args) {// 反射獲取類Class<Dog> dogClass = Dog.class;// 獲取當前類的父類泛型Type genericSuperclass = dogClass.getGenericSuperclass();// 如果父類使用了泛型if (genericSuperclass instanceof ParameterizedType){// 轉換為參數化類型ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;// 獲取泛型數組Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();// 遍歷泛型數組for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument.getTypeName());}}}
2.接口的泛型?
public interface Animal<T, V, K> {
}
public class Cat implements Animal<String, Integer, Boolean> {
}
public class Test {public static void main(String[] args) {// 反射獲取類Class<Cat> catClass = Cat.class;// 獲取接口的泛型Type[] genericInterfaces = catClass.getGenericInterfaces();for (Type genericInterface : genericInterfaces) {if (genericInterface instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericInterface;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}}
}
3.屬性的泛型
public class Animal {public Map<Integer, Boolean> name;
}
public class Test {public static void main(String[] args) throws NoSuchFieldException {// 反射獲取類Class<Animal> animalClass = Animal.class;// 獲取屬性Field field = animalClass.getField("name");// 獲取屬性泛型Type genericType = field.getGenericType();if (genericType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}
}
4.方法參數的泛型
public class Animal {public void eat(List<String> food) {}
}
public class Test {public static void main(String[] args) throws NoSuchMethodException {// 反射獲取類Class<Animal> animalClass = Animal.class;// 獲取方法Method declaredMethod = animalClass.getDeclaredMethod("eat", List.class);// 獲取方法參數泛型Type[] genericParameterTypes = declaredMethod.getGenericParameterTypes();for (Type genericParameterType : genericParameterTypes) {if (genericParameterType instanceof ParameterizedType){ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}}
}
5.方法返回值的泛型
public class Animal {public Map<String, Integer> eat(List<String> food) {return null;}
}
public class Test {public static void main(String[] args) throws NoSuchMethodException {// 反射獲取類Class<Animal> animalClass = Animal.class;// 獲取方法Method declaredMethod = animalClass.getDeclaredMethod("eat", List.class);// 獲取方法返回值的泛型Type genericReturnType = declaredMethod.getGenericReturnType();if (genericReturnType instanceof ParameterizedType){ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}
}
6.構造方法參數的泛型
public class Animal {private Map<String, Boolean> name;public Animal(Map<String, Boolean> name) {this.name = name;}
}
public class Test {public static void main(String[] args) throws NoSuchMethodException {// 反射獲取類Class<Animal> animalClass = Animal.class;// 獲取構造方法Constructor<Animal> animal = animalClass.getDeclaredConstructor(Map.class);// 獲取構造方法參數泛型Type[] genericParameterTypes = animal.getGenericParameterTypes();for (Type genericParameterType : genericParameterTypes) {if (genericParameterType instanceof ParameterizedType) {ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}}
}