一、反射的概念
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
二、反射的作用:
1、反编译:.class-->.java
2、通过反射机制访问对象的属性,方法,构造方法等,不仅仅可以是访问公共的还可以访问私有权限修饰符修饰的属性,方法,构造方法;
三、SUN公司为我们提供了反射机制中的类:
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
四、反射的常用方法
通过反射获取构造方法并使用
getConstructor 获取指定的公共构造方法
getConstructors()获取所有的公共构造方法
getDeclaredConstructor 获取指定的构造方法
getDeclaredConstructors获取所有的构造方法
创建对象
newInstance( ) 通过无参构造创建对象
newInstance(“zhangsan", 20); 通过带参构造创建对象
通过反射获取成员变量并使用
getFields,getDeclaredFields获取所有成员
getField,getDeclaredField获取单个成员
set(Object obj,Object value)将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
通过反射获取成员方法并使用
getMethods获取所有方法(不包含private关键字修饰的方法)
getDeclaredMethods获取所有方法(包含private关键字修饰的方法)
getMethod获取单个方法(不包含private关键字修饰的方法)
getDeclaredMethod获取单个方法(包含private关键字修饰的方法)
method.setAccessible(true); 暴力访问,设置私有的方法可以被访问
反射的练习案例:
package UDP;
//Person类
public class Person {
private String name;
int age;
public String address;
public Person() {
}
Person(String name) {
this.name = name;
}
private Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
private void show(){
System.out.println("hello");
}
public String run(String n,int a){
return n+"-------"+a;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address
+ "]";
}
}
//测试类1
package Class;
import java.lang.reflect.Constructor;
public class ClassDemo1 {
public static void main(String[] args) throws Exception {
//获取字节码文件对象
Class c=Class.forName("UDP.Person");
//获取该字节码文件对象的所有构造方法
Constructor[] conts=c.getDeclaredConstructors() ;
for(Constructor cont:conts){
System.out.println(cont);
}
}
}
运行测试类1后的结果是:
由上图一可知,getDeclaredConstructors()方法获取到的是所有的构造方法,包括private关键字修饰的构造方法也能获取到。
//测试类2
package Class;
import java.lang.reflect.Constructor;
public class ClassDemo3 {
public static void main(String[] args) throws Exception {
//创建类的字节码对象
Class c=Class.forName("UDP.Person");
//获取该字节码对象的两个参数的构造方法
Constructor cons=c.getDeclaredConstructor(String.class,int.class);
//暴力访问私有构造方法(设置私有的构造方法可见)
cons.setAccessible(true);
//通过两个参数的构造方法建立该字节码类的Object类型对象
Object obj=cons.newInstance("张三",23);
System.out.println(obj);
}
}
测试类2的运行结果是:
由图二可知,在不同的包下反射可以用Person类的私有构造方法创建Person对象。
//测试类3
package Class;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ClassDemo6 {
public static void main(String[] args) throws Exception {
//创建类的字节码对象
Class c=Class.forName("UDP.Person");
//获取该字节码对象的构造方法
Constructor cons=c.getDeclaredConstructor();
//通过无参构造方法建立该字节码类的Object类对象
Object obj=cons.newInstance();
Method m=c.getDeclaredMethod("show");
//设置私有的方法可见
m.setAccessible(true);
m.invoke(obj);
}
}
测试类3运行的结果是:
由图三可知,可以通过字节码文件对象获取该类所有的方法并,并调用指定的方法