类的加载
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
- 加载:就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
- 连接:
验证 : 是否有正确的内部结构,并和其他类协调一致
准备 : 负责为类的静态成员分配内存,并设置默认初始化值
解析: 把类中的符号引用转换为直接引用 - 初始化:顺序,父类静态变量–> 父类静态代码块–> 子类静态变量–> 子类静态代码块 -->父类非静态变量–> 父类非静态代码块–> 父类构造函数–> 子类非静态变量–> 子类非静态代码块–> 子类构造函数
类加载器
类加载器的作用是负责将类加载进内存,并为之生成对应的class对象
分类:
- Bootstrap ClassLoader 根类加载器,也被称为引导类加载器,负责Java核心类的加载比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
- Extension ClassLoader 扩展类加载器,负责JRE的扩展目录中jar包的加载。在JDK中JRE的lib目录下ext目录
- Sysetm ClassLoader 系统类加载器,负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
反射
java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法和属性,这样动态获取类的信息一级动态调用对象的方法的功能称为java的反射机制。
想要剖析一个类,必须西安获取这个类的字节码对文件象,获取 字节码文件对象的方式有三种:
- a: 第一种通过Object类中的getClass方法
- b: 通过静态属性(class属性)
- c: 通过Class类中的一个静态方法:
-public static Class forName(String className):
-className: 这个表示的是一个类对应的全类名(就是需要加上包名)
//方式1. 通过Object类中的getClass方法
Student student = new Student(); //Student.class
//Class 类的实例表示正在运行的 Java 应用程序中的类和接口
Class clazz = student.getClass();
//方式2.任何一个类,都有一个 class属性,通过这个属性就可以获取到该类的字节码文件对象
Class<Student> studentClass = Student.class;
System.out.println(clazz==studentClass);
//获取一个类的字节码文件对象的方式3
//全路径:一个类带有包名 全类名:带有包名的类
Class<?> aClass = Class.forName("org.westos.demo.Student");
通过反射获取构造方法
A:获取所有构造方法
public Constructor<?>[] getConstructors() 获取所有的构造方法不包含私有的
public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法 包括私有的
B:获取单个构造方法
public Constructor getConstructor(Class<?>… parameterTypes) 获取单个的构造方法 不包含私有的
public Constructor getDeclaredConstructor(Class<?>… parameterTypes) 获取单个的构造方法包含私有的
newInstance(Object… initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("day0802.Student");//拿到类的字节码文件对象
//获取公共构造方法对象
Constructor<?>[] constructors1 = aClass.getConstructors();
for (Constructor<?> constructor : constructors1) {
System.out.println(constructor);
}
System.out.println();
//获取所有构造方法对象
Constructor<?>[] constructors = aClass.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println();
//空参构造
Constructor<?> constructor = aClass.getConstructor();
Object o = constructor.newInstance();
//有参构造
Constructor<?> constructor1 = aClass.getConstructor(String.class);
Object 张三 = constructor1.newInstance("张三");
Constructor<?> constructor2 = aClass.getConstructor(String.class, int.class);
Object 李四 = constructor2.newInstance("李四", 23);
//私有有参构造
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class);
declaredConstructor.setAccessible(true);//取消权限检查
Object o1 = declaredConstructor.newInstance(24);
System.out.println(o==张三);
}
}
class Student{
public Student(){
System.out.println("空参构造");
}
public Student(String name){
System.out.println("有参构造"+name);
}
public Student(String name,int age){
System.out.println("有参构造2"+name+age);
}
private Student(int age){
System.out.println("私有有参构造");
}
public void show(){
System.out.println("构造方法");
}
}
通过反射获取成员变量
A:获取所有成员变量
public Field[] getFields() 获取所有的成员变量包含从父类继承过来的
public Field[] getDeclaredFields() 获取所有的成员变量 包含私有的 也包含从父类继承过来的成员变量
B:获取单个成员变量
public Field getField(String name) 获取单个公共字段对象
public Field getDeclaredField(String name) 获取单个私有字段对象
public class Student {
public String name;
public int age;
private double money;
public Student() {
}
}
public class MyTest {
public static void main(String[] args) throws NoSuchFieldException {
//Field 字段类型
Class<Student> studentClass = Student.class;
//获取所有的公共字段对象
Field[] fields = studentClass.getFields();
for (Field field : fields) {
System.out.println(field.toString());
}
System.out.println("----------------------");
//获取所有的字段对象,包括私有的
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName());
}
//获取单个公共字段对象
Field name = studentClass.getField("name");
System.out.println(name);
//获取单个的私有字段对象
Field money = studentClass.getDeclaredField("money");
System.out.println(money);
}
}
C: 给字段赋值
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("org.westos.demo4.Student");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object object= declaredConstructor.newInstance();
//以前我们给字段赋值
//Student student = new Student();
//student.name="张三";
Field name = aClass.getField("name");
name.set(object,"张三");
Object o = name.get(object);
System.out.println(o);
}
通过反射获取成员方法
A:获取所有成员方法
public Method[] getMethods() //获取所有的公共的成员方法不包含私有的 包含从父类继承过来的过来的公共方法
public Method[] getDeclaredMethods()//获取自己的所有成员方法 包含私有的
B:获取单个成员方法
//参数1: 方法名称 参数2:方法行参的class 对象
public Method getMethod(String name,Class<?>… parameterTypes) //获取单个的方法 不包含私有的
public Method getDeclaredMethod(String name,Class<?>… parameterTypes) 获取单个方法包括私有的
invoke(Object obj, Object… args) 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
public class MyTest2 {
public static void main(String[] args) throws Exception{
Class<?> aClass = Class.forName("org.westos.demo5.Student");
Constructor<?> constructor = aClass.getDeclaredConstructor();
constructor.setAccessible(true);
Student obj = (Student) constructor.newInstance();
// obj.show();
//获取方法对象
Method show = aClass.getMethod("show");
//通过反射的反射,来让方法执行invoke()让方法执行
show.invoke(obj);
System.out.println("---------------------");
Method test = aClass.getMethod("test", String.class, int.class);
//参1:该类的对象,参数2:传给方法的形参要的值
test.invoke(obj,"zhangsan",23);
Method hehe = aClass.getMethod("hehe", double.class);
Object invoke = hehe.invoke(obj, 3.2);
System.out.println(invoke);
System.out.println("-----------------------------");
//通过反射,掉私有的方法
Method haha = aClass.getDeclaredMethod("haha");
haha.setAccessible(true);//调用私有方法,取消权限检查
Object invoke1 = haha.invoke(obj);
System.out.println(invoke1);
}
}
public class Student {
private Student() {
}
public void show(){
System.out.println("空参数的show方法执行了");
}
public void test(String name,int age) {
System.out.println("两个参数的 test方法执行了"+name+"==="+age);
}
public String hehe(double num) {
System.out.println("有返回值的方法执行了"+num);
return "呵呵";
}
private String haha(){
System.out.println("私有的方法执行了");
return "哈哈";
}
}