类加载与反射

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底层的反射机制.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值