反射的概念
反射允许对成员变量 成员方法 构造方法的信息进行编程访问
获取对应方法的 相关的成员变量 构造方法 和 成员方法(比如idea中的方法字段名提示就是这样实现的)
在JAVA中并不是对原始的JAVA文件进行反射获取而是对对应的字节码文件
即所谓的Class文件
所以第一步是获取对应的Class文件对象
反射的作用大致就是这两类,对信息进去获取 以及获取后的使用
获取Class对象
获取Class对象一共有三种方式 分别对应代码运行的三种
- 在源代码阶段 Class.forname(“全类名”)
- 在加载阶段. 类名.class()
- 在运行阶段. 对象.getClass();
public class reflect_day01 {
public static void main(String[] args) throws ClassNotFoundException {
// 第一种方式
// 最为常用
Class<?> cla = Class.forName("reflectDemo.Student");
System.out.println(cla);
// 第二种方式
// 常用来作为一种参数传递
Class<Student> claz = Student.class;
System.out.println(claz);
// 第三种方式
// 有类 对象的时候使用 使用情况特殊
Student s = new Student();
Class<? extends Student> clas = s.getClass();
System.out.println(claz == cla);
System.out.println(cla == clas);
}
}
结果都是字节文件 最后都是true
获取部分详细
获取构造方法
public class reflect_day02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
// 获取class字节文件
Class clazz = Class.forName("reflectDemo.Student");
// 获取第一种不被保护的全部构造方法
Constructor [] constructors = clazz.getConstructors();
for(Constructor cons: constructors){
System.out.println(cons);
}
System.out.println("***********");
// 获取所有的包括被保护的全部构造方法
Constructor [] constructors1 = clazz.getDeclaredConstructors();
for(Constructor cons: constructors1){
System.out.println(cons);
}
System.out.println("*************");
// 获取某个特定的构造方法 根据传入参数确定
Constructor constructor2 = clazz.getConstructor();
System.out.println(constructor2);
System.out.println("****************");
// 获取某个有参数的构造方法
Constructor constructor3 = clazz.getConstructor(String.class);
System.out.println(constructor3);
System.out.println("*************");
// 获取某个被保护的构造方法 就必须要使用getDeclaredConstructor
Constructor constructor4 = clazz.getDeclaredConstructor(int.class);
System.out.println(constructor4);
System.out.println("****************");
}
}
以上是获取构造方法的方式
接下来是获取后如何的运用
// 获取方法修饰符
int modifier = constructor4.getModifiers();
System.out.println(modifier);
// 获取参数 个数 种类 全部
int paramCount = constructor4.getParameterCount();
System.out.println(paramCount);
Class[] paramTypes = constructor4.getParameterTypes();
for(Class cla : paramTypes){
System.out.println(cla);
}
Parameter[] parameters = constructor4.getParameters();
for(Parameter param : parameters){
System.out.println(param);
}
// 创建对象
constructor4.setAccessible(true);
Student stu = (Student)constructor4.newInstance("Tom",22);
System.out.println(stu);
获取成员变量
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class clazz = Class.forName("reflectDemo.Student");
// 获取 所有未被保护的的成员变量
Field [] fields = clazz.getFields();
for(Field fie : fields){
System.out.println(fie);
}
System.out.println("***********");
// 获取所有所有的成员变量
Field [] fields1 = clazz.getDeclaredFields();
for(Field fie : fields1){
System.out.println(fie);
}
System.out.println("***********");
// 获取单个 指定的字段
Field field2 = clazz.getDeclaredField("age");
System.out.println(field2);
System.out.println("**********");
// 获取指定字段的修饰符
int modifier = field2.getModifiers();
System.out.println(modifier);
// 获取指定字段的数据类型
Class<?> type = field2.getType();
System.out.println(type);
// 获取对象的该指定成员变量 且修改
Student stu = new Student("张三",23,"男");
field2.setAccessible(true);
int age = (int) field2.get(stu);
System.out.println(age);
field2.set(stu, 24);
System.out.println(stu);
}
获取成员方法
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 第一步获取字节变量
Class clazz = Class.forName("reflectDemo.Student");
// 获取全部的 成员方法 会获取包括父类的公共方法
Method [] methods = clazz.getMethods();
for(Method method : methods){
System.out.println(method);
}
System.out.println("**********");
// 获取所有的成员方法 但不包括父类
Method [] methods1 = clazz.getDeclaredMethods();
for(Method method : methods1){
System.out.println(method);
}
System.out.println("*************");
// 获取某个特定的成员方法
Method m = clazz.getDeclaredMethod("eat", String.class);
System.out.println(m);
System.out.println("**************");
// 可以获取特定方法的诸多 属性
String name = m.getName();
System.out.println(name);
Parameter [] parameters = m.getParameters();
for(Parameter parameter : parameters){
System.out.println(parameter);
}
// 将获取的方法执行起来
Student s = new Student();
m.setAccessible(true);
Object re = m.invoke(s, "汉堡包");
System.out.println(re.getClass());
System.out.println(re);
}
三种查找有许多的相似 注意多总结归纳
反射的作用
同等处理不同的类(保存不同类创建的对象值)
public class reflect_day05 {
public static void main(String[] args) throws IOException, IllegalAccessException {
/*
对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
*/
Student s = new Student("小A",23,'女',167.5,"睡觉");
Teacher t = new Teacher("播妞",10000);
save(s);
}
//把对象里面所有的成员变量名和值保存到本地文件中
public static void save(Object obj) throws IOException, IllegalAccessException {
/*
java 默认以当前项目的文件作为 当前文件
../在父目录查找
./在当前文件查找
*/
//1.获取字节码文件的对象
Class clazz = obj.getClass();
//2. 创建IO流
BufferedWriter bw = new BufferedWriter(new FileWriter("/Users/qishimuh/JavaProject/JDBC/JavaEE/src/reflectDemo/myreflect5/a.txt"));
// 获取所有的对象 field
Field [] fields = clazz.getDeclaredFields();
for(Field field : fields){
field.setAccessible(true);
// 字段获取对应的名字 和 值
String name = field.getName();
Object value = field.get(obj);
bw.write(name + " = " + value);
bw.newLine();
}
bw.close();
}
}
练习 :反射可以跟配置文件结合的方式,动态的创建对象,并调用方法
public class reflect_day06 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
/*
反射可以跟配置文件结合的方式,动态的创建对象,并调用方法
*/
// 读取配置文件
Properties properties = new Properties();
FileInputStream fis = new FileInputStream("./prop.properties");
properties.load(fis);
fis.close();
System.out.println(properties);
// 获取全类名
String classname = (String)properties.get("classname");
String methodName = (String)properties.get("method");
// 利用反射创建对象 并执行
Class clazz = Class.forName(classname);
Constructor [] constructors = clazz.getDeclaredConstructors();
// for(Constructor constructor: constructors){
// System.out.println(constructor);
// }
Constructor constructor = clazz.getConstructor();
Object stu = constructor.newInstance();
System.out.println(stu);
Method met = clazz.getDeclaredMethod(methodName);
met.invoke(stu);
}
}