反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
Oracle 官方有着相关解释:
通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。
举个例子:下面定义了两个函数,一个是setName和getname。
student.java
public class Student {
public String name;
public int age;
public void setName(String name){
this.name = name;
System.out.println("your name is "+this.name);
}
public String getname(){
return this.name;
}
public static void main(String[] args) {
Student s = new Student();
s.setName("zyer1");
s.getname();
}
}
首先如上是正常的定义,Student这个对象,因为我们就在这个类中,但如果不在这个类中还要使用这个类呢?也可以import导入。
也正是存在这个反射机制,才会导致有很多的反序列化漏洞的存在--通过构造恶意类,并寻找到可以实例化的地方从而实现调用恶意方法。
那么何为反射呢?
举个例子:还是如上的代码,其中我们知道Student这个类的类名,且我们可以访问到它,java作为面向对象的编程语言,一切皆为对象,于是我们需要先获取Student这个类,使用Class对象的forName方法,但需要throws ClassNotFoundException
Class name = Class.forName("Student");
输出查看一下
发现成功获取到Student类对象了,但是此时我们还不能使用,个人认为,这个就相当于c语言的指针,我们获取到的指针只是地址,但使用还需要&一下,在java中我们也需要相同的操作,将它实例化,使用newInstance方法,同时需要throw InstantiationException, IllegalAccessException
Student stu = (Student) name.newInstance();
这样就新建了Student这个对象,便可以调用其内置方法了,到这应该对反射有了一定的了解了,说直白点就是:我们要去一个饭店吃饭,我们会有很多条路,使用new方法相当于直接去,使用反射相当于走弯路去。
那么下面做一下我对反射学习的总结:
一.通过反射创建类:
- 通过 Class 对象的 newInstance() 方法
- 通过 Constructor 对象的 newInstance() 方法
- 其它方法
1.代码示例(通过 Class 对象的 newInstance() 方法)
Class name = Class.forName("Student");
Student stu = (Student) name.newInstance();
2.代码示例(通过 Constructor 对象的 newInstance() 方法)
Class name1 = Student.class;
Constructor cons = name1.getConstructor();
Student stu1 = (Student) cons.newInstance();
3.其它方法
public class reflection {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> name1 = Runtime.class; //直接获取
System.out.println(name1);
System.out.println("--------");
Runtime rt = Runtime.getRuntime();
Class<?> name3 = rt.getClass(); //使用getClass()方法
System.out.println(name3);
System.out.println("--------");
Class<?> name4 = ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime");//使用 getSystemClassLoader().loadClass() 方法
System.out.println(name4);
}
}
二.获取类方法
import java.lang.reflect.Method;
public class reflection {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class name = Class.forName("java.lang.Runtime"); //获取类对象使用forName方法
Method[] declaredMethods = name.getDeclaredMethods(); //getDeclaredMethods()获取类方法
// for(Method m:declaredMethods){
// System.out.println(m);
// }
System.out.println("----------------------");
Runtime rt = Runtime.getRuntime();
Class<?> name1 = rt.getClass();
Method[] methods = name1.getMethods(); //getMethods()获取类方法
System.out.println("----------------------");
Method method = name1.getMethod("exec", String.class); //getMethod()方法只能返回一个特定的方法,如 Runtime 类中的exec()方法,该方法的第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
System.out.println("----------------------");
Method method1 = name1.getDeclaredMethod("exec", String.class); //与getMethod()方法类似
}
}
————————————————————————————————————————
对于反射的学习是很有必要的,这是java中较为重要的一环,因为现实环境中不可能会让我们直接Runtime.getRuntime().exec()这种直接命令执行,但是总会有一些环节有疏漏,导致将我们的输入实例化并执行,于是就出现了Commons Collections反序列化漏洞。对于我目前的水平,因为是自己在摸索,于是先对反射的学习到这里,能自己手写,可以将其实例化即可,在后续的学习中再慢慢巩固。