- dom4j下载地址 https://dom4j.github.io
- 如果下载不了,推荐使用谷歌浏览器打开
类的加载时机
-
当程序要使用某个类时,如果该类还未被加载到内存中
-
系统会通过加载,连接,初始化三步来实现对这个类进行初始化
- 加载
就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。 - 连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值 - 初始化
初始化成员变量等等
- 加载
-
加载时机
- 创建类的实例
- 访问类的静态变量,或者为静态变量赋值
- 调用类的静态方法
- 初始化某个类的子类
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
类加载器
-
什么是类加载器classLoader
- 负责将.class文件加载到内存中,并为之生成对应的Class对象。
- 虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
-
类加载器分类
- 根类加载器
- 也被称为引导类加载器,负责Java核心类的加载
- 比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
- 扩展类加载器
- 负责JRE的扩展目录中jar包的加载。
- 在JDK中JRE的lib目录下ext目录
- 系统类加载器
- 负责在JVM启动时加载来自java命令的class文件
- 以及classpath环境变量所指定的jar包和类路径
- 根类加载器
什么是反射
-
创建一个对象的三个阶段
- 源文件阶段 .java的文件
- 字节码阶段 .class
- 创建对象阶段 new 对象名称
-
内省
- 在运行时能够获取JavaBean当中的属性名称和get与set方法
-
反射
- JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
- 对于任意一个对象,都能够调用它的任意一个方法和属性;
- 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
- 想要使用反射,就必须得要获取字节码文件
-
获取字节码文件
- Object类的getClass()方法
- 判断两个对象是否是同一个字节码文件
- 静态属性class
- 当作静态方法的锁对象
- Class类中静态方法forName()
- 读取配置文件
- 实例
输出//Person类 public class Person { public String name="coco"; private String age = "10"; public void show() { System.out.println(name+age); } } @Test //.class文件的获取 Class<?> class1 = Class.forName("com.coco.domain.Person"); System.out.println("-Class类中静态方发forName()"+class1); Person person = new Person(); Class<? extends Person> class2 = person.getClass(); System.out.println("-Object类的getClass()方法"+class2); Class<Person> class3 = Person.class; System.out.println("-静态属性Class"+class3);
-Class类中静态方发forName()class com.coco.domain.Person
-Object类的getClass()方法class com.coco.domain.Person
-静态属性Classclass com.coco.domain.Person
- Object类的getClass()方法
通过字节码创建对象
-
通过无参构造创建对象
-
获取字节码
-
调用字节码的newInstance()方法
-
实例
Person类 public class Person { public String name="coco"; private String age = "10"; public void show() { System.out.println(name+age); } } @Test //获取字节码.class Class<?> clazz = Class.forName("com.coco.domain.Person"); //通过字节码创建对象 Person per = (Person)clazz.newInstance(); per.show();
输出
coco10
-
-
通过有参构造创建对象
- 获取字节码的构造器
- clazz.getConstructor(type.class)
- 因为在反射阶段操作的都是字节码,不知道具体的类型,只有在创建对象的时候才去给实际参数
- 通过构造器创建对象
- 调用构造器的newInstance方法并传入参数
- 实例
//Person类 public class Person { public String name="coco"; private String age = "10"; public Person(String name) { System.out.println(name); } public void show() { System.out.println(name+age); } } @Test //获取字节码.class Class<?> clazz = Class.forName("com.coco.domain.Person"); //通过字节码创建构造器,然后用构造器创建对象 Constructor c = clazz.getConstructor(String.class); Person per = (Person)c.newInstance("MoMo"); per.show();
- 获取字节码的构造器
获取字段
-
获取公共的字段
- 实例
输出//Person类 public class Person { public String name="coco"; private String age = "10"; public void show() { System.out.println(name+age); } } @Test //获取字节码.class Class<?> clazz = Class.forName("com.coco.domain.Person"); Person per = (Person)clazz.newInstance(); Field f = clazz.getField("name"); f.set(per, "ZoZo"); per.show();
ZoZo10
- 实例
-
获取私有字段
- 实例
输出//Person类 public class Person { public String name="coco"; private String age = "10"; public void show() { System.out.println(name+age); } } @Test //获取字节码.class Class<?> clazz = Class.forName("com.coco.domain.Person"); Person per = (Person)clazz.newInstance(); //暴力反射获取字段 Field f = clazz.getDeclaredField("age"); //去除私有属性 f.setAccessible(true); f.set(per, "99"); per.show();
coco99
- 实例
获取方法
- 实例
输出//Person类 public class Person { public String name="coco"; private String age = "10"; public void show() { System.out.println(name+age); } private void eat(String food) { System.out.println(food); } } @Test //获取字节码.class Class<?> clazz = Class.forName("com.coco.domain.Person"); //创建对象 Person per = (Person)clazz.newInstance(); //获取一个无参数公有的方法 Method show = clazz.getMethod("show"); //运行方法 show.invoke(per); //获取一个私有的带参数的方法 Method eat = clazz.getDeclaredMethod("eat", String.class); eat.setAccessible(true); eat.invoke(per, "shi");
coco10
shi
越过数组泛型检测
-
数组如果定义好了泛型就不能添加泛型以外的类型
-
可以通过反射来去实现添加以外的类型
-
在一个Integer泛型的数组当中添加字符串类型
-
实例
ArrayList<Integer> list = new ArrayList<>(); list.add(1); list.add(2); System.out.println(list); Class<?> classList = Class.forName("java.util.ArrayList"); Method m = classList.getMethod("add", Object.class); m.invoke(list, "CPKL"); System.out.println(list);
Servlet创建过程
注意事项
- 需要dom4j的jar包
- dom4j下载地址 https://dom4j.github.io
web.xml内容
<?xml version="1.0" encoding="UTF-8"?>
<persion>
<name>com.coco.domain.Person</name>
</persion>
@Test
//读取xml文件
SAXReader reader = new SAXReader();
Document read = reader.read("src/web.xml");
System.out.println(read);
//获取根元素
Element element = read.getRootElement();
//获取根部元素下的name标签
Element element2 = element.element("name");
//获取标签的内容
String text = element2.getText();
System.out.println(text);
//用类的反射机制创建类
Class<?> class1 = Class.forName(text);
Person object = (Person)class1.newInstance();
object.show();
输出
org.dom4j.tree.DefaultDocument@73a28541 [Document: name src/web.xml]
com.coco.domain.Person
coco10