反射原理

反射原理

  • 反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

  • 其实就是获取一个类的Class对象,并且操作类中的各个组成部分的一个技术。

  • 在运行时可以获取。

反射使用的第一步

  • 获取一个类的Class对象(字节码对象)。

  • 有三种方法:(重点,熟练掌握)

    1. Class.forName(“全类名”)
      解耦性更好,一般用于配置文件设置全类名。在框架中经常使用。

    2. 类名.class
      编写方便

    3. 对象.getClass()
      即使是使用接口类型接受的对象,也能获取其字节码对象

  • 一个类,在同一jvm中,只会加载一次。Class对象无论获取多少次,都是同一个。

Class对象的使用

  1. 获取成员变量

     	1. Field getField(String fieldName); 
     		根据指定的成员变量名,获取指定的成员变量,只能获取非私有化成员变量
    
     	2)Field getDeclaredField(String fieldName); 
     		根据指定的成员变量名,获取指定的成员变量,可以获取私有化成员变量
    
  2. 获取构造方法

     	1)Constructor getConstructor(Class… parameterTypes);
     		根据参数类型,获取指定参数类型的构造方法,只能获取非私有化的构造方法
    
     	2)Constructor[] getConstructors(); 
     		获取当前类内的所有非私有化构造方法
    
     	3)Object newInstance(Object… args); 
     		通过Constructor类对象,调用newInstance方法,
     		创建类对象 Object… 不定长参数,用于传入构造方法所需的参数
    
     	4)setAccessible(boolean) ; 
     		给予 私有化构造方法,成员方法,成员变量 操作权限
    
  3. 获取成员方法

     	Method getMethod(String methodName, Class… parameterTypes);
     		根据方法名和参数类型,获取指定的非私有化成员方法 
     		methodName:当前方法的名字 
     		parameterTypes: 不定长参数,用于约束方法的参数
    
     	Method getDeclaredMethod(String methodName, Class… parameterTypes);
     		根据方法名和参数类型,可以获取指定的私有化成员方法
    
    
     	Method[] getMethods(); 
     		获取类内所有非私有化成员方法,和从父类继承而来的可以在子类使用的成员方法
    
    
     	invoke(Object obj, Object… args); 
     		指定Method类对象方法
     		obj: 执行当前方法的类对象
     		args:不定长参数,是当前执行方法所需的实际参数列表
    
    
     	1)指定方法的名称以及参数列表(用Class表示)
    
     	2)Method对象,可以调用其invoke方法执行该方法。
    
     	3)静态方法,在调用时,不需要指定在哪个对象上执行,所以直接传null即可。
     		staticMethod.invoke(null);
    
  4. 类中的其他信息

     	类名			getName​()
    
     	包名			getPackageName​()
    
     	类实现的所有接口	Class<?>[] getInterfaces​() 
    
     在上述方法中,Declared修饰的方法代表获取所有已声明的类的组成部分。
     从而可以达到绕过修饰符限制访问这些组成部分的效果。
    
  5. 注意:
    真正使用这些组成部分是,需要“暴力反射”。setAccessable(true)
    即使可以使用反射绕过访问修饰符,
    但是实际操作时不推荐访问private修饰的组成部分。因为这种操作可能有安全隐患。

反射调用方法的步骤

  • 步骤

    1. 获取方法所在类的字节码对象.

    2. 获取方法对象.

    3. 使用反射调用方法.

  • 案例

	  	public class User {
			public void doWork() {
				System.out.println("User doWork()");
			}
		 
			public static void doWork(String name) {
				System.out.println("User doWork()"+name);
			}
		 
			private String sayHello(String name, int age) {
				System.out.println("User sayHello()"+name+","+age);
				return name + "," + age;
			}
		}
		
		public class InvokeMethodDemo {
			public static void main(String[] args) throws Exception {

				//1.获取方法所在类的字节码对象.
				Class<User> user = User.class;


		//调用doWork()

				//2.获取方法对象.
				Method method1 = user.getMethod("doWork");

				//3.使用反射调用方法.
				method1.invoke(user.newInstance());//User doWork()
				System.out.println("================================");


		//调用doWork(String name)

				//2.获取方法对象.
				Method method2 = user.getMethod("doWork", String.class);

				//3.使用反射调用方法.
				method2.invoke(user.newInstance(), "杨哥");//User doWork()杨哥
				System.out.println("================================");


		//调用private String sayHello(String name,int age)

				//2.获取方法对象.
				Method method3 = user.getDeclaredMethod("sayHello", String.class,int.class);

				method3.setAccessible(true);//设置可访问私有的成员

				//3.使用反射调用方法.
				String ret = (String) method3.invoke(user.newInstance(), "杨哥",18);//User sayHello()杨哥,18

				System.out.println(ret);


			}
		}

使用反射优缺点

  • 可以在配置文件中进行类的相关设置。修改功能时,无需修改代码,而是修改配置。

  • 好处:
    不改代码,不需要重新编译。也不需要重新打包,部署。
    配置文件不参与编译,所以修改非常灵活。

  • 坏处:
    代码的复杂度提升了。维护代码不方便。对编程人员的技术要求更高

ClassLoader加载文件

  • 类加载器。只能获取类路径下的资源。

  • getResource
    获取类路径下的资源,返回一个URL对象

  • getResourceAsStream
    获取类路径下的资源,返回一个流对象InputStream

  • 上述方法传参:
    传递的是相对于类路径的一个相对路径。不需要在前面写 /

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值