反射【重点,难点,提升点】

1.程序运行分析
1.1 Java 文件 和 java 程序的关系
	按照目前的代码风格, Java 文件有且只有一个类,类的组成格式
		class 类名 {
			成员变量:Filed
			成员方法:Method
			构造方法:Constructor
		}
		
Java 文件包含 对应 Java 程序的所有内容
1.2 Java文件编译之后的 .class 字节码文件
Java 文件通过该 Java 编译器 (javac) 编译之后得到可以交给 JVM 执行所需的 .class
字节码文件/二进制文件。
Java 文件中的每一个 class /interface 都会生成对应的.class 字节码文件

【问题】
	.class 字节码文件中是否包含 Java 程序的所有内容,或者说对应 class / 		interface 的所有内容 ??
		.class 字节码文件是 Java 文件编译之后的结果,包含文件所有的 class/ interface 代码内容
	
1.3 类加载过程和内存占用分析
运行程序 JVM 会将当前程序运行所需 .class 字节码文件加载到内存中。 .class 字节码文件加载到内存【方法区】,占用一块内存【方法区】数据空间

【问题】
	.class 字节码文件件占用的内存【方法区】空间,是否包含 Java程序,或者说对应 class /interface 的所有内容??
		对应的内存空间包含 Java 程序的所有内容
1.4 删除分析加载过程和内存占用问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HaYnLRaA-1668605672134)(F:\qianfeng\笔记\img\内存分析.jpg)]

2. Class 对象获取操作
2.1 Class 对象获取方式【万恶之源】
public static Class forName(String packageAndClassName);
	Class 类静态成员方法,通过参数指定的完整的包名,类名字符串信息,获取包名,类名对应类的 Class 对象

Class getClass();
	Object 类内成员方法. Java 中的任意一个对象都通过调用 getClass() 方法获取当前对象对应数据类型 Class 对象。
		new Person().getClass();
类名.class
	通过 Java 中类型名称,获取当前类对应的属性,结果为 Class 对象
public class Demo1 {
	public static void main(String[] args) 
        //ClassNotFoundException 指定类型未找到异常
			throws ClassNotFoundException {
		
		//public static Class forName(String packageAndClassName);
		Class<?> cls1 = Class.forName("com.qfedu.a_reflect.Person");
		//Class getClass();
		Person p1 = new Person();
		Class<? extends Person> cls2 = p1.getClass();
		//类名.class
		Class<Person> cls3 = Person.class;
		
		/*
		 * 三种方式获取的 Class 对象是否为同一个 Class 对象??
		 *		Java 中规定,任何一个类型有且只加载一次,对应的内存空间有且只有一			*		份
		 *		无论通过哪种手段获取的 Class 对象,只有类型一致,都是同一个  			 *		Class 对象
		 *
		 * */
		System.out.println(cls1);//true
		System.out.println(cls2);//true
		System.out.println(cls3);//true
	}
}
2.3 方法功能分析概述
public static Class forName(String packageAndClassName);
	【使用最多】
		使用最多可以通过完整的包名,类名获取任意 class 对象,后期可以用于指定类型		加载,指定类型获取,也可以通过该配置文件方式获取相关内容得到执行类型。
		Class.forName 有一个特殊功能,也可以强制要求 JVM 加载指定类。
Class getClass();
	通常用于类型判断,类名比较,在已获取对象的情况下,获取对应 Class 对象。
	利用 getClass 优化重写 equals 方法。
类名.calss
	常用于方法参数的,所需参数的类型约束,
	例如
		方法约束参数类型为 Person.class ==> 要求 ==> 方法所需参数为 Person 类对象
		方法约束参数类型为 int.class ==> 要求 ==> 方法所需参数为 int 类型
中午思考的问题
1.构造方法定义格式?? 是否每一个类相同的格式/模板??

2.成员方法定义格式?? 是否每一个类相同的格式/模板???

3.成员变量定义格式?? 是否每一个类相同的格式/模板??



以上所有内容,关注
	1.调用操作要求
	2.唯一性,特征性,有哪些???
3. 构造方法 Constructor 对象相关操作
3.1 构造方法分析
构造方法格式:
	权限修饰符 类名(形式参数列表) {
		构造方法方法体
	}
	
调用构造方法过程中:
	1.所有的构造方法的名称一样,都是类名【Java 中的规定】
	2。java 编译器是根据实际参数类型,个数,顺序来决定到底调用哪个构造方法
	
【总结】
	执行不同的构造方法,关键因素是实际参数类型,个数和顺序。
	
【补充问题】
	参数命重要吗?
		参数名称不重要,保证最基本是见明知意,小驼峰命名法,重点【参数类型】
		
【补充问题】
	Class 类型对象,是否存在一个方法可以获取当前类型的名称???
		Class<Person> cls1 = Person.class;
		cls1.getName();
		cls1.getClassName();
		存在获取类型名称的方法。

【重点】
	通过 Class 对象【提取】内部的构造方法Constructor 对象 有且只关注
			参数类型,个数,顺序
		
3.2 通过 Class 对想获取 Constructor 构造方法对象相关方法
Constructor[] getConstructors();
 通过获取 Class 对象调用,获取对应类型的所有非私有化构造方法 Constructor 对象数组
 
Constructor[] getDeclaredConstructers();
	【暴力反射】
	通过Class 对象调用,获取对应类型所有构造方法 Constructor 对象数组,包括私有化构造方法
	
	
Constructor getConstructor(Class... parameterTypes);
	通过 Class 对象调用,获取指定参数类型的非私有化构造方法对象。
	Class... parameterTypers
		不定长参数,要求参数类型为 Class 类型,用来约束构造方法的数据类型情况,包括类型,顺序和参数个数
	例如:
		Class<Person> clas = Person.class;
        //获取 Person 类的无参数构造方法 Person();
        Constructor c1 = cls.getConstructor(); ===> public Person();
        
        //获取 Person 类的有参构造方法 Person(int, String);
        Constructor c2 = cls.getConstructor(int.class ,string.class);
        	==> public Person(int , String);
        	
Constructor getDeclarConstructor(Class... parameterTypes);
        【暴力反射】
        通过Class 对象调用,获取指定参数类型的构造方法对象,获取私有化构造方法对象
        Class... parameterTypes
        	不定长参数,要求参数类型为 Class 类型,用来约束构造方法的数据类型情况,包括类型,顺序,个数。
        例如:
        	Class<Person> cls = Person.class;
        	//获取 Person 类的私有化有参数构造方法 private Person(String);
        	Constructor c2 = cls.getConstructor(int.class, String.class);
        	====> public Person(int , String);
        
import java.lang.reflect.Constructor;

/*
 * 构造方法对象获取代码演示
 * ClassNotFoundException,  
 * 类型未找到异常注意提供的包名类名信息是否正确
 * NoSuchMethodException,
 * 指定方法未找到异常,需要注意方法的名称,参数名称,参数顺序,参数个数是否与已存在的方法一致
 * SecurityException
 * 安全异常
 * */
public class Dmeo2 {
	public static void main(String[] args) 
			throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
		
		/*
		 * 万恶之源,获取指定类型的 class 对象
		 * */
		Class<?> cls = Class.forName("com.qfedu.a_reflect.Person");
	
		/*
		 * 
		 * Constructor[] getConstructors();
		 * 获取类内的非私有化构造方法对象数组
		 * */
		Constructor<?>[] constructors = cls.getConstructors();
		for (Constructor<?> constructor : constructors) {
			System.out.println(constructor);
		}
		System.out.println();
		
		/*
		 * Constructor[] getDeclaredContructors();
		 * 【暴力反射】
		 * 获取类内所有构造方法对象数组,包括私有化构造方法
		 * */
		Constructor<?>[] declaConstructors = cls.getDeclaredConstructors();
		for (Constructor<?> constructor : declaConstructors) {
			System.out.println(constructor);
		}
		
		System.out.println();
		
		/*
		 * 根据指定参数类型,获取非私有化构造方法对象
		 * 
		 * int.class String.class 都是 Class对象 完成操作是对于方法参数类型,顺序,个数约束
		 * */
		Constructor<?> c1 = cls.getConstructor();
		Constructor<?> c2 = cls.getConstructor(int.class);
		Constructor<?> c3 = cls.getDeclaredConstructor(int.class, String.class);
		// NoSuchMethodException 方法参数类型,个数,顺序与当前类内存在的构造方法不一致,
		// Constructor<?> c4 = cls.getConstructor(String.class, int.class);
		// NoSuchMethodException 方法权限修饰非私有化,private 修饰需要暴力反射
		// Constructor<?> c4 = cls.getConstructor(String.class);		
		System.out.println(c1);
		System.out.println(c2);
		System.out.println(c3);
		System.out.println();
		/*
		 * Constructor getDeclaredConstructor(Class... parameterTypes);
		 * 【暴力反射】
		 * 根据指定的参数类型,获取构造方法对象,可以获取私有化构造方法
		 */
		Constructor<?> c4 = cls.getDeclaredConstructor(String.class);
		Constructor<?> c5 = cls.getDeclaredConstructor(int.class, String.class);
		
		System.out.println(c4);	
	}
}

3.4 利用构造方法对象实例化对应类对象
Object newInstance(Object... parameters);
 	通过 Constructor 构造方法对象调用,用于实例化对应类对象,所需参数为
 	Object... 不定长参数,根据构造方法实际所需参数(类型,个数,顺序)给予对应的实参。
 	

package com.qfedu.a_reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/*
 * 构造方法对象,实例化对应类对象操作
 * 
 * ClassNotFoundException 指定类型未找到异常 
 * NoSuchMethodException 指定方法未找到异常
 * SecurityException 安全异常
 * InstantiationException 实例化操作异常
 * IllegalAccessException 非法权限操作异常
 * IllegalArgumentException 非法参数异常
 * InvocationTargetException 执行目标操作异常
 * 
 * */
public class Demo3 {
	public static void main(String[] args) 
			throws 
			ClassNotFoundException, 
			NoSuchMethodException,
			SecurityException, 
			InstantiationException, 
			IllegalAccessException, 
			IllegalArgumentException, 
			InvocationTargetException {
		Class<?> cls = Class.forName("com.qfedu.a_reflect.Person");
	
		Constructor<?> c1 = cls.getConstructor();
		Constructor<?> c2 = cls.getConstructor(int.class);
		Constructor<?> c3 = cls.getConstructor(int.class , String.class);
		Constructor<?> c4 = cls.getDeclaredConstructor(String.class);
		/*
		 * 目前构造方法对应的类为 Person 类型实例化对象得到的都是Person对象
		 * */
		Object o1 = c1.newInstance();
		System.out.println(o1);
		Object o2 = c2.newInstance(10);
		System.out.println(o2);
		Object o3 = c3.newInstance(10, "张三");
		System.out.println(o3);
		/*
		 * void setAccessible(boolean flag)
		 * 		给予通过【暴力反射】 获取Constructor,Method,Field 私有化修饰内容
		 * 		操作权限 flag = true 即可操作
		 * 
		 * */
		c4.setAccessible(true);
		Object o4 = c4.newInstance("张三");
		System.out.println("私有化构造方法实例化对象:" + o4);
		System.out.println();
		/*
		 * 终究只能是一个类型
		 * 反射操作,可以是多种多样的类型
		 * 
		 * */
		Person p1 = new Person();
		Person p2 = new Person(10);
		Person p3 = new Person(10, "张三");
		System.out.println(p1);
		System.out.println(p2);
		System.out.println(p3);
	}
}

字符串内容:
	String info = "class=com.qfedu.entity.Student;[id=1,name=张三,age=16,gender=男][id=2,name=李四,age=17,gender=男][id=3,name=王五,age=26,gender=男]";
	
	
	String info = "class=com.qfedu.entity.Teacher;[id=1,name=张三,age=16,gender=男][id=2,name=李四,age=17,gender=男][id=3,name=王五,age=26,gender=男]";
4.1 成员方法 Method 对象相关操作
4.1 成员方法分析
格式:
	权限修饰符 是否静态 返回值类型 方法名(形式参数列表) {
			方法体;
	}
	
调用/使用一个方法的过程中:
	1.调用这是谁
	2.执行方法的名称是什么
	3.执行方法所需的实际参数是什么


获取 Method 成员方法对象,关注点
	1.方法的名称
	2.方法的参数类型,个数,顺序。
4.2 通过 Class 对想获取 Method 成员方法对象相关方法
Method[] getMethods();
	通过 Class 对象调用,获取 Class 对应对应类型类内所有的费私有化成员方法 Method 对象数组,包括从父类继承到之类的非私有化成员方法。
	
Method[] getDeclaredMethods();
	
	【暴力反射】
	通过Class 对象调用,获取 Class 对象对应类型类内所有成员方法 Method 对象数组,包括私有化方法,但是不包括父类继承而来的方法,仅是当前类特征方法
Method getMethod(String methodName, Class... parameterTypes);
	通过 Class 对象调,根据指定的成员方法名称,methodName 以及对应形式参数列表 Class ...
     parameterTypes 类型,获取对应的非私有化成员方法对象。
        methodName 约束成员方法名称
        Class... parameterTyes 约束成员方法对应的参数类型,个数和顺序
        案例:
        	Class<Person> cls = Person.class;
			//获取成员方法 public game();
			Method m1 = cls.getMethod("game");
				==> public game();
			//获取成员方法 public game(String);
			Method m2 = cls.getMethod("game", String.class);
				==> public game(String);
Method getDeclaredtMethod(String methodName, Class... parameterTypes);
	【暴力反射】
	通过 Class 对象调用, 根据指定的成员方法名称 methodName,以及对应形式参数列表 			Class... parameterTypes 类型,获取对应的成员方法对象,包括私有化成员方法,同时限制为		当前类特征方法。
	methodName 约束成员方法名称
    Class... parameterTypes 约束成员方法对应的参数类型,个数和顺序
    案例:
    	Class<Person> cls = Person.class;
		// 获取成员方法 private testPrivate();
		Method m1 = cls.getDeclaredtMethod("testPrivate");
			===> private testPrivate();
		// 获取成员方法 private testPrivate(String);
		Method m2 = cls.getDeclaredtMethod("testPrivate", String.class);
			===> private testPrivate(String);
4.3 成员方法对象获取代码演示
import java.lang.reflect.Method;

/*
 * Method 成员方法获取
 * */
public class Demo4 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
		
		Class<?> cls = Class.forName("com.qfedu.a_reflect.Person");
		/*
		 *Method[] getMethod();
		 * 获取非私有化成员方法,包含父类继承到子类的方法
		 */
		Method[] methods = cls.getMethods();
		for (Method method : methods) {
			System.out.println(method);
		}
		System.out.println();
		/*
		 * Method[] getDeclaredMethods();
		 *【暴力反射】
		 * 获取所有成员方法,包括私有方法,但是不包含继承父类的方法
		 * */
		Method[] declaredMethods = cls.getDeclaredMethods();
		for (Method method : declaredMethods) {
			System.out.println(method);
		}
		System.out.println();
		/*
		 * Method getMethod(String methodName, Class... parameterTyper);
		 * 	根据成员方法名称,成员方法数据类型,获取指定成员方法
		 * */
		Method m1 = cls.getMethod("game");
		Method m2 = cls.getMethod("game", String.class);
		System.out.println(m1);
		System.out.println(m2);
		System.out.println();
		/*
		 * Method getDeclaredMethod(String methodName, Class... parameterTypes);
		 * 	【暴力反射】
		 * 	根据方法名称,以及方法参数类型,获取成员方法,包括私有化成员方法	
		 */
		Method m4 = cls.getDeclaredMethod("game");
		System.out.println(m4);
		System.out.println();
		Method m3 = cls.getDeclaredMethod("game", String.class);
		System.out.println(m3);
	
	}
}
4.4 成员方法调用操作演示
原本调用方法:
	调用者.方法名(实际参数);
	
目前得到的是 Method 对象,如果当前Method 对象对应的方法需要执行,缺什么??
	1.调用者
	2.实际参数
	
	
	Method 对象.xxx(调用者, 实际参数...)
	
Object invoke(Object obj, object... parameters);
	通过 Method 对象调用,执行目标方法所需参数
		Object obj 执行当前方法的类对象
		Object... parameters 当前方法所需的实际参数,数据类型多样。
						采用 Object 数据个数不限制采用不定长参数。
						
						
						
成员方法调用操作演示
package com.qfedu.a_reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo5 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
		Class<?> cls = Class.forName("com.qfedu.a_reflect.Person");
	
		//非暴力反射获取成员方法Method 对象
		Method m1 = cls.getMethod("game");
		Method m2 = cls.getMethod("game", String.class);
		//暴力反射获取成员方法Method 对象
		Method m3 = cls.getDeclaredMethod("game");
		Method m4 = cls.getDeclaredMethod("game", String.class);
	
		//利用反射操作实例化 Person 类型对象
		Object  obj = cls.getConstructor().newInstance();	
		//invoke 执行目标成员方法操作
		m1.invoke(obj);
		m2.invoke(obj, "PUBG");	
		//暴力反射没有权限,直接赋予操作
		m3.setAccessible(true);
		m4.setAccessible(true);
		m3.invoke(obj);
		m4.invoke(obj, "大盘鸡");

	}
}

5.成员变量 Field对象相关操作
5.1成员变量分析
格式:
	数据类型 成员变量名称;
区分成员变量:
	成员变量名称,
5.2 通过 Class 对象获取 Field 成员变量对象相关方法
Field[] getFields();
	获取类内所有非私有化成员变量对象数组
Field[] getDeclaredFields();
	【暴力反射】
	获取类内所有成员变量对象数组,包括私有化成员变量
Field getField(String fieldName);
	根据指定的成员变量名称,获取对应的非私有化成员变量 Field 对象
Field getDeclaredField(String fieldName);
	【暴力反射】
	根据指定的成员变量名称,获取对应的非私有化成员变量 Field 对象,包括私有化成员变量
5.3成员变量对象代码演示
package com.qfedu.a_reflect;

import java.lang.reflect.Field;

/*
 * Field
 * 成员变量对象获取操作
 * */
public class Demo6 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException {
		Class<?> cls = Class.forName("com.qfedu.a_reflect.Person");
		
		/*
		 * Field[] getFields();
		 * 获取非私有化成员变量对象数组
		 * */
		Field[] fields = cls.getFields();
		for (Field field : fields) {
			System.out.println(field);
		}
		
		System.out.println();
		/*
		 *Field[]  getDeclaredFields();
		 * 【暴力反射】
		 * 获取所有成员变量,包括私有化成员变量
		 * */
		Field[] fields2 = cls.getDeclaredFields();
		for (Field field : fields2) {
			System.out.println(field);
		}
		/*
		 * Field getField(String fieldName);
		 * 
		 * 	根据指定成员变量名称,获取对应的非私有成员变量 Field 对象
		 * */
		Field f2 = cls.getField("test");
		System.out.println(f2);
		
		
		
		/*
		 * 【暴力反射】
		 * 	根据指定成员变量名称,获取对应的成员变量,包括私有化成员变量
		 * */
		Field f1 = cls.getDeclaredField("id");
		Field f3 = cls.getDeclaredField("name");
		System.out.println(f1);
		System.out.println(f3);
	
	}
}

5.4成员变量赋值取值操作
原本操作:
	Person p1 = new Person();
	
	p1.setId(10);
	p1.setName("张三");
	p1.getId();
	p1.getName();
	
反射操作思想:
	目前我们手里有成员变量 Field 对象
	想要执行赋值和取值操作
		1. 明确是哪一个对象的成员变量【调用者】
		2.值 赋值操作对应的数据
		
	field 对象.set(调用者, 值);
	field对象.get(调用者); 取值
	
取值方法:
	void set(Object obj, Object value);
package com.qfedu.a_reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/*
 * 
 * Field 成员变量赋值/取值操作
 * */
public class Demo7 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
		Class<?> cls = Class.forName("com.qfedu.a_reflect.Person");
		/*
		 * 【暴力反射】
		 * 获取指定的成员变量包括私有化成员变量
		 * */
		Field id = cls.getDeclaredField("id");
		Field name = cls.getDeclaredField("name");
	
		/*
		 * 获取指定的非私有化成员变量
		 * */
		Field test = cls.getField("test");
		
		
		//实例化当前 Class对应类型对象 ,实例化 Person 对象
		
		Object obj = cls.getConstructor().newInstance();
		System.out.println(obj);
		
		test.set(obj, 200);
		System.out.println(obj);
		id.setAccessible(true);
		name.setAccessible(true);
		id.set(obj, 1);
		name.set(obj, "张三");
		System.out.println(obj);
		System.out.println(test.get(obj));
		System.out.println(id.get(obj));
		System.out.println(name.get(obj));
	
	}
}
6. 给予暴力反射操作权限
void setAccessible(boolean flag);
	给予通过【暴力反射】获取Constructor,Method ,Field 私有化修饰内容操作权限,flag = true 即可操作。

getDeclaredField(“name”);

	/*
	 * 获取指定的非私有化成员变量
	 * */
	Field test = cls.getField("test");
	
	
	//实例化当前 Class对应类型对象 ,实例化 Person 对象
	
	Object obj = cls.getConstructor().newInstance();
	System.out.println(obj);
	
	test.set(obj, 200);
	System.out.println(obj);
	id.setAccessible(true);
	name.setAccessible(true);
	id.set(obj, 1);
	name.set(obj, "张三");
	System.out.println(obj);
	System.out.println(test.get(obj));
	System.out.println(id.get(obj));
	System.out.println(name.get(obj));

}

}


#### 6. 给予暴力反射操作权限

void setAccessible(boolean flag);
给予通过【暴力反射】获取Constructor,Method ,Field 私有化修饰内容操作权限,flag = true 即可操作。






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值