反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。一直以来反射技术都是Java中的闪亮点,这也是目前大部分框架(如Spring/Mybatis等)得以实现的支柱。
在Java中,Class类与java.lang.reflect类库一起对反射技术进行了全力的支持。在反射包中,我们常用的类主要有Constructor类表示的是Class 对象所表示的类的构造方法,利用它可以在运行时动态创建对象、Field表示Class对象所表示的类的成员变量,通过它可以在运行时动态修改成员变量的属性值(包含private)、Method表示Class对象所表示的类的成员方法,通过它可以动态调用对象的方法(包含private)
一、实体对象类,用作反射操作的对象
public class Person {
public static final long serialVersionUID=1l;
public String name;
private int age;
public Person() {
System.out.println("无参构造函数,运行...");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造函数,运行...");
System.out.println("name:"+this.name+",age:"+this.age);
}
public void method01(){
System.out.println("共有无参函数,运行...");
}
private void method02(){
System.out.println("私有无参函数,运行...");
}
public void method03(String name,int age){
System.out.println("公有带参函数,name:"+name+"; age:"+age);
}
private void method04(String name,int age){
System.out.println("私有带参函数,name:"+name+"; age:"+age);
}
}
二、获取字节码类的方式
/**
* @Author Loujitao
* @Date 2018/6/27
* @Time 11:32
* @Description: 第一种通过实例对象获取字节码类
*/
public static void function01(){
Person person=new Person();
Class c=person.getClass();
System.out.println(c);
/**结果:
* 无参构造函数,运行...
* class com.steve.reflect.Person
*/
}
public static void function02(){
//通过静态方法获取字节码类
Class c=Person.class;
System.out.println(c);
/**结果:
* class com.steve.reflect.Person
*/
}
public static void function03() throws Exception{
//通过类名获取字节码类
Class c = Class.forName("com.steve.reflect.Person");
System.out.println(c);
/**结果:
* class com.steve.reflect.Person
*/
}
三、获取字段(成员变量)
/**
* 获取单个字段
*/
public static void function01(Class c) throws Exception{
//它反映此 Class 对象所表示的类或接口的指定 公共 成员字段。
Field field=c.getField("name");
//反映此 Class 对象所表示的类或接口的指定已声明字段。 可以获取私有的属性
Field f=c.getDeclaredField("age");
System.out.println("name: "+field );
System.out.println("age: "+f);
/* 结果:
name: public java.lang.String com.steve.reflect.Person.name
age: private int com.steve.reflect.Person.age
*/
}
/*
* 获取字段数组 只能获取共有的字段
* */
public static void function02(Class c) throws Exception{
Field[] fields=c.getFields();
for (Field f:fields ) {
System.out.println(f);
}
/**结果:
* public static final long com.steve.reflect.Person.serialVersionUID
* public java.lang.String com.steve.reflect.Person.name
*/
}
/*
* 获取字段数组 所有的
* */
public static void function03(Class c)throws Exception{
Field[] fields=c.getDeclaredFields();
for (Field f:fields ) {
System.out.println(f);
}
/**结果:
* public static final long com.steve.reflect.Person.serialVersionUID
public java.lang.String com.steve.reflect.Person.name
private int com.steve.reflect.Person.age
* */
}
四、获取方法并执行
//获取构造函数
public static void function01(Class c) throws Exception{
Object obj=c.newInstance();
System.out.println(obj);
Constructor ct=c.getConstructor(String.class,int.class);
Object o= ct.newInstance("steve",18);
System.out.println(o);
/*结果:
无参构造函数,运行...
com.steve.reflect.Person@1540e19d
有参构造函数,运行...
name:steve,age:18
com.steve.reflect.Person@677327b6
*/
}
//获取方法
public static void function02(Class c)throws Exception{
Object obj=c.newInstance();
Method m=c.getMethod("method01",null);
m.invoke(obj);
Method m2=c.getDeclaredMethod("method02",null);
//将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力
m2.setAccessible(true);
//对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
m2.invoke(obj);
Method m3=c.getMethod("method03",String.class,int.class);
m3.invoke(obj,"steve",26);
Method m4=c.getDeclaredMethod("method04",String.class,int.class);
m4.setAccessible(true);
m4.invoke(obj,"steve",26);
}
//获取方法数组
public static void function03(Class c)throws Exception{
//获取共有方法
Method[] m1=c.getMethods();
for (Method m:m1) {
System.out.println(m);
}
System.out.println("----------手动分割线-------------------");
Method[] m2=c.getDeclaredMethods();
for (Method mt:m2 ) {
System.out.println(mt);
}
}