类加载器&反射

1. 类加载器

负责将.class文件(存储的物理文件)加载到内存中

1.1 类加载的过程

  • 类加载时机

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

    (有用到就加载,没用到就不加载)

  • 类加载的过程

    1. 加载

      • 通过包名 + 类名,获取这个类,准备用流进行传输
      • 把这个类加载到内存中
      • 加载完毕创建一个class对象
    2. 链接

      1. 验证

        文件中的信心时候符合虚拟机规范,有没有安全隐患

      2. 准备

        初始化静态变量

      3. 解析

        本类中如果用到了其它类。此时就需要找到对应的类

    3. 初始化

      根据程序员通过程序制定的主观计划去初始化类变量和其他资源

      (静态变量赋值以及初始化其他资源)

1.2 类加载器的分类

  • 分类
    • Bootstrap class loader:虚拟机的内置类加载器,通常表示为null ,并且没有父null(启动类加载器—引导类加载器)
    • Platform class loader:平台类加载器,负责加载JDK中一些特殊的模块(扩展类加载器)
    • System class loader:系统类加载器,负责加载用户类路径上所指定的类库(应用程序类加载器)

1.3 双亲委派模型

  • 介绍

    如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式

1.4 ClassLoader 中的两个方法

  • 方法介绍

    方法名说明
    public static ClassLoader getSystemClassLoader()获取系统类加载器
    public InputStream getResourceAsStream(String name)加载某一个资源文件
  • 注意

    • getResourceAsStream(String name) :相对路径是在src下

2. 反射

在运行状态中,对于任意一个类都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意属性和方法;
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

2.1 获取Class类对象的三种方式

  1. 类名.class
  2. 对象名.getClass()方法
  3. Class.forName(全类名) 方法
public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //类名.class
        Class clazz = Student.class;
        System.out.println(clazz);//class com.lan.domain.Student

        //对象名.getClass()方法
        Student stu = new Student();
        Class clazz1 = stu.getClass();
        System.out.println(clazz1);//class com.lan.domain.Student

        //Class.forName(全类名) 方法
        Class clazz2 = Class.forName("com.lan.domain.Student");
        System.out.println(clazz2);//class com.lan.domain.Student

        //一个类只有一个类对象,是唯一的
        System.out.println(clazz == clazz1);//true
        System.out.println(clazz1 == clazz2);//true
    }
}

2.2 反射获取构造方法并使用

  • Class类获取构造方法对象的方法

    方法名说明
    Constructor<?>[] getConstructors()返回所有公共构造方法对象的数组
    Constructor<?>[] getDeclaredConstructors()返回所有构造方法对象的数组
    Constructor getConstructor(Class<?>… parameterTypes)返回单个公共构造方法对象
    Constructor getDeclaredConstructor(Class<?>… parameterTypes)返回单个构造方法对象
  • 小栗子

    public class Student {
        private String name;
        private Integer age;
        private String sex;
    
        public Student() {
        }
    
        private Student(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    
        public Student(String name, Integer age, String sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", sex='" + sex + '\'' +
                    '}';
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
    }
    
    //测试类
    public class Test02 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
            Class clazz = Class.forName("com.lan.domain.Student");
    
            //返回所有公共构造方法对象的数组
            Constructor[] constructors = clazz.getConstructors();
            for (Constructor constructor : constructors) {
                System.out.println(constructor);
            }
    
            //返回所有构造方法对象的数组,不管公有私有
            Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
            for (Constructor constructor : declaredConstructors) {
                System.out.println(constructor);
            }
    
            //返回无参构造的对象
            Constructor clazzConstructor = clazz.getConstructor();
            System.out.println(clazzConstructor);
    
            //返回有参构造的对象
            Constructor clazzConstructor1 = clazz.getConstructor(String.class,Integer.class,String.class);
            System.out.println(clazzConstructor1);
    
            //返回私有有参构造的对象
            Constructor clazzDeclaredConstructor = clazz.getDeclaredConstructor(String.class, Integer.class);
            System.out.println(clazzDeclaredConstructor);
        }
    }
    
  • Constructor类用于创建对象的方法

    方法名说明
    T newInstance(Object…initargs)根据指定的构造方法创建对象
    setAccessible(boolean flag)设置为true,表示取消访问检查
public class Test05 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1.获取Class对象
        Class clazz = Class.forName("com.lan.domain.Student");

        //2. 获取构造方法对象
        Constructor constructor = clazz.getDeclaredConstructor(String.class, Integer.class);

        //3.取消访问检查--暴力反射
        constructor.setAccessible(true);

        //4.创建对象
        Student stu = (Student) constructor.newInstance("张三", 12);

        System.out.println(stu);

        //创建空参的简写格式
        Student stu1 = (Student) clazz.newInstance();
        System.out.println(stu1);
    }
}
  • 小结

2.3 反射获取成员变量并使用

  • Class类获取成员变量对象的方法

    方法名说明
    Field[] getFields()返回所有公共成员变量对象的数组
    Field[] getDeclaredFields()返回所有成员变量对象的数组
    Field getField(String name)返回单个公共成员变量对象
    Field getDeclaredField(String name)返回单个成员变量对象
  • 小栗子

    public class Test03 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
    
            Class clazz = Class.forName("com.lan.domain.Student");
    
            //返回所有公共成员变量对象的数组
            Field[] fields = clazz.getFields();
            for (Field field : fields) {
                System.out.println(field);
            }
    
            //返回所有成员变量对象的数组,包括私有
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                System.out.println(field);
            }
    
            //返回单个公共成员变量对象
            //获取的成员变量必须真实存在并且是public修饰的
            //不然会出 NoSuchFieldException
            Field phone = clazz.getField("phone");
            System.out.println(phone);
    
            //返回单个成员变量对象,包括私有也可以返回
            Field name = clazz.getDeclaredField("name");
            System.out.println(name);
    
        }
    }
    
  • Field类用于给成员变量赋值的方法

    方法名说明
    void set(Object obj, Object value)赋值
    Object get(Object obj)获取值
  • 小栗子

    public class Test04 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
            //1.获取Class对象
            Class clazz = Class.forName("com.lan.domain.Student");
    
            //2.获取name这个Field对象
            Field fname = clazz.getDeclaredField("name");
    
            //3.取消一下访问检查,暴力反射
            fname.setAccessible(true);
    
            //4.创建对象
            Student stu = (Student) clazz.newInstance();
    
            //5.给指定对象赋值
            fname.set(stu,"张三");
    
            //6.获取指定对象的name值
            System.out.println(fname.get(stu));
        }
    }
    

2.4 反射获取成员方法并使用

  • Class类获取成员方法对象的方法

    方法名说明
    Method[] getMethods()返回所有公共成员方法对象的数组,包括继承的
    Method[] getDeclaredMethods()返回所有成员方法对象的数组,不包括继承的
    Method getMethod(String name, Class<?>… parameterTypes)返回单个公共成员方法对象
    Method getDeclaredMethod(String name, Class<?>… parameterTypes)返回单个成员方法对象
  • Method类用于执行方法的方法

    方法名说明
    Object invoke(Object obj, Object… args)运行方法

    参数一: 用obj对象调用该方法

    参数二: 调用方法的传递的参数(如果没有就不写)

    返回值: 方法的返回值(如果没有就不写)

  • 小栗子

    public class Student {
    
        //私有的,有参有返回值
        private String show(String name) {
            System.out.println("私有的show方法,有参有返回值,参数为:"+name);
            return "LAN";
        }
    
        //公共的,无参无返回值
        public void function1() {
            System.out.println("function1方法,无参无返回值");
        }
    
        //公共的,有参无返回值
        public void function2(String name) {
            System.out.println("function2方法,有参无返回值,参数为" + name);
        }
    
        //公共的,无参有返回值
        public String function3() {
            System.out.println("function3方法,无参有返回值");
            return "aaa";
        }
    
        //公共的,有参有返回值
        public String function4(String name) {
            System.out.println("function4方法,有参有返回值,参数为" + name);
            return "aaa";
        }
    }
    
    public class Test06 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
            //1.创建class对象
            Class clazz = Class.forName("com.lan.test01.Student");
    
            //2.获取成员方法
                //返回所有公共方法,包括继承的
                //method1(clazz);
    
                //返回所有成员方法,包括私有,不包括继承
                //method2(clazz);
    
                //返回单个公共成员方法对象
                //参数一:方法名
                //参数二:可变参数,传入方法形参类型的class类
                //method3(clazz);
    
            //返回单个成员方法对象,可以是私有
            Method method = clazz.getDeclaredMethod("show", String.class);
            System.out.println(method);
            //运行方法
            method.setAccessible(true);
            Student stu = (Student) clazz.newInstance();
            Object invoke = method.invoke(stu, "张三");
            System.out.println(invoke);
    
        }
    
        private static void method3(Class clazz) throws NoSuchMethodException {
            Method method = clazz.getMethod("function2", String.class);
            System.out.println(method);
        }
    
        private static void method2(Class clazz) {
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                System.out.println(method);
            }
        }
    
        private static void method1(Class clazz) {
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                System.out.println(method);
            }
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值