反射

概念

官方介绍

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

通俗解释

把.class文件加载到内存,并创建对应的Class对象(这是第一步),然后获取Class对象(字节码对象)中的Constructor,Field,Method(这是第二步)。并通过这三个对象任意操作内存中的对象属性和行为(这是第三步)。

名词解释:

  • Constructor 构造方法描述器
  • Field 属性描述器
  • Method 方法描述器

获取Class对象的方式

当Person.class或者Dog.class文件加载到内存后可以得到一个对象,这个对象叫做Class,我们称为字节码对象,.class文件我们称为字节码文件,下面介绍如何把.class文件加载到内存,并得到对应的Class对象

public class 获取Class对象的三种方式 {
    public static void main(String[] args) throws Exception {
        //1.类名.class
        Class clazz = Person.class;

        //2.Class.forName("全类名");
        Class clazz2 = Class.forName("cn.itcast.domain.Person");

        //3.对象名.getClass()
        Class clazz3 = new Person().getClass();

        System.out.println(clazz==clazz2);//true
        System.out.println(clazz3==clazz2);//true
    }
}

输出都是true,说明同一个.class文件被加载到内存后我们得到的Class对象都是一样的

通过反射操作对象的属性

案例一:通过反射给person对象的name属性赋值,并且在获取name属性的值

Person person = new Person("李四", 13);


/*1.获取字节码对象*/
Class clazz = Person.class;

//2.获取name属性对应的Field对象
Field field = clazz.getDeclaredField("name");

//3.暴力反射,目的1.获取私有属性访问权限 2.提升程序性能
field.setAccessible(true);

//4.通过field给person对象的name属性赋值,等价于 person.name = "张三";
field.set(person, "张三");

//5.通过field获取person对象的name属性值,等价于 String name = person.name;
String name = (String)field.get(person);

//测试输出结果
System.out.println(name);//输出张三

通过反射操作构造方法

案例一:获取public Person(String name, int age){}构造方法对应的Constructor并创建对象

//1.获取字节码对象
Class clazz = Person.class;

//2.获取Person(String, int)构造对应的Constructor对象 
Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);

//3.暴力反射,目的1.获取私有属性访问权限 2.提升程序性能
constructor.setAccessible(true);

//4.通过constructor创建对象,等价于 Person person = new Person("张三",13);
Person person = (Person)constructor.newInstance("张三", 13);

System.out.println(person);

案例二:获取public Person(int age, String name){}构造方法对应的Constructor并创建对象

//1.获取字节码对象
Class clazz = Person.class;

//2.获取Person(int age, String name)构造对应的Constructor对象 
Constructor constructor = clazz.getDeclaredConstructor(int.class,String.class);

//3.暴力反射,目的1.获取私有属性访问权限 2.提升程序性能
constructor.setAccessible(true);

//4.通过constructor创建对象,等价于 Person person = new Person(13,"张三");
Person person = (Person)constructor.newInstance(13,"张三");

System.out.println(person);

案例三:获取Person()构造方法对应的Constructor并创建对象

//1.获取字节码对象
Class clazz = Person.class;

//2.获取Person()构造对应的Constructor对象 
Constructor constructor = clazz.getDeclaredConstructor();

//3.暴力反射,目的1.获取私有属性访问权限 2.提升程序性能
constructor.setAccessible(true);

//4.通过constructor创建对象,等价于 Person person = new Person();
Person person = (Person)constructor.newInstance();

System.out.println(person);

通过反射操作对象的普通方法

案例一:通过反射调用person对象的public setName(String name){}方法

Person person = new Person("张三", 13);

//1.获取字节码对象
Class clazz = Person.class;

//2.获取public setName(String name){} 方法对应的Method对象
Method setName = clazz.getDeclaredMethod("setName",String.class);

//3.暴力反射,目的1.获取私有属性访问权限 2.提升程序性能
setName.setAccessible(true);

//4.执行person对象的setName方法,等价于person.setName("李四");
setName.invoke(person,"李四");

System.out.println(person);

案例二:通过反射调用person对象的public getName(){}方法

Person person = new Person("张三", 13);

//1.获取字节码对象
Class clazz = Person.class;

//2.获取public String getName(){} 方法对应的Method对象
Method getName = clazz.getDeclaredMethod("getName");

//3.暴力反射,目的1.获取私有属性访问权限 2.提升程序性能
getName.setAccessible(true);

//4.执行person对象的getName方法,等价于String name = person.getName("李四");
String name = getName.invoke(person);

System.out.println(name);

反射案例

通过反射执行配置文件中指定类的指定方法

在src根目录新建配置文件config.properties,内容如下:

className=cn.itcast.domain.Student
methodName=sleep

Student类代码,该类必须放在cn.itcast.domain包下

public class Student{
    public void sleep(){
        System.out.println("睡觉");
    }
}

测试代码如下:

Properties properties = new Properties();
//表示将src目录下的config.properties中的数据加载到当前properties集合中
properties.load(反射的应用真实案例.class.getClassLoader().getResourceAsStream("config.properties"));

/*目的:执行className对应的类中methodName对应的方法*/
/*换句话说目的就是:执行Student类中sleep()方法*/

/*1.根据配置文件中className的值将Student类加载到内存,得到Class字节码对象*/
String className = properties.getProperty("className");
Class clazz = Class.forName(className);

/*2.通过Class字节码对象得到Constructor对象,并创建Student对象*/
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Object stu = constructor.newInstance();

/*3.通过Class字节码对象和methodName的值得到Method对象,并执行stu对象的方法*/
String methodName = properties.getProperty("methodName");//methodName的值sleep
Method method = clazz.getDeclaredMethod(methodName);
method.setAccessible(true);
method.invoke(stu);

好处

通过反射创建的这个测试类代码通用性非常强,可以执行任意类的任意无参方法。好处就是把项目部署到服务器以后如果想执行其他类的方法,只需要修改服务器上的config.properties配置文件即可。如果按照以前的方式:new Student().sleep(),想执行其他类的方法那么必须要在开发者电脑上修改源代码,重新编译项目,最后还需要重新上传到服务器,非常麻烦。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值