目录
一、什么是反射
反射允许对成员变量,成员方法和构造方法的信息进行编程访问。
idea里面的变量,成员方法的提示,都是靠反射获取的,类的信息都被扒的干干净净
要使用反射就必须获取类的Class文件,从类的Class对象上获取类的所有信息。
下面就会讲如何获取Class对象
二、获取class对象的3种方法
3种方法对应着代码的3个不同的阶段
下面是一个测试类Student
class Student{ private String name; public int age; public Student() { } public Student(String name) { this.name = name; } protected Student(int age) { this.age = age; } private Student(String name, int age) { 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; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
下面代码,通过3种方式获得Student类的字节码文件对象,以及比较
public class test1 { public static void main(String[] args) throws ClassNotFoundException { //获取Class对象的三种方式比较 //1.通过Class.forName("全类名") Class<?> clazz = Class.forName("reflect.test.Student"); System.out.println(clazz); //2.通过类名.class Class<?> clazz1 = Student.class; System.out.println(clazz1); //3.通过对象的getClass() Student student = new Student(); Class<? extends Student> clazz2 = student.getClass(); System.out.println(clazz2); //因为类的字节码文件只有一个即Class字节码文件 //所以都为true System.out.println(clazz == clazz1); System.out.println(clazz == clazz2); System.out.println(clazz1 == clazz2); } }
第一种方式是最为常用的,第二种方式一般作为参数传递使用,第三种只有在有对象的情况下使用
获得class对象后,就可以通过class对象获取类的构造方法,成员变量,成员方法了。
在反射里面,构造方法,成员变量,成员方法通通视为类
于是我们可以通过class对象的成员方法获取类信息对象——构造方法类Constructor、成员变量类Field、成员方法类Method。
获得类的构造方法,成员变量和成员方法后可以获得三者的信息
三、反射获取构造方法
1.通过class对象的成员方法获得类的构造方法,实际上返回的是类对应的Constructor类。
2.获得的构造方法类的对象可以使用其成员方法创建类的对象。
下面是class对象获取构造方法类的对象的成员方法
和构造方法类对象创建类的对象的成员方法
//获取Student类的所有构造方法 Constructor<?>[] constructors = clazz.getDeclaredConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor); } //获取Student类的指定构造方法 Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class); //因为两个参数的构造方法私有,所以需要使用暴力反射 //才能使用这个构造方法创建对象 constructor.setAccessible(true); Student student1 = (Student) constructor.newInstance("张三", 18); System.out.println(student1);//Student{name='张三', age=18} //获取构造器后 //可以获取构造器的信息 //比如修饰词、参数列表、返回值类型 //获取构造器的修饰词 System.out.println(constructor.getModifiers());//2代表private //获取构造器的参数列表 System.out.println(constructor.getParameterTypes()); //获取构造器的返回值类型 System.out.println(constructor.getName());
暴力反射:获得的构造器是私有的private修饰,不能直接使用,必须constructor.setAccessible(true);暴力反射后,临时取消权限校验,就可以使用反射获得的构造方法了。
四、反射获取成员变量
还能获取成员变量的修饰词、类型、名字、变量的值(上面的获取值)
public class test2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
//1.获取类的class对象
Class<?> clazz = Class.forName("reflect.test.Student");
//2.获取成员变量的对象
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
Field name = clazz.getDeclaredField("name");
//name是私有的,要暴力反射
name.setAccessible(true);
Student student = new Student();
//set方法
//第一个参数:对象
//第二个参数:对应成员变量赋值或改变值
name.set(student, "张三");
//get方法
//获取对象的对应成员变量的值
System.out.println(name.get(student));//张三
}
}
五、反射获取成员方法
还能获得成员方法的修饰符、方法的名字、形参、返回值、方法的抛出的异常。
//1. 获取class字节码文件对象 Class clazz = Class.forName("com.itheima.myreflect4.Student"); //2. 获取里面所有的方法对象(包含父类中所有的公共方法) /* Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method); }*/ // 获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法) /*Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); }*/ // 获取指定的单一方法 Method m = clazz.getDeclaredMethod("eat", String.class); System.out.println(m); // 获取方法的修饰符 int modifiers = m.getModifiers(); System.out.println(modifiers); // 获取方法的名字 String name = m.getName(); System.out.println(name); // 获取方法的形参 Parameter[] parameters = m.getParameters(); for (Parameter parameter : parameters) { System.out.println(parameter); } //获取方法的抛出的异常 Class[] exceptionTypes = m.getExceptionTypes(); for (Class exceptionType : exceptionTypes) { System.out.println(exceptionType); } //方法运行 /*Method类中用于创建对象的方法 Object invoke(Object obj, Object... args):运行方法 参数一:用obj对象调用该方法 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写)*/ Student s = new Student(); m.setAccessible(true); //参数一s:表示方法的调用者 //参数二"汉堡包":表示在调用方法的时候传递的实际参数 String result = (String) m.invoke(s, "汉堡包"); System.out.println(result);
六、反射的作用
1.获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
2.结合配置文件,动态的创建对象并调用方法
七、反射的两种使用方式
1.Demo1保存信息
public class Demo1 { public static void main(String[] args) throws IllegalAccessException, IOException { Student s = new Student("小王", 18,"女","1234567"); Teacher t = new Teacher("小李", 35); saveObject(s); } private static void saveObject(Object obj) throws IllegalAccessException, IOException { Class<?> clazz = obj.getClass(); Field[] fields = clazz.getDeclaredFields(); BufferedWriter bw = new BufferedWriter(new FileWriter("files\\a.txt")); for (Field field : fields) { field.setAccessible(true); String name = field.getName(); Object value = field.get(obj); String line = name + ":" + value; bw.write(line); bw.newLine(); } bw.close();//将缓冲区的数据刷新到文件 } }
2.Demo2结合配置文件获取类信息
下面是配置文件的位置和信息:
主要记录类的全名和类的成员方法
准备好的两个类Student和Teacher
public class Student { private String name; private int age; private String gender; private String phone; public Student() { } public Student(String name, int age, String gender, String phone) { this.name = name; this.age = age; this.gender = gender; this.phone = phone; } private void study(){ System.out.println("学生在学习"); } }
public class Teacher { private String name; private int age; public Teacher() { } public Teacher(String name, int age) { this.name = name; this.age = age; } private void teach(){ System.out.println("老师在教课"); } }
通过配置文件读取上面两个类信息
下面是通过配置文件(记录Student类的全类名和方法名)反射读取Student类的信息
public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Properties properties = new Properties(); FileReader fr = new FileReader("prop.properties"); properties.load(fr); String className = properties.getProperty("classname"); String methodName = properties.getProperty("method"); //通过配置文件的类名获取类对象 Class<?> clazz = Class.forName(className); //获取无参构造器创建对象 Constructor<?> constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); Object o = constructor.newInstance(); //获取叫做study的成员方法并调用 Method method = clazz.getDeclaredMethod(methodName); method.setAccessible(true); method.invoke(o); } }
如果要读取Teacher类的信息只要修改配置文件就可以了,修改后的配置文件的内容如下:
标签:基本,反射,java,name,System,获取,Student,println,String From: https://blog.csdn.net/2202_75483664/article/details/141001909