Java 反射
Java 反射概述
- JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
- 而需要解剖一个类,那么我们第一件事肯定是获取到该类的字节码文件对象。
- 获取到该类的字节码文件后,我们使用Class中的方法进行解剖。
Class的原理
- Class 何德何能能够担任解剖的任务呢?那是因为所有的Java类都继承了object这个类,而object这个类中有一个方法:getclass(),它可以获取该类的已经实例化的对象。
获取Class对象
- 首先,我们先创建一个供我们解剖的Student类,如下:
public class Student {
//默认的构造方法
Student(String str){
System.out.println("默认的构造方法 s = " + str);
}
//无参构造方法
public Student(){
System.out.println("调用了公有、无参构造方法执行了。。。");
}
//有一个参数的构造方法
public Student(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造方法
public Student(String name ,int age){
System.out.println("姓名:"+name+"年龄:"+ age);
}
//受保护的构造方法
protected Student(boolean n){
System.out.println("受保护的构造方法 n = " + n);
}
//私有构造方法
private Student(int age){
System.out.println("私有的构造方法 年龄:"+ age);
}
}
- 既然前面说解剖的工具在Class中,那么我们怎么获取Class呢?有以下三种方式:
- Class类的forName方法,此种方式需要包名+该类名,如下:
Class<?> aClass = Class.forName("com.haicoder.reflect.Student");
包名:com.haicoder.reflect,类名:Student。
- 对象的getClass()方法,如下:
Student student = new Student();
Class<? extends Student> aClass1 = student.getClass();
此种方式已经创建对象,所以反射会显得多此一举。
- 使用类名加.class,如下:
Class classes = Student.class;
但是此种方式需要导入类的包,依赖性太强。
- 通过ClassLoader对象的loadClass()方法,如下:
Class<?> aClass2 = ClassLoader.getSystemClassLoader().loadClass("com.haicoder.reflect.Student");
获取类所有构造函数
流程如下:
步骤 | 方法 |
---|---|
加载Class对象 | Class.forName() |
获取类的所有构造方法 | getDeclaredConstructors() |
获取构造方法的所有参数 | getParameterTypes() |
案例如下:
- 先创建一个供测试用的Student类,如下:
public class Student {
//默认的构造方法
Student(String str){
System.out.println("默认的构造方法 名字= " + str);
}
//无参构造方法
public Student(){
System.out.println("公有无参构造函数");
}
//有一个参数的构造方法
public Student(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造方法
public Student(String name ,int age){
System.out.println("姓名:"+name+"年龄:"+ age);
}
//受保护的构造方法
protected Student(boolean n){
System.out.println("受保护的构造方法 n = " + n);
}
//私有构造方法
private Student(int salary){
System.out.println("私有的构造方法 工资:"+ salary );
}
}
- 现在我们要通过反射技术获取上方Student类的所有构造函数,如下:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//1.加载Class对象
Class clazz = Class.forName("com.haicoder.reflect.Student");
//2.获取类的所有构造方法
Constructor [] constructors;
constructors = clazz.getDeclaredConstructors();
for(int i=0;i<constructors.length;i++) {
//3.打印构造方法
System.out.println(constructors[i]);
//4.getParameterTypes可以得到构造方法的所有参数
Class[] parametertypes = constructors[i].getParameterTypes();
//5.打印参数类型名称
for(int j=0;j < parametertypes.length;j++){
System.out.print(parametertypes[j].getName()+" ");
}
System.out.println("");
}
}
运行结果如下:
获取指定参数构造函数
- 那么如果我们只是想获取
public Student(String name ,int age)
这一个构造函数呢?
流程如下:
步骤 | 方法 |
---|---|
加载Class对象 | Class.forName() |
设置参数 | Class[] p = { int.class, String.class |
获取类的指定构造方法 | getDeclaredConstructor§ |
获取构造方法的所有参数 | getParameterTypes() |
案例如下:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 加载Class对象
Class clazz = Class.forName("com.haicoder.reflect.Student");
// 获取类的指定构造方法
Class[] p = { int.class, String.class };
Constructor constructor;
constructor = clazz.getDeclaredConstructor(p);
// getParameterTypes可以得到构造方法的所有参数
Class[] parametertypes = constructor.getParameterTypes();
// 打印参数类型名称
for (int j = 0; j < parametertypes.length; j++) {
System.out.print(parametertypes[j].getName() + " ");
}
System.out.println("");
}
运行结果如下:
调用构造方法
- 上方已经获取到了构造方法,那么我们怎么调用这些构造方法呢?
- 调用公有构造函数。
流程如下:
步骤 | 方法 |
---|---|
调用公有构造方法 | constructor.newInstance(“haicoder”,22) |
案例如下:
public static void main(String[] args) throws Exception {
// 加载Class对象
Class clazz = Class.forName("com.haicoder.reflect.Student");
// 获取类的指定构造方法
Class[] p = {String.class,int.class};
Constructor constructor;
constructor = clazz.getDeclaredConstructor(p);
//使用newInstance方法调用构造函数
constructor.newInstance("haicoder",22);
}
运行结果如下:
- 如果调用的构造函数是私有的呢?
- 调用私有构造函数。
流程如下:
步骤 | 方法 |
---|---|
取消Java语言访问检查 | constructor.setAccessible(true); |
调用私有构造函数 | constructor.newInstance(“haicoder”) |
案例如下:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 加载Class对象
Class clazz = Class.forName("com.haicoder.reflect.Student");
// 获取类的私有构造方法
Class[] p = {int.class};
Constructor constructor;
constructor = clazz.getDeclaredConstructor(p);
//取消Java语言访问检查
constructor.setAccessible(true);
//使用newInstance方法调用构造函数
constructor.newInstance(90);
}
运行结果如下:
调用类中的私有方法
流程如下:
步骤 | 方法 |
---|---|
加载Class对象 | Class.forName |
获取类的默认构造方法 | class.getDeclaredConstructor |
创建实例 | constructor.newInstance |
获取私有方法 | getDeclaredMethod |
取消Java语言访问检查 | method.setAccessible |
调用方法 | method.invoke |
案例如下:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 加载Class对象
Class clazz = Class.forName("com.haicoder.reflect.Student");
// 获取类的默认构造方法
Class[] p = { String.class };
Constructor constructor;
constructor = clazz.getDeclaredConstructor(p);
// 使用newInstance方法调用构造函数,创建实例
Student student=(Student) constructor.newInstance("haicoder");
//获取私有方法
Class[] m = { String.class, int.class };
Method method = clazz.getDeclaredMethod("showScore", m);
//取消Java语言访问检查
method.setAccessible(true);
//输入学生信息
Object info[] = {"嗨客",90};
//调用方法
method.invoke(student,info);
}
运行结果如下:
总结
以上为本人在看其他大牛的反射文章后,根据自己的理解,总结调试出来的结果,本人学识尚浅,如果有错误的地方,请多多指教!