目? 錄
一、概述
二、獲取 Class?的四種方式
1.Class.forName("完整全限定類名")
2.getClass()
3.class 屬性
4.通過類加載器獲取
三、通過反射機制實例化對象
?1.newInstance()(已過時)
?2.配置文件利用反射機制實例化對象
?四、反射 Class 的 Field
1.獲取 Person 的屬性
2.反編譯 String 類的屬性
3.通過反射為對象屬性賦值
一、概述
- 反射機制是 JDK 中的一套類庫,可以幫助操作或讀取字節碼文件;
- 很多 Java 框架底層都是基于反射機制實現的;
- 部分核心類:
- java.lang.Class:實例代表某個 class 文件 或 某一類型;
- java.lang.reflect.Field:實例代表類中的屬性或字段;
- java.lang.reflect.Constructor:實例代表類中的構造方法;
- java.lang.reflect.Method:實例代表類中的方法。
二、獲取 Class?的四種方式
1.Class.forName("完整全限定類名")
- 全限定類名含有包名,是 lang 包下的,【 java.lang 】也不可省略;
- 參數是字符串類型;
- 若類不存在,則會報 【 java.lang.ClassNotFoundException】異常;
- 此方法的執行,會導致類加載。
public class ReflectTest {static {System.out.println("static block");}public static void main(String[] args) throws ClassNotFoundException {Class<?> aClass1 = Class.forName("reflecttest.ReflectTest");System.out.println(aClass1);Class<?> aClass2 = Class.forName("java.lang.Integer");System.out.println(aClass2);}
}
2.getClass()
- ?該方法通過引用去調用;
- 某類型的字節碼文件在內存中僅存儲一份。
public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException {Class<?> aClass1 = Class.forName("java.lang.String");System.out.println(aClass1);String str = "hello";Class<?> aClass2 = str.getClass();System.out.println(aClass2);System.out.println(aClass1 == aClass2);Class<?> aClass3 = Class.forName("reflecttest.ReflectTest");System.out.println(aClass3);ReflectTest reflectTest = new ReflectTest();Class<? extends ReflectTest> aClass4 = reflectTest.getClass();System.out.println(aClass4);System.out.println(aClass3 == aClass4);}
}
3.class 屬性
? ? ? ? 在 Java 中,任何類型(包括基本數據類型)都有 class 屬性,可以通過這個屬性獲取 Class 實例。
public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException {Class<Integer> intClass = int.class;Class<Integer> integerClass = Integer.class;System.out.println(intClass); // intSystem.out.println(integerClass); // java.lang.Integer}
}
4.通過類加載器獲取
public class ReflectLoader {public static void main(String[] args) throws ClassNotFoundException {ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println(systemClassLoader);Class<?> aClass = systemClassLoader.loadClass("java.lang.String");System.out.println(aClass);}
}
? ? ? ? ?有關類加載器的部分細節,將在下一節進行討論。
三、通過反射機制實例化對象
? ? ? ? 那么,獲取到 Class 有什么用處呢?
? ? ? ? 這就是通過反射機制實例化對象。
?1.newInstance()(已過時)
public class Person {private String name;private int age;public Person() {System.out.println("Person 無參構造方法");}public Person(String name, int age) {System.out.println("Person 有參構造方法");this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {Class<?> personClass = Class.forName("reflecttest.Person");System.out.println(personClass);Person person = (Person) personClass.newInstance();System.out.println(person);}
}
- 以上代碼通過 personClass 實例化 Person 類型對象;
- 原理:調用 Person 的無參構造方法實例化對象;
- 使用此方法實現對象實例化,必須保證該類存在無參構造方法,否則會報【java.lang.InstantiationException】異常;
- 從 jdk 9 開始,該方法被標注已過時。
?2.配置文件利用反射機制實例化對象
# classInfo.properties 文件
className=reflecttest.Person
public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {ResourceBundle resourceBundle = ResourceBundle.getBundle("reflecttest\\classInfo"); // 加載classInfo.properties文件String className = resourceBundle.getString("className"); // 獲取className的值Class<?> aClass = Class.forName(className);Object o = aClass.newInstance();System.out.println(o);}
}
? ? ? ? 那么,在想要靈活實例化其他對象時,無需修改 java 文件,只需要修改配置文件即可。例如:將實例化 Person 對象改為 實例化 Date 對象。
# classInfo.properties 文件
className=java.util.Date
?四、反射 Class 的 Field
1.獲取 Person 的屬性
public class Person {public String name;private int age;protected String sex;public static String country;public static final String job = "程序員";
}
public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {// 反射獲取類信息Class<?> aClass = Class.forName("reflecttest.Person");// 獲取類中的所有被 public 修飾的屬性Field[] fields = aClass.getFields();for (Field field : fields) {System.out.print(field.getName() + " "); // name country job}System.out.println();// 獲取類中的所有屬性Field[] declaredFields = aClass.getDeclaredFields();for (Field declaredField : declaredFields) {// 獲取屬性名System.out.print(declaredField.getName() + " "); // name age sex country job}System.out.println();for (Field declaredField : declaredFields) {// 獲取屬性類型System.out.print(declaredField.getType().getName() + " "); // java.lang.String int java.lang.String java.lang.String java.lang.String}System.out.println();for (Field declaredField : declaredFields) {// 獲取屬性類型簡單名稱System.out.print(declaredField.getType().getSimpleName() + " "); // String int String String String}System.out.println();for (Field declaredField : declaredFields) {// 獲取屬性的修飾符System.out.print(declaredField.getModifiers() + " "); // 1 2 4 9 25}System.out.println();for (Field declaredField : declaredFields) {// 獲取屬性的修飾符名稱System.out.print(Modifier.toString(declaredField.getModifiers()) + " "); // public private protected public static public static final}}
}
2.反編譯 String 類的屬性
public class ReflectTest {public static void main(String[] args) {String str = new String();// 獲取類信息Class<? extends String> aClass = str.getClass();// 獲取類修飾符String classMod = Modifier.toString(aClass.getModifiers());// 獲取簡單類名String className = aClass.getSimpleName();// 獲取簡單父類名String classSupName = aClass.getSuperclass().getSimpleName();// 獲取父類接口Class<?>[] classInterfaces = aClass.getInterfaces();// 獲取所有屬性Field[] declaredFields = aClass.getDeclaredFields();// 字符串拼接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 (Field declaredField : declaredFields) {stringBuilder.append("\t");// 獲取屬性修飾符stringBuilder.append(Modifier.toString(declaredField.getModifiers()));stringBuilder.append(" ");// 獲取屬性類型stringBuilder.append(declaredField.getType().getSimpleName());stringBuilder.append(" ");// 獲取屬性名stringBuilder.append(declaredField.getName());stringBuilder.append(";\n");}stringBuilder.append("}");System.out.println(stringBuilder);}
}
3.通過反射為對象屬性賦值
- 三要素:對象、屬性、值。缺一不可;
- 若屬性不是 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 class FieldTest {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {Person person = new Person();// 獲取Person類Class<? extends Person> aClass = person.getClass();// 獲取屬性Field name = aClass.getDeclaredField("name");Field age = aClass.getDeclaredField("age");Field sex = aClass.getDeclaredField("sex");Field country = aClass.getDeclaredField("country");Field job = aClass.getDeclaredField("job");// 設置屬性可訪問age.setAccessible(true);sex.setAccessible(true);// 設置屬性值name.set(person, "小明");age.set(person, 23);sex.set(person, "男");country.set(person, "中國");// 獲取屬性值System.out.println("姓名:" + name.get(person));System.out.println("年齡:" + age.get(person));System.out.println("性別:" + sex.get(person));System.out.println("國籍:" + country.get(person));System.out.println("職業:" + job.get(person));}
}