1.类加载器
1.1类加载:
当程序要使用某个类时,如果该类还没有被加载到内存中,系统会通过类的加载,类的连接,类的初始化这三个步骤对类进行初始化,如果不出现意外,JVM会连续完成这三个步骤,所以有时候会把这三个步骤称为类的加载或类的初始化
类的加载
- 就是将Class文件读入内存,并位置创建一个java.lang.Class对象
- 任何类被使用时,系统都会为之创建一个java.lang.Class对象
类的连接
- 验证阶段:用于检验被加载的类是否有正确的内部结构,并和其它类协调一致
- 准备阶段:负责为类的类变量分配内存,并设置初始化值
- 解析阶段:将类中的二进制符号引用替换为直接引用
类的初始化
- 在该阶段主要是对类变量进行初始化
类的初始化步骤
- 假如类还未被加载和连接,则程序先加载并连接该类
- 假如该类的直接父类还未被初始化,则先初始化其直接父类
- 假如类中有初始化语句,系统依次执行这些初始化语句
类的初始化时机
- 创建类的实例
- 调用类的类方法
- 访问类或者接口的类变量,或者为该类的变量赋值
- 使用反射方式强制创建某个类或接口对应的java.lang.Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某给类的子类
1.2类加载器
类加载的作用
- 负责将.class文件加载到内存,并为之生成对应的java.lang.Class对象
JVM的类加载机制
- 全盘负责:就是类加载器加载某一个Class时,该Class所依赖的和引用的其他Class也将由该加载器负责载入
- 父类委托:当类加载器加载某一个Class时,先让其父类加载器视图加载该Class,只有父类加载器无法加载时,才尝试从自己的类路径加载该类
- 缓存机制:保证所有加载过的Class都会被缓存,当程序使用某个Class对象时,类加载器先从缓存区搜索该Class,只有缓存区不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存储到缓存区
类加载器可查看相关API文档:
2.反射
2.1反射的概述
Java反射机制:是指在运行时获取一个类的变量和方法信息,然后通过获取的信息来创建对象,调用方法的一种机制,这种动态性极大的增强了程序的灵活性,程序不用在编译器就完成确定,在运行期仍然可以扩展
2.2获取Class对象的三种方式
package com.Reflect_01;
public class Student {
//成员变量:一个私有,一个默认,一个公共
private String name;
int age;
public String address;
//构造方法:一个私有,一个默认,两个公共
public Student() {
}
private Student(String name) {
this.name = name;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
//成员方法:一个私有,四个公共
private void function(){
System.out.println("function");
}
public void method1(){
System.out.println("method");
}
public void method2(String s){
System.out.println("method"+s);
}
public String method3(String s, int i){
return s+","+i;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
package com.Reflect_01;
/**
* 获取Class对象的三种方式
*/
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
//使用class属性获取该类对应的class对象
Class<Student> c1 = Student.class;
System.out.println(c1); //class com.Reflect_01.Student
Class<Student> c2= Student.class;
System.out.println(c2==c2); //true
//调用对象的getClass方法,返回该对象所属类的Class对象
Student s=new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1==c3); //true
//使用Class类中的静态方法forName(String className)
Class<?> c4 = Class.forName("com.Reflect_01.Student");
System.out.println(c1==c4); //true
}
}
反射获取构造方法并使用:
package com.Reflect_01;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 反射获取构造方法并使用
*/
public class ReflectDemo01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> c = Class.forName("com.Reflect_01.Student");
//使用getConstructors()方法获取构造方法,值是一个数组(只能获取公共的构造方法)
Constructor<?>[] cons = c.getConstructors();
for (Constructor<?> con : cons) {
System.out.println(con);
}
//使用getConstructor()方法获取构造方法,值时单个(只能获取公共的构造方法)
//获取单个构造方法对象
Constructor<?> con = c.getConstructor(String.class,int.class,String.class);
//(反射)通过构造方法对象里面的方法来创建对象
Object obj = con.newInstance("张三",18,"上海");
System.out.println("使用公共的构造方法创建对象:"+obj);
//使用getDeclaredConstructor()获取私有的构造方法
Constructor<?> con1 = c.getDeclaredConstructor(String.class);
//因私有构造方法不能创建对象,所以在此处使用暴力反射
//设置值为true,取消访问检查
con1.setAccessible(true);
Object obj1 = con1.newInstance("李四");
System.out.println("使用私有构造方法创建对象:"+obj1);
}
}
反射获取成员变量并使用:
package com.Reflect_01;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
/**
* 反射获取成员变量并使用
*/
public class ReflectDemo02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//获取Class对象
Class<?> c = Class.forName("com.Reflect_01.Student");
//获取该类无参构造方法
Constructor<?> con = c.getConstructor();
//获取无参构造方法对象
Object obj = con.newInstance();
//根据参数获取成员变量
Field nameField = c.getDeclaredField("name");
//暴力反射
nameField.setAccessible(true);
nameField.set(obj,"张三");
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj,18);
Field addressField = c.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj,"上海");
System.out.println(obj);
}
}
反射获取成员方法并使用:
package com.Reflect_01;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 反射获取成员方法并使用
*/
public class ReflectDemo03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//获取Class对象
Class<?> c = Class.forName("com.Reflect_01.Student");
/*无参成员方法的调用*/
//获取成员方法对象(私有方法getDeclaredMethod)
Method m1 = c.getMethod("method1");
//获取无参构造方法创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
//成员方法对象调用invoke()方法,传递无参构造方法对象作为参数
m1.invoke(obj); //此处表式无参构造对象obj调用成员方法对象m1
/*有参成员方法的调用*/
//获取成员方法对象
Method m2 = c.getMethod("method2", String.class);
//无参构造方法对象调用成员方法对象,需给定一个参数
m2.invoke(obj,"张三");
/*有参数有返回值成员方法的调用*/
//获取成员方法对象
Method m3 = c.getMethod("method3", String.class, int.class);
//无参构造方法对象调用成员方法对象,需给定两个参数
Object o = m3.invoke(obj, "lisi", 18);
//将返回值打印
System.out.println(o);
}
}
通过反射向Integer类型的ArrayList集合中添加字符串类型的参数:
package com.Reflect_01;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* 通过反射向Integer类型的ArrayList集合中添加字符串类型的参数
*/
public class ReflectDemo04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//创建集合对象
ArrayList<Integer> array = new ArrayList<>();
//获取集合的字节码文件对象
Class<? extends ArrayList> c = array.getClass();
//通过反射获取成员方法对象,给出参数
Method m = c.getMethod("add", Object.class);
//调用invoke()方法
m.invoke(array,"hello");
m.invoke(array,"world");
System.out.println(array);
//打印结果为[hello, world]
}
}
通过配置文件运行类中的方法:
package com.Reflect;
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 ReflectTest {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//加载数据
Properties prop = new Properties();
FileReader fr = new FileReader("D:\\WorkSpace\\Spring\\Reflect\\class.txt");
prop.load(fr);
fr.close();
//通过类的名称获取类的全路径
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
//通过反射获取Student类
Class<?> c = Class.forName(className);
//获取类的构造方法
Constructor<?> con = c.getConstructor();
//获取构造方法对象
Object obj = con.newInstance();
//获取成员方法对象
Method m = c.getMethod(methodName);
//调用成员方法
m.invoke(obj);
}
}
走的再远,也别忘回头看看!
2019-12-14,今天自习小回顾一下Java底层的反射机制.