类加载过程和反射机制使用详解

1.类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

加载

就是指将class文件读入内存,并为之创建一个Class对象。
任何类被使用时系统都会建立一个Class对象。

连接

验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值 static{}语句块
解析 将类的二进制数据中的符号引用替换为直接引用

初始化类型

创建类的实例
访问类的静态变量,或者为静态变量赋值
调用类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类

2.类加载器

负责将.class文件加载到内在中,并为之生成对应的Class对象。

3.类加载器的组成

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包和类路径
自己写的类使用此加载器执行

4.反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

反射代码详细解析:

测试类

package com.xiaoqiang;

import static org.junit.Assert.*;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.junit.Test;

public class StudentReflex {

    // 获取Class类对象的三种方法
    @Test
    public void test1() throws Exception {

        Class c1 = Student.class;
        Class c2 = new Student().getClass();
        Class c3 = Class.forName("com.xiaoqiang.Student");
        System.out.println(c1.equals(c2));// true
        System.out.println(c1.equals(c3));// true
        /*
         * 推荐使用第三种,可以遵循避开原则, 将字符串存储在配置文件中 读取配置文件
         */
    }

    // 构造方法获取及使用
    @Test
    public void test2() throws Exception {
        Class c = Class.forName("com.xiaoqiang.Student");
        Constructor[] cons1 = c.getConstructors();
        // 获取所有公有构造方法

        for (Constructor constructor : cons1) {
            System.out.println(constructor);
        }

        Constructor[] cons = c.getDeclaredConstructors();
        // 获取所有构造方法

        for (Constructor constructor : cons) {
            System.out.println(constructor);
        }

        // 通过反射调用私有构造方法
        Constructor con = c.getDeclaredConstructor(String.class, String.class);
        // 若调用非公有的构造方法需要设置安全管理器
        con.setAccessible(true);

        Object obj = con.newInstance("小强", "男");
        System.out.println(obj);
    }
    //属性的获取及设置
    @Test
    public void test3() throws Exception {
        Class c = Class.forName("com.xiaoqiang.Student");
        Object obj = c.newInstance();
        Field[] fields1 = c.getFields();
        //获取公有的属性
        for (Field field : fields1) {
            System.out.println(field);
        }
        Field[] fields = c.getDeclaredFields();
        //获取所有属性
        for (Field field : fields) {
            System.out.println(field);
        }
        //加上 Declared 可访问私有属性
        Field fieldName = c.getDeclaredField("name");
        Field fieldSex = c.getDeclaredField("sex");
        Field fieldAge = c.getDeclaredField("age");
        fieldName.set(obj, "小强");
        fieldSex.set(obj, "男");
        fieldAge.setAccessible(true);
        //设置安全管理器强制访问

        fieldAge.set(obj, 18);
        System.out.println(obj);
    }
    //方法获取及使用
    @Test
    public void test4() throws Exception {
        Class c = Class.forName("com.xiaoqiang.Student");
        Object obj = c.newInstance();
        Method[] methods1 = c.getMethods();
        //获取所有公有方法 (包括继承过来的) 所有类继承自 Object
        for (Method method : methods1) {
            System.out.println(method);
        }
        Method[] methods = c.getDeclaredMethods();
        //获取本类所有方法 (不包括继承的) 包括非私有,保护,和默认
        for (Method method : methods) {
            System.out.println(method);
        }
        Method method = c.getDeclaredMethod("eat", null);
        // 此处null为参数 类型为Class类型
        method.setAccessible(true);
        //设置安全管理器强制访问 私有方法
        method.invoke(obj, null);
        // null 位置若有参数 直接传递
    }
}

学生类

package com.xiaoqiang;

public class Student {
    public String name;
    protected String sex;
    private int age;
    public Student() {

    }

    private Student(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }
    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    protected Student(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public void study(){
        System.out.println("学习ing");
    }

    private void eat(){
        System.out.println("吃ing");
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", sex=" + sex + ", age=" + age + "]";
    }

}

下期预告

下次博客将讲解apache的开源框架commons-beanutils,通过反射机制实现
该框架广泛用于其他框架中如struts,hibernate,spring中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值