反射简单学习

目录

反射

概述介绍

概述:

好处:

获取Class对象三种方式

Class对象的功能

获取成员变量

获取构造方法

获取成员方法

案例


反射

概述介绍

概述:

  1. 将类的各个组成部分封装为其他对象,这就是反射机制

好处:

  1. 可以在程序运行过程中,操作这些对象。

  2. 可以解耦,提高程序的可扩展性。

获取Class对象三种方式

  1. Class.forName("全类名") 将字节码文件加载进内存,返回class对象

    多用于配置文件,将类名定义在配置文件中。读取文件,加载类

  2. 类名.class :通过类名的属性class获取

    多用于参数的传递

  3. 对象.getclass() : getclass()方法在object类中定义着。

    多用于对象的获取字节码的方式

注意:同一个类中,不论通过哪一种方式获取的Class对象都是同一个

Class对象的功能

获取成员变量

  1. Field getField(string name) 获取public且指定的成员变量

  2. Field[] getFields() 获取所以public修饰的所以成员变量

  3. Field getDedclaredField(string name) 获取指定的成员变量

  4. Field[] getDeclaredFields() 获取所以的成员变量,不考虑修饰符

    注意:得到了以上的field对象,都可以通过 field对象.get(访问的那个对象) ,获取具体的成员变量值

    但是,private修饰的不能直接field.get(obj)获取,需要 field.setAccessible(true);//叫暴力反射

package com.xxx.index;
import java.lang.reflect.Field;
public class Text {
	public static void main(String[] args) throws Exception{
//		获取Class类 和 Demo01对象
		Class cla=Demo.class;
		Demo demo01=new Demo();
//		获取public修饰的
		System.out.println(cla.getField("name").get(demo01));//mxp
//		获取private修饰的
		Field field=cla.getDeclaredField("age");
		System.out.println(field);//private int com.xxx.index.Demo01.age
//		System.out.println(field.get(demo01));//java.lang.IllegalAccessException(非法访问) 因为是private修饰的,
//		忽略访问权限修饰符的安全检查
		field.setAccessible(true);//叫暴力反射
		System.out.println(field.get(demo01));
	}

}
class Demo {
	public String name="mxp";
	private int age=18;
}

看看输出结果:

获取构造方法

  1. Constructor<?> getConstructor(Class<?>... parameterTypes) 返回一个public修饰的且指定的构造器

  2. Constructor<T>[] getConstructors() 返回全部public修饰的构造器

  3. Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) 获取指定的构造器

  4. Constructor<?>[] getDeclaredConstructors() 获取所有的构造器

    直接上代码吧

     package com.xxx.index;
     import java.lang.reflect.Constructor;
     public class Text {
         public static void main(String[] args) throws Exception {
             Class cla1=Demo.class;
     //      获取有参构造器
             Constructor<Object> con01=cla1.getConstructor(String.class,int.class);
             System.out.println(con01);//public com.xxx.index.Demo(java.lang.String,int)
     //      创建对象    newInstance
             System.out.println(con01.newInstance("mxp",18));
     //      为了方便    Class还提供了一个可以直接创建无参对象的方法
             System.out.println(cla1.newInstance()); 
         }
     }
     class Demo {
         public Demo() {
             System.out.println("执行了无参构造");
         }
         public Demo(String name,int age) {
             System.out.println("执行了有参构造");
         }
     }

    看看输出结果:

获取成员方法

  1. Method getMethod(String name,类<?>... parameterTypes) 获取public修饰的指定方法

    第一个参数:String是获取的那个方法名

    第二个参数:这个方法参数的Class对象。

  1. 其他的三个方法跟上面都差不多,我就不列出来了

  2. method.invoke(Object obj,Object... args); 执行获取的method对象

    第一个参数:目标对象

    第二个参数:传给实现方法的参数传值

package com.xxx.index;
 import java.lang.reflect.Method;
 public class Text {
     public static void main(String[] args) throws Exception {
         Class class1=Demo.class;
         Demo demo=new Demo();
         //获取方法
         Method method=class1.getMethod("eat", String.class,int.class);
         System.out.println(method);//public void com.xxx.index.Demo.eat(java.lang.String,int)
         //执行方法
         method.invoke(demo, "佩奇",7);//我叫佩奇一顿吃7碗
         }
 }
 class Demo {
     public void eat(String name, int a) {
         System.out.println("我叫" + name + "一顿吃" + a + "碗");
     }
 }

看下输出结果:

案例

看了这么多是不是感觉不出,学这个有啥用?直接上代码

我们的需求就是在不修改任何代码的情况下,调用不同的方法

 package anli;
 ​
 public class Person01 {
     public void eat() {
         System.out.println("eat...");
     }
 }
 class Person02{
     public void sleep() {
         System.out.println("sleep...");
     }
 }
 
 package anli;
 import java.io.InputStream;
 import java.lang.reflect.Method;
 import java.util.Properties;
 ​
 public class Test {
     public static void main(String[] args) throws Exception{
 //      1.创建properties      用于读取Java的配置文件
         Properties pro=new Properties();
         ClassLoader classLoader=Test.class.getClassLoader();//获取这个字节码文件的内加载器
         InputStream is=classLoader.getResourceAsStream("pro.properties");//获取资源对应的字节流
         pro.load(is);//这里需要传一个字节或字符 , 从输入流中读取属性列表(键和元素对),  读取properties的配置文件
         
 //      获取配置文件的数据
         String className=pro.getProperty("className");
         String methodName=pro.getProperty("methodName");
         
 //      加载该类进内存
         Class cls=Class.forName(className);
         Object obj=cls.newInstance();
         Method method=cls.getMethod(methodName);
         method.invoke(obj);//sleep...
     }
 ​
 }
​pro.properties
 className=anli.Person02
 methodName=sleep

 看下输出结果:

现在我们就不需要改源代码了,修改配置文件就行了

className是全类名

methodName是方法名 

className=anli.Person01
methodName=eat

 看下输出结果:

现在明白了哈,瑞思拜

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值