反射原理

反射原理:

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

	* 其实就是获取一个类的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修饰的方法代表获取所有已声明的类的组成部分。
	从而可以达到绕过修饰符限制访问这些组成部分的效果。

	注意:真正使用这些组成部分是,需要“暴力反射”。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

* 上述方法传参:
		传递的是相对于类路径的一个相对路径。不需要在前面写 / 
上一篇:JAVA设计模式之装饰器模式


下一篇:C#多态