(一)什麼是反射?
在詳細瞭解反射機制之前,我們先來了解一下java代碼在計算機中的運行過程:
比如當我們編寫好一個類:Student.java,裏面包含學生的姓名和年齡,構造方法,其他方法。
javac會把我們寫的代碼編譯成.class字節碼文件,保存在硬盤中,這個文件中保存着該類的類名,成員名,構造方法等等。
Class階段會把字節碼文件中的信息轉化成class類對象,比如成員變量用Field[]保存,構造方法用Constructor[]保存,成員方法用Method[]保存
通過new Student(),根據第二個階段的類對象創建出Student對象
這裏的第二個階段,將類的各個組成部分封裝爲其他對象就是反射機制。
(二)獲取字節碼Class對象的三種方式
class.forname("全類名");
類名.class;
對象.getclass();
同一個字節碼文件(.class)在一次程序運行過程中只會被加載一次,通過以上三種方法創建的class對象是同一個。
public class Student {
private String name;
private int age;
//方便後期測試的成員變量
public int a;
public Student(){}
public Student(String name, int age,int a) {
this.name = name;
this.age = age;
this.a=a;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", a=" + a +
'}';
}
}
public class reflectTest {
public static void main(String[] args) throws ClassNotFoundException {
//方法一
Class cls1 = Class.forName("com.sdxb.reflect.Student");
System.out.println(cls1);
//方法二
Class cls2 = Student.class;
System.out.println(cls2);
//方法三
Student student=new Student();
Class cls3 = student.getClass();
System.out.println(cls3);
//判斷是否是同一對象
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);
}
}
(三)Class獲取對象方法
1.1 獲取成員變量
Field getField(String name) //獲取指定名稱public修飾的成員變量
Field[] getFields() //獲取所有public修飾的成員變量
Field getDeclaredField(String name) //獲取指定名稱成員變量
Field[] getDeclaredFields() //獲取所有成員變量
1.2 操作成員變量
Object get(Object obj) //通過Field獲取對象
void set(Object obj, Object value) //修改Field的值
public class FieldTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class cls = Class.forName("com.sdxb.reflect.Student");
//1.獲取所有public的成員變量
Field[] fields = cls.getFields();
for (Field field:fields) {
System.out.println(field);
}
//2.獲取指定名字的public成員變量
Field a = cls.getField("a");
Student student=new Student();
//3.操作Field的方法,get和set
System.out.println(a.get(student));
a.set(student,10);
System.out.println(student);
//4.獲取所有成員變量
Field[] declaredFields = cls.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f);
}
}
}
這裏的兩個操作Field的方法只能操作public修飾的變量,如果需要訪問其他修飾符修飾的元素,則要添加安全許可:
a.setAccessible(true);
2.1 獲取構造方法
Constructor<T> getConstructor(Class<?>... parameterTypes) //根據參數不同獲取指定的public構造方法
Constructor<?>[] getConstructors() //獲取所有public構造方法
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) //根據參數不同獲取指定的構造方法
Constructor<?>[] getDeclaredConstructors() //獲取所有構造方法
2.2 操作構造方法
T newInstance(Object... initargs) //創建對象
public class reflectTest2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class cls = Class.forName("com.sdxb.reflect.Student");
//有參構造方法
Constructor constructor = cls.getConstructor(String.class, int.class, int.class);
Object student = constructor.newInstance("sdxb", 24, 1);
System.out.println(student);
//無參構造方法
Constructor constructor2 = cls.getConstructor();
Object student2 = constructor2.newInstance();
System.out.println(student2);
//無參構造方法可以用下面的方式代替
cls.newInstance();
}
}
Method getMethod(String name, Class<?>... parameterTypes) //根據名稱和參數類型獲取public方法
Method[] getMethods() //獲取所有public方法
Method getDeclaredMethod(String name, Class<?>... parameterTypes) //根據名稱和參數類型獲取方法
Method[] getDeclaredMethods() //獲取所有方法
3.2 成員方法的操作
Object invoke(Object obj, Object... args) //執行成員方法
public void run(){
System.out.println("run");
}
public void run(int speed){
System.out.println("run"+speed);
}
public class reflectTest3 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class cls = Student.class;
Student student=new Student();
//無參方法
Method run = cls.getMethod("run");
run.invoke(student);
//帶參數方法
Method run2=cls.getMethod("run", int.class);
run.invoke(student,1);
}
}
(四)總結
java的反射機制在框架中應用十分廣泛,被譽爲是框架的靈魂。原因是框架是一個半成品,我們無法通過new去創建框架中定義的類,因此反射起到了很大的作用。