反射有什么用?
能在程序运行期间动态加载一个完全未知的类
显然可以提高java灵活性和增加应用场景
核心
Class c=Class.forName("reflection.User");
这里声明一个类的对象(注意Class中c是大写,class是关键字)
然后获取路径(包名+类名),这样c虽然不是User类,但是就相当于一面镜子
可以通过c获得对象,所以称为“反射”
说明
下面举例说明,这是包的结构,这三个类我们一一构造
首先我们构建一个User类,作为实验
package reflection;
public class User {
private String name="cs";
private String sex;
private int age;
public String address;
public User(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public User(){};
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
注意:
1、需要反射的对象,我们称为JavaBean,他一定要有一个无参构造器(反射通过无参构造器获取对象)
2、我们给name赋了初值cs,address没有任何方法;作为对照
Test.java
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String [] args) throws NoSuchMethodException {
String path="reflection.User";
try {
Class <?>clazz=Class.forName(path);
System.out.println(clazz.getSimpleName());
//Field[] fields=clazz.getFields();//只能获得public修饰的属性
Field[] fields=clazz.getDeclaredFields();//可以获得所有属性
System.out.println(fields.length);
Method[] methods=clazz.getDeclaredMethods();
for(Method method:methods){
System.out.println("方法有"+method);
}
Constructor [] constructors=clazz.getDeclaredConstructors();
Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
System.out.println("获得构造器"+c);
for (Constructor constructor:constructors){
System.out.println("构造器有"+constructor);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
这里会看到很多陌生的方法 field,method,constructor
他们分别对应类中的属性,方法,构造器
也就是说,可以通过这三个方法获取到类
这是打印结果,打印了属性的数量,方法的具体名称,构造器,其中获得构造器表示在getDeclaredConstructor方法中加入构造器名和对应的参数属性(因为会有同名构造器),就可以获得目标构造器,也可以通过这个方法获得目标普通方法
当然了上面的虽然能获取,但是其实没有太多作用,我们需要的是获取具体内容并修改
Test2.java
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//这个注解可以避免代码警告
@SuppressWarnings("all")
public class Test2 {
public static void main(String[] args) {
String path="reflection.User";
User user= null;
//以下方法都是反射API
try {
Class clazz=Class.forName(path);
//通过newInstance(),调用无参构造方法,获取到user的对象.
//因此javabean必须要有无参构造方法
user = (User) clazz.getDeclaredConstructor().newInstance();
//也可以调用其他构造器
//先构造目标构造器,然后通过目标构造器获得相应的类的对象,以及修改属性
Constructor constructor=clazz.getDeclaredConstructor(String.class,String.class,int.class);
user= (User) constructor.newInstance("陈松","男",18);
System.out.println(user.getName());
//调用普通方法
//用method设置需要调用的方法名和类型(避免重载的同名方法混淆),
User u3= (User) clazz.getDeclaredConstructor().newInstance();
Method method=clazz.getDeclaredMethod("setName", String.class);
//然后用invoke激活该方法,参数是对象名和方法参数
method.invoke(u3,"陈松u3");
System.out.println(u3.getName());
//调用并操作属性,使用field获取对应属性,然后跳过检测,在field中设置新数据
User u4=(User)clazz.getDeclaredConstructor().newInstance();
Field field=clazz.getDeclaredField("name");
//我们这里是操作私有属性,所以是用setAccessible方法跳过私有检测
field.setAccessible(true);
field.set(u4,"陈松u4");
System.out.println(u4.getName());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
在代码中我已经写了大量注释,就不再赘述
这是输出