反射
一、类加载器
1.1类加载
类加载(类初始化化):
不出意外JVM连续完成以下三步骤:
类的加载
1.class文件读入内存,建立一个java.lang.Class对象
2.任何类被使用时,系统都会建立一个java.lang.Class对象
类的连接
验证阶段: 检验类的内部结构 和其他类协调一致
准备阶段:为类变量分配内存,设置默认初始化值
解析阶段:将类的二进制数据中的符号引用替换为直接引用
类的初始化
类变量初始化步骤
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WWjMxRvG-1616143801437)(C:\Users\wcy\AppData\Roaming\Typora\typora-user-images\image-20210319131310436.png)]
类变量初始化时机(首次使用)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WfEgDVdT-1616143801441)(C:\Users\wcy\AppData\Roaming\Typora\typora-user-images\image-20210319131430909.png)]
1.2类加载器
负责把.class文件加载到内存中 生成对应的java.lang.Class对象
JVM的类加载机制:
全盘负责:加载某类 该类依赖的引用和依赖的其他类 也该由这个类加载器负责(除非说明是别的类加载器)
父类委托:加载某类,先让父类加载器试图加载此类,无法加载,才尝试用自己的类路径加载
缓存机制:加载过的类都放到缓存区,缓存区没有,再读取二进制数据,并转换为class对象存到缓存区。
Bootstrap -> Platform -> System (父—>子)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYZ0VnOU-1616143801443)(C:\Users\wcy\AppData\Roaming\Typora\typora-user-images\image-20210319132656894.png)]
-
-
ClassLoader
getParent()
返回父类加载器进行委派。
-
-
-
static ClassLoader
getSystemClassLoader()
返回用于委派的系统类加载器。
-
二、反射
2.1 反射概述
Java反射机制:是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展
2.2 获取Class类的对象
我们要想通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型的对象这里我们提供三种方式获取Class类型的对象
1.使用类的class属性来获取该类对应的Class对象。举例: Student.class将会返回Student类对应的Class对象
2.调用对象的getClass()方法,返回该对象所属类对应的Class对象,该方法是Object类中的方法,所有的Java对象都可以调用该方法
3.使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径
Class<Student> c1 = Student.class;
System.out.println(c1);//class m3d19Reflect.Student
Class<Student> c2 = Student.class;
System.out.println(c1==c2);//true
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1==c3);//true
Class<?> c4 = Class.forName("m3d19Reflect.Student");
System.out.println(c1==c4);//true
2.3反射获取构造方法
先获取class对象 再用
getConstructors 返回所有pubic构造方法对象数组
getDeclaredConstructors返回所有构造方法对象数组
getConstructor 返回指定pubic构造方法对象(参数为构造方法参数类型.class(基本类型也可以.class))
getDeclaredConstructor返回指定构造方法对象
Class<?> c = Class.forName("m3d19Reflect.Student");
//获取构造方法并使用
//getConstructors()(对象数组)(public构造方法)
//返回包含一个数组 Constructor对象反射由此表示的类的所有公共构造类对象。
Constructor<?>[] cConstructors = c.getConstructors();
//返回所有构造方法(对象数组)
Constructor<?>[] cons = c.getDeclaredConstructors();
//返回一个指定构造函数对象
Constructor<?> c1 = c.getConstructor(String.class,int.class,String.class);
//构造函数实例
Object s = c1.newInstance("张三",2,"abc");
System.out.println(s);
//正常不能对private构造方法创建对象
//暴力反射(通过反射 Constructor方法setAccessible使用私有构造方法创建对象)
Constructor<?> dc1 = c.getDeclaredConstructor(String.class);
dc1.setAccessible(true);//取消访问检查
Object s2 = dc1.newInstance("小王");
System.out.println(s2);
2.4反射获取成员变量
先获取class对象 再用
getFields 返回所有pubic成员变量对象数组
getDeclareFields 返回所有成员变量对象数组
getField 返回指定pubic成员变量对象(参数:成员变量名称(字符串))
getDeclareField 返回指定成员变量对象
调用.set方法为对象赋值
成员变量对象.set(对象,值)
Class<?> c = Class.forName("m3d19Reflect.Student");
Field f = c.getField("address");//获取成员变量对象
Field df = c.getDeclaredField("name");//可以获取私有的
df.setAccessible(true);//取消访问检查
Constructor<?> cCon = c.getConstructor();
Object o = cCon.newInstance();//反射创建对象
f.set(o,"西安");//通过反射为对象赋值
System.out.println(o);
2.5反射获取成员方法
先获取class对象 再用
getMethods
getDeclareMethods
getMethod (参数:方法名称(字符串))
getDeclareMethod
方法对象.invoke(对象,方法参数)
Class<?> c = Class.forName("m3d19Reflect.Student");
Method[] methods = c.getMethods();//公共方法(包括继承来的)
Method[] declaredMethods = c.getDeclaredMethods();//所有方法 不包含继承的
Method method = c.getMethod("method");
Constructor<?> con = c.getConstructor();
Object o = con.newInstance();
method.invoke(o);//反射使用成员方法
Method method1 = c.getDeclaredMethod("function");
method1.setAccessible(true);//私有方法 取消访问检查
method1.invoke(o);
2.6通过配置文件运行类中的方法
Properties prop = new Properties();
FileReader fr = new FileReader("01\\src\\m3d19Reflect\\class.txt");
prop.load(fr);
fr.close();
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
Class<?> c = Class.forName(className);
Method method = c.getMethod(methodName,String.class);
Constructor<?> con = c.getConstructor();
Object o = con.newInstance();
method.invoke(o,"小彭");
注:Properties类的使用
Java 语言的配置文件所使用的类
读入:
.load(输入流)
以key=value 的 键值对的形式进行存储值。 key值不能重复(继承了hashtable类)
方法.getProperty(key) 返回value
ect o = con.newInstance();
method.invoke(o,“小彭”);
### 注:Properties类的使用
Java 语言的配置文件所使用的类
读入:
.load(输入流)
以key=value 的 键值对的形式进行存储值。 key值不能重复(继承了hashtable类)
方法.getProperty(key) 返回value