反射
1.类加载器
当程序需要使用某个类的时候,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化,如果不出现意外,JVM将会持续完成这三个步骤所以也把这三个步骤统称为类的加载或者类的初始化
类的加载:
就是将Class文件读入内存,并为之创建一个java.long.Class对象
任何类被使用的时候,系统都会为之创建一个java.lang.Class对象
类的连接:
验证阶段: 用于检验被加载的类是否有正确的内部结构,并且和其它类协调一致
准备阶段:负责为类的类变量分配内存,并设置默认初始化值
解释阶段:将类的二进制数据中的符号引用替换为直接引用
类的初始化:
在该阶段,主要就是对类变量进行初始化
类的初始化步骤
假如类还未被加载和连接,则程序先加载并连接该类
假如该类的直接父类还未被初始化,则先初始化其父类
假如类中有初始化语句,则系统依次执行这些初始化语句
注意:在执行第二个步骤的时候,系统对直接父类的初始化步骤也遵循初始化步骤1-3
类的初始化时机:
创建类的实例
调用类的类方法
访问类或接口的类变量或者为该类变量赋值
使用反射方法来强制创建某个类或接口对应的java.long.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类
2.类加载器
类加载器的作用:
负责将.class文件加载到内存中,并为之生成对应的java.long.Class对象
虽然我们不用过度关心类的加载机制,但是了解这个机制我们可以更好的理解程序的运行
JVM 的类加载机制
全盘负责:就是当一个类加载器负责加载某个Class 的时候,该Class所依赖和引用的其它Class也将由该类加载器负责载入,除非显式使用另一个类加载器来载入
父类委托:就是当一个类加载器负责加载某个class时,先让父类加载器试图加载该Class,只有父类加载器无法加载该类的时候才尝试从自己的类路径中加载该类
缓存机制:保证所有加载过的Class都会被缓存,当程序需要使用某个class对象的时候,类加载器先从缓存区搜索该class,只有当缓存区中不存在该class对象的时候,系统才会读取该类对应的二进制数据,并将其转化成class对象,存储到缓存区
ClassLoader : 是负责加载类的对象
Java运行的时候有以下内置类加载器:
Bootstrap class loader:他是虚拟机的内置加载器,通常表示为null,并且没有父null
Planform class loader: 平台类加载器可以看到所有的平台类,平台类包括平台类加载器或其祖先定义的Java SE平台API,其实现类和JDK特定的运行时类
System class loader:它也被称为应用程序类加载器,与平台加载器不同。系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类
类加载器的继承关系:System 的父加载器为Platform,而Platform的父加载器为bootstrap
ClassLoader 中的两个方法:
static ClassLoader getSystemLoader():返回用于委派的系统类加载器
ClassLoader getParent():返回父类加载器进行委派
3.反射
反射概念:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BIoSk4DG-1663809984766)(C:\Users\29304\AppData\Roaming\Typora\typora-user-images\image-20220921093947202.png)]
通过class来使用成员变量,构造方法成员方法
java反射机制:是指在运行时去获取一个类的变量和方法信息,然后通过获取到的信息来创建对象,调用方法的一种机制。
由于这种动态性,可以极大地增强程序的灵活性,程序不用在编译期就完成确定,在运行期间仍可以拓展
4.获取class类的对象
我们想要去通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为class类型的对象这里我们提供三种方式来获取class类型的对象
使用类的属性来获取该类对应class对象 举例:Student.class将会返回Student类对应的Class对象
调用对象的getClass()方法,返回该对象所属类对应的class对象 该方法是Object类中的方法,所有的java对象都可以调用该方法
使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径
package com.company;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException {
Class<Student> c = Student.class;
System.out.println(c);
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c == c3);
Class<?> c4 = Class.forName("com.company.Student");
System.out.println(c == c4);
}
}
三种方式获得类的字节码文件对象,第一种方式是最方便的,最后的方式可以把字符串的数据配置到一个配置文件中这样可以随时修改配置文件的内容,灵活性是最高的
练习:
package practicce1;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取class对象
Class<?> c = Class.forName("com.company.Student");
Constructor<?> con = c.getConstructor(String.class, int.class, String.class);
//基本数据类型也可以通过.class得到对应的class类型
Object obj = con.newInstance("林明卿", 30, "西安");
System.out.println(obj);
}
}
首先通过Class.forName得到Class对象c 然后c调用getContructor得到构造方法对象con 最后通过构造方法对象调用newInstance生成了一个对象
基本数据类型也可以通过.class得到对应的class类型
四种整数类型(byte、short、int、long) 两种浮点数类型(float、double) 一种字符类型(char) 一种布尔类型(boolean)
引用数据类型:
类(class) 接口(interface) 数组
package practicce1;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> c1 = Class.forName("com.company.Student");
//获取一个参数的构造方法对象(是私有方法)
Constructor<?> con = c1.getDeclaredConstructor(String.class);
//暴力反射
//public void setAccessible (boolean flag);值为true,取消访问检查
con.setAccessible(true);
Object obj = con.newInstance("林青霞");
System.out.println(obj);
//非法的访问异常IllegalAccessException:
}
}
public void setAccessible (boolean flag);值为true,取消访问检查(用于私有方法和变量)
反射获取成员变量并使用
package practicce1;
import com.company.Student;
import java.io.File;
import java.io.FileDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取class对象
Class<?> c = Class.forName("com.company.Student");
Field[] fields = c.getFields();
for (Field filed: fields){
System.out.println(filed);
//输出的公共的成员变量
}
Field[] field = c.getDeclaredFields();
for (Field filedss: field){
System.out.print(filedss);
//输出的全部的成员变量
}
System.out.println("===============================");
//单个的成员变量
Field address = c.getField("address");
//获取无参构造方法创建对象
Constructor<?> con = c.getConstructor();
Object o = con.newInstance();
//o.address = "西安";
address.set(o,"西安");
//给o的成员变量address赋值为西安 adderss对应的是Field address = c.getField("address");里的adress所以相当于给这里的aderss赋值
System.out.println(o);
/*Student s = new Student();
s.address = "西安";
System.out.println(s);*/
}
}
首先获取class对象c然后通过c按照指定的成员变量得到成员变量对象,然后通过成员变量对象调用set方法给成员对象赋值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UZofKFi2-1663809984768)(C:\Users\29304\AppData\Roaming\Typora\typora-user-images\image-20220921112419778.png)]
练习
package practicce1;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Demo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//获取class对象
Class<?> c = Class.forName("com.company.Student");
//Student s = new Student();
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj);
//Student{ name = null,age = 0,address= null}(输出结果)
//s.name = “林青霞”;
Field namefield = c.getDeclaredField("name");//IllegalAccessException(非法访问异常)
//需要用这个来解开
namefield.setAccessible(true);
namefield.set(obj, "林青霞");
System.out.println(obj);
// Field namefield = c.getField("name"); NoSuchFieldException(找不到变量)不能用
//age = 3o
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj, 30);
System.out.println(obj);
//西安
Field addressField = c.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj,"西安");
System.out.println(obj);
}
}
反射获取成员方法并使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z1gJGcqc-1663809984768)(反射.assets/image-20220921150711455.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GITljVOH-1663809984769)(反射.assets/image-20220921150739625.png)]
package practicce1;
import com.company.Student;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo5 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取class对象
Class<?> c = Class.forName("com.company.Student");
//获取成员方法
// 公共方法 返回的由该class对象表示的类或者接口的所有的公共方法,包括由类和接口声明的以及从超类和超级接口继承的类
//Method[] method = c.getMethods();
//私有方法 只有本类的
Method[] method = c.getDeclaredMethods();
for (Method methods:method){
System.out.println(methods);
}
System.out.println("======================");
//获取单个方法
//Method
//getDeclaredMethod()
Method m= c.getMethod("method1");
//获取无参构造方法创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
//调用对象m方法
m.invoke(obj);
/*Student s = new Student();
s.method1(); */
}
}
练习
package practicce1;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Demo6 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("com.company.Student");
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
Method method1 = c.getMethod("method1");
method1.invoke(obj);
Method method2 = c.getMethod("method2", String.class);
method2.invoke(obj,"林青霞");
Method method3 = c.getMethod("method3", String.class, int.class);
Object o = method3.invoke(obj, "lin", 23);
System.out.println(o);
//Method m4 = c.getMethod("function");//NoSuchMethodException
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);
}
}
反射练习
练习1 : 假如我有一个ArrayList集合,现在我想在这个集合中添加一个字符串数据,如何实现
package practicce1;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Demo7 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList<Integer> array = new ArrayList<Integer>();
/* array.add(10);
array.add(20);
array.add("hello");*/
Class<? extends ArrayList> c = array.getClass();
Method m = c.getMethod("add",Object.class);
m.invoke(array,"hello");
m.invoke(array,"world");
m.invoke(array,"java");
System.out.println(array);
}
}
练习2 : 通过配置文件运行类中的方法
package practicce1;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class Demo8 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
/* Stu s = new Stu();
s.study();*/
/*Tea t = new Tea();
t.tea();*/
/*
class.txt
className=xx(类)
methodName =xx(方法)
*/
//加载数据
Properties prop = new Properties();
FileReader fr = new FileReader("D:\\Lianxi\\Level15\\src\\practicce1\\class.txt");
prop.load(fr);
fr.close();
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
//通过反射使用
Class<?> c = Class.forName(className);
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
Method method = c.getMethod(methodName);
method.invoke(obj);
}
}
i\Level15\src\practicce1\class.txt");
prop.load(fr);
fr.close();
String className = prop.getProperty(“className”);
String methodName = prop.getProperty(“methodName”);
//通过反射使用
Class<?> c = Class.forName(className);
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
Method method = c.getMethod(methodName);
method.invoke(obj);
}
}