JAVA基础----反射



反射技术:

动态的获取指定的类以及动态的调用类中的内容。

以前是先有类,再new对象。
有了反射后:先new对象,也就是说把创建对象的动作先做完,至于new哪个类由用户通过配置文件传递。

好处:大大的提高了程序的扩展性。

反射的应用:当使用的类不确定的时候,可以通过配置文件告诉应用程序,只要应用程序中使用反射技术就可以了。


需要哪些对象呢?



Class 获取Class字节码文件
Constructor     提供关于类的单个构造方法的信息以及对它的访问权限。
Field 获取类或接口的字段信息
Method 提供关于类或接口上单独某个方法



动态创建对象的方法。newInstance();默认调用的是被反射类的空参数构造函数。


如果要通过指定的构造函数来初始化对象,需要先通过getConstructor()方法获取构造器对象。


然后,在通过构造器创建对象,并初始化。


如果要通过指定的构造函数初始化对象怎么办呢?
 
1,获取字节码文件对象。


  2,再获取给定的构造函数。


3,通过构造函数初始化对象。



要想获取字节码文件中的成员,必须要先获取字节码文件对象。
获取字节码文件对象的方式:


1,通过Object类中的getClass方法。


虽然通用,但是前提必须有指定类,并对该类进行对象的创建,才可以调用getClass方法。





2,使用的任意数据类的一个静态成员class,所有的数据类型都具备的一个属性。
好处:不用new对象。但是,还需要使用具体的类。



3,使用Class类中的forName方法。通过给定类名来获取对应的字节码文件对象。
这种方式很爽,只要知道类的名字就可以了。获取对应的字节码文件直接由forName方法自动完成。
这就是反射技术使用的获取字节码文件对象的方式。




字节码文件已经获取,那么它有什么用呢?


1.创建对象


2.获取字段


3.调用方法



创建对象:




1,通过给定的类名称,加载对应的字节码文件,并封装成字节码文件对象Class.

通过newInstance()就可以创建字节码对象所表示的类的实例。

2,通过new创建给定的类的实例。


3,调用该类的构造函数。
通常被反射的类都会有提供空参数的构造函数。
没有对应的构造函数,会报InstantiationException
如果有提供,但是权限不够,会报IllegalAccessException
 




获取字段:
 

获取字段对象。


Field field = 字节码对象.getField(fieldName); //获取是公共的字段。


Field field = 字节码对象.getDeclaredField(fieldName);//通过字段的名字获取字段

field.setAccessible(true);//取消权限检查,暴力访问。一般不访问私有。



获取方法:



getDeclaredMethods() //获取单个方法(包括私有)


getDeclaredMethod(String name, Class<?>... parameterTypes)  //获取所有方法 


getMethod(String name, Class<?>... parameterTypes) //获取所有公共方法


getMethods() //获取单个公共方法



练习:



<span style="font-size:24px;">/*自定义一个类,
 * 	面有公共成员变量,私有成员变量
 * 	公共成员方法,私有成员方法
 * 
 * 
 */
public class Reflect {
	
	private String name;
	
	public int i=100;
	
	private void show(){
		
		System.out.println("show---run");
		
	}
	
	public void show1(String str,int j){
		
		System.out.println(str+"show1---run"+j);
		
	}
}
</span>









<span style="font-size:24px;">public class ReflectDemo {
	public static void main(String[] args) {
		
		//配置文件位置
		File file=new File("src\\class.properties");
		
		//读取流引用
		FileReader fr=null;
		
		try {
			
			//创建读取流
			fr=new FileReader(file);
		} catch (FileNotFoundException e2) {
			
			System.out.println("未找到配置文件");
			return;
		}
		
		//可以从流中读取键值对的类
		Properties prop=new Properties();
		
		
		try {
			
			//从输入流中读取属性列表
			prop.load(fr);
		} catch (IOException e2) {
			
			e2.printStackTrace();
		}
		
		//通过建获取值,赋值给className
		String className = prop.getProperty("class");
		
		//字节码对象的引用
		Class<?> clazz;
		try {
			
			//获取字节码文件对象
			clazz = Class.forName(className);
		} catch (ClassNotFoundException e) {

			System.out.println("没有这个类");
			return;
		}
		
		//创建对象的引用
		Object obj;
		try {
			
			//创建对象
			obj = clazz.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			System.out.println("没有适合的构造方法或权限不够");
			return;
		}

		//获取字节码中的所有成员变量
		Field[] field = clazz.getDeclaredFields();
		
		//对成员变量进行遍历
		for (Field field2 : field) {

			try {
				
				//判断此对象有没有被赋值
				if (field2.get(obj)== null) {
					
					//如果没有赋值...
					field2.set(obj, "Ok");
					
					//打印成员变量的值
					System.out.println(field2.get(obj));
				} else {
					
					//如果已经赋值则直接打印
					System.out.println(field2.get(obj));
				}
			} catch (IllegalArgumentException e) {

				System.out.println("参数传递错误");
			} catch (IllegalAccessException e) {
				/*
				 * 如果成员是私有的,会进入到此catch中处理
				 */
				//暴力访问
				field2.setAccessible(true);
				try {
					if (field2.get(obj) == null) {
						
						field2.set(obj, "Ok");
				
						System.out.println(field2.get(obj));
						
					} else {
						
						System.out.println(field2.get(obj));
						
					}
				} catch (Exception e1) {
					e1.printStackTrace();
				}

			}
		}

		//获取所有方法
		Method[] method = clazz.getDeclaredMethods();
		//对方法进行遍历
		for (Method method2 : method) {

			try {
				
				//如果方法有参数
				if ((method2.getParameterTypes()).length != 0) {
					
					//调用传参方法
					method2.invoke(obj, "show运行", 1234);
					
				} else {
					
					//否则直接调用
					method2.invoke(obj, null);
					
				}
			} catch (IllegalAccessException e) {
				
				/*
				 * 如果成员是私有的,会进入到此catch中处理
				 */
				
				//暴力访问
				method2.setAccessible(true);
				try {
					if ((method2.getParameterTypes()).length != 0) {
						
						method2.invoke(obj, "show运行", 4321);
						
					} else {
						
						method2.invoke(obj, null);
						
					}
				} catch (Exception e1) {

					e1.printStackTrace();
				}

			} catch (IllegalArgumentException e) {

				System.out.println(method2 + "参数传递错误");
				break;
			} catch (InvocationTargetException e) {

				System.out.println("无法调用此类");
			}

		}

	}
}
</span>





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值