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 即可操作。