0
点赞
收藏
分享

微信扫一扫

15-基础加强1-类加载器&反射



文章目录

  • 1.类加载器
  • 1.1类加载器【理解】
  • 1.2类加载的过程【理解】
  • 1.3类加载的分类【理解】
  • 1.4双亲委派模型【理解】
  • 1.5ClassLoader 中的两个方法【应用】
  • 2.反射
  • 2.1反射的概述【理解】
  • 2.2获取Class类对象的三种方式【应用】 第1步:获取类的Class对象
  • 2.3反射获取构造方法并使用【应用】第2.1步:利用Class类获取对象方法
  • 2.3.1Class类获取构造方法对象的方法
  • 2.3.2Constructor类用于创建对象的方法 (构造方法获取到了,接下来第3步:利用构造方法创建对象了)
  • 2.3.3小结
  • 2.4反射获取成员变量并使用【应用】
  • 2.4.1Class类获取成员变量对象的方法 (第2步:获取成员变量 (第1步已经获取了Class类对象了))
  • 2.4.2Field类用于给成员变量赋值的方法 (第3步:使用成员变量 (前面已经获取到了成员变量对象了))
  • 2.5反射获取成员方法并使用【应用】
  • 2.5.1Class类获取成员方法对象的方法 (第2步:用Class类对象获取成员方法)
  • 2.5.2Method类用于执行方法的方法 (第3步:前面已经获取了成员方法,这里该执行成员方法了)
  • 小结:反射根据配置文件动态创建对象并执行方法
  • LX 再手敲一遍,读取配置文件,动态创建类对象,获取方法并执行


1.类加载器

1.1类加载器【理解】

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

15-基础加强1-类加载器&反射_构造方法

1.2类加载的过程【理解】

  • 类加载时机
  • 创建类的实例(对象)
  • 调用类的类方法
  • 访问类或者接口的类变量,或者为该类变量赋值
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类
  • 类加载过程
  1. 加载
  • 通过包名 + 类名,获取这个类,准备用流进行传输
  • 将这个类加载到内存中
  • 加载完毕创建一个class对象 类在内存中不能随便乱放,得为每个类创建一个Class对象来存放这个类的信息

15-基础加强1-类加载器&反射_jvm_02

  1. 链接
  • 验证
    确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全
    (文件中的信息是否符合虚拟机规范有没有安全隐患)

15-基础加强1-类加载器&反射_java_03

  • 准备
    负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值
    (初始化静态变量) 静态变量有默认的初始化值 开辟空间 赋值为null 注意只为static修饰的静态变量赋初值

15-基础加强1-类加载器&反射_开发语言_04

  • 解析
    将类的二进制数据流中的符号引用替换为直接引用
    (本类中如果用到了其他类,此时就需要找到对应的类)

15-基础加强1-类加载器&反射_开发语言_05


15-基础加强1-类加载器&反射_java_06

“将类的二进制数据流中的符号引用替换为直接引用”:
加载好了类Student,但是其成员name是引用类型,对应的String类到底有没有被加载呀,加载了在哪呀? 所以String先是符号引用
----内存中找到String类------ 就变成了 直接引用(String类型)

  1. 初始化
    根据程序员通过程序制定的主观计划去初始化类变量和其他资源
    (静态变量赋值以及初始化其他资源)
  • 小结
  • 当一个类被使用的时候,才会加载到内存
  • 类加载的过程: 加载、验证、准备、解析、初始化

1.3类加载的分类【理解】

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

1.4双亲委派模型【理解】

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

是逻辑上的父子关系,不是extends的继承父子关系。 就是把类加载任务委托给‘父亲’去加载

某个父亲加载不了就返回,直到最后没办法,自己才去加载

15-基础加强1-类加载器&反射_jvm_07

1.5ClassLoader 中的两个方法【应用】

  • 方法介绍

方法名

说明

public static ClassLoader getSystemClassLoader()

获取系统类加载器

public InputStream getResourceAsStream(String name)

加载某一个资源文件

public class ClassLoaderDemo1 {

    public static void main(String[] args) {
        //获得系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

        //获得系统类加载器的父加载器 --- 平台类加载器
        ClassLoader platformClassLoader = systemClassLoader.getParent();

        //获得平台类加载器的父加载器 --- 启动类加载器
        ClassLoader bootstrapClassLoader = platformClassLoader.getParent();

        System.out.println("系统类加载器"+systemClassLoader);
        System.out.println("平台类加载器"+platformClassLoader);
        System.out.println("启动类加载器"+bootstrapClassLoader);
    }
}

15-基础加强1-类加载器&反射_开发语言_08

  • LX 读取properties文件
  • prop.properties

name=zhangsan
age=13

  • ClassLoaderDemo2.java

public class ClassLoaderDemo2 {
    public static void main(String[] args) throws IOException {
        //static ClassLoader getSystemClassLoader() 获取系统类加载器
        //InputStream getResourceAsStream(String name)  加载某一个资源文件

        //获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

        //利用加载器去加载一个指定的文件
        //参数:文件的路径(放在src的根目录下,默认去那里加载)
        //返回值:字节流。
        InputStream is = systemClassLoader.getResourceAsStream("prop.properties");

        Properties prop = new Properties();
        prop.load(is);

        System.out.println(prop);

        is.close();
    }
}

15-基础加强1-类加载器&反射_System_09

  • ClassLoaderDemo2.java 整理后很简单

public class ClassLoaderDemo2_1 {
    public static void main(String[] args) throws IOException {
        // 获得系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        // 利用加载器加载一个指定文件 返回字节流
        InputStream is = systemClassLoader.getResourceAsStream("prop.properties");
        Properties prop = new Properties();
        prop.load(is);
        System.out.println("prop = " + prop);
        is.close();
    }
}

2.反射

2.1反射的概述【理解】

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

2.2获取Class类对象的三种方式【应用】 第1步:获取类的Class对象

  • 三种方式分类
  • 类名.class属性
  • 对象名.getClass()方法
  • Class.forName(全类名)方法

15-基础加强1-类加载器&反射_开发语言_10

  • 示例代码
    Student.java

package cn.whu.myreflect1;

public class Student {
    private String name;
    private int age;

    //空参构造,全参构造,toString,所有get/set

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

ReflectDemo1.java

/**
 * 各种获取类的Class对象的方法
 */
public class ReflectDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //方法1.Class类中的静态方法forName("全类名") //所谓全类名: 包名.类名
        Class clazz = Class.forName("cn.whu.myreflect1.Student");
        System.out.println(clazz);//class cn.whu.myreflect1.Student

        //方法2.通过class属性来获取
        Class clazz2 = Student.class;
        System.out.println(clazz2);//class cn.whu.myreflect1.Student

        //方法3.利用对象的getClass方法来获取class对象
        //getClass方法是定义在Object类中的,所以任何对象都有
        Student stu = new Student();
        Class clazz3 = stu.getClass();
        System.out.println(clazz3);//class cn.whu.myreflect1.Student


        System.out.println(clazz == clazz2);//true
        System.out.println(clazz2 == clazz3);//true
    }
}

15-基础加强1-类加载器&反射_java_11


无视修饰符: 无视private还是public

有了Class对象可以干嘛,可以获取类的所有信息,主要也就三类:构造器、普通方法、成员变量

Class对象组成如下:

15-基础加强1-类加载器&反射_构造方法_12

2.3反射获取构造方法并使用【应用】第2.1步:利用Class类获取对象方法

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

  • 方法介绍

方法名

说明

Constructor<?>[] getConstructors()

返回所有公共构造方法对象的数组

Constructor<?>[] getDeclaredConstructors()

返回所有构造方法对象的数组

Constructor getConstructor(Class<?>… parameterTypes)

返回单个公共构造方法对象

Constructor getDeclaredConstructor(Class<?>… parameterTypes)

返回单个构造方法对象

  • Student.java

package cn.whu.myreflect2;

public class Student {
    private String name;
    private int age;

    //私有的有参构造
    private Student(String name){
        System.out.println("name值为:"+name);
        System.out.println("private Student 有参构造方法");
    }

    //公共无参构造
    public Student() {
        System.out.println("public Student 无参构造方法");
    }

    //公共有参构造
    public Student(String name,int age){
        System.out.println("name值为:"+name+" age值为:"+age);
        System.out.println("public Student 有参构造方法");
    }
}

  • Constructor<?>[] getConstructors() 返回所有公共构造方法对象的数组

public static void main(String[] args) throws ClassNotFoundException {
        //1.不管那种获取方法 第一步都得先获取Class对象啊
        Class<?> clazz = Class.forName("cn.whu.myreflect2.Student");

        //2. Constructor<?>[] getConstructors()	返回所有公共构造方法对象的数组
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
    }

15-基础加强1-类加载器&反射_System_13

  • Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组

public static void main(String[] args) throws ClassNotFoundException {
        //1.不管那种获取方法 第一步都得先获取Class对象啊
        Class<?> clazz = Class.forName("cn.whu.myreflect2.Student");

        //2. Constructor<?>[] getDeclaredConstructors()	返回所有构造方法对象的数组
        Constructor<?>[] declaredAnnotations = clazz.getDeclaredConstructors();
        for (Constructor declaredAnnotation : declaredAnnotations) {
            System.out.println(declaredAnnotation);
        }

15-基础加强1-类加载器&反射_开发语言_14

  • Constructor getConstructor(Class<?>… parameterTypes) 返回单个公共构造方法对象
    参数就写构造方法的形式参数类型对应的Class类

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        //1.不管那种获取方法 第一步都得先获取Class对象啊
        Class<?> clazz = Class.forName("cn.whu.myreflect2.Student");
        //2. Constructor getConstructor(Class<?>… parameterTypes)	返回单个公共构造方法对象
        Constructor<?> constructor1 = clazz.getConstructor();
        System.out.println(constructor1);//public cn.whu.myreflect2.Student() 公共空参构造

        Constructor<?> constructor2 = clazz.getConstructor(String.class, int.class);//参数类型就写构造方法的形参类型和顺序
        System.out.println(constructor2);//public cn.whu.myreflect2.Student(java.lang.String,int) //string,int参构造方法
        //Constructor<?> constructor3 = clazz.getConstructor(int.class);//报错 并没有一个参数为(int)的构造方法
    }

15-基础加强1-类加载器&反射_java_15

  • Constructor getDeclaredConstructor(Class<?>… parameterTypes) 返回单个构造方法对象
    私有的也可以获取到

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        //1.不管那种获取方法 第一步都得先获取Class对象啊
        Class<?> clazz = Class.forName("cn.whu.myreflect2.Student");
        
        //2. Constructor getDeclaredConstructor(Class<?>… parameterTypes)	返回单个构造方法对象
        // 私有的也可以获取到
        Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(String.class);
        System.out.println(declaredConstructor);
    }

15-基础加强1-类加载器&反射_java_16

2.3.2Constructor类用于创建对象的方法 (构造方法获取到了,接下来第3步:利用构造方法创建对象了)

  • 方法介绍

方法名

说明

T newInstance(Object…initargs)

根据指定的构造方法创建对象

setAccessible(boolean flag)

设置为true,表示取消访问检查

  • T newInstance(Object…initargs) 根据指定的构造方法创建对象

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1. 第一步永远都是先获取Class对象
        Class<?> clazz = Class.forName("cn.whu.myreflect2.Student");
        //2.获取构造方法对象
        Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
        //3.利用newInstance 创建Student对象
        Student student = (Student) constructor.newInstance("张三",23); // 当然创建对象时的实参值得这时候传递了
                                                                                // 此时,构造方法会自动执行
        System.out.println("student = " + student);
    }

15-基础加强1-类加载器&反射_java_17


类似的调用空参构造

public static void main(String[] args) throws Exception {
        //1. 第一步永远都是先获取Class对象
        Class<?> clazz = Class.forName("cn.whu.myreflect2.Student");
        //2.获取构造方法对象
        Constructor<?> constructor = clazz.getConstructor();
        //3.利用newInstance 创建Student对象
        Student student = (Student) constructor.newInstance(); // 当然创建对象时的实参值得这时候传递了
        														// 此时,构造方法会自动执行
        System.out.println("student = " + student);
    }

15-基础加强1-类加载器&反射_jvm_18


空参构造还有个简写方式(过时方法 了解即可)

public static void main(String[] args) throws Exception {        
        // 反射调用空参创建对象简写格式
        //1. 第一步永远都是先获取Class对象
        Class<?> clazz = Class.forName("cn.whu.myreflect2.Student");
        //2. 在Class类中,有一个newInstance方法,可以利用空参直接创建一个对象 (直接跳过了获得构造对象那一步)
        Student student = (Student) clazz.newInstance(); // 该方法已经过时 了解即可
        
        System.out.println(student);
    }

15-基础加强1-类加载器&反射_System_19

  • setAccessible(boolean flag) 设置为true,表示取消访问检查(可以临时使用私有成员了)

★获取一个私有的构造方法,创建对象★
多一步,临时取消访问检查

public static void main(String[] args) throws Exception {
        //1. 第一步永远都是先获取Class对象
        Class<?> clazz = Class.forName("cn.whu.myreflect2.Student");
        //2.获取构造私有方法对象
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);

        //直接创建对象会报错 毕竟私有,直接调用私有构造方法肯定不妥
        //也即:被private修饰的成员,不能直接使用
        //如果用反射强行获取并使用,需要临时取消访问检查
        constructor.setAccessible(true);//临时取消(私有)访问检查

        //3.利用newInstance 创建Student对象
        Student student = (Student) constructor.newInstance("张三"); // 当然创建对象时的实参值得这时候传递了
        															// 此时,构造方法会自动执行
        
        System.out.println("student = " + student);
    }

15-基础加强1-类加载器&反射_jvm_20


反射可以强行获取私有方法,并强行用其获取对象

2.3.3小结

  • 获取class对象
    三种方式: Class.forName(“全类名”), 类名.class, 对象名.getClass()
  • 获取里面的构造方法对象
    getConstructor (Class<?>... parameterTypes) getDeclaredConstructor (Class<?>… parameterTypes)
  • 如果是public的,直接创建对象
    newInstance(Object… initargs)
  • 如果是非public的,需要临时取消检查,然后再创建对象
    setAccessible(boolean) 暴力反射

2.4反射获取成员变量并使用【应用】

2.4.1Class类获取成员变量对象的方法 (第2步:获取成员变量 (第1步已经获取了Class类对象了))

  • 方法分类

方法名

说明

Field[] getFields()

返回所有公共成员变量对象的数组

Field[] getDeclaredFields()

返回所有成员变量对象的数组

Field getField(String name)

返回单个公共成员变量对象

Field getDeclaredField(String name)

返回单个成员变量对象

公共成员变量:仅仅public修饰的成员变量
所有成员变量:public、private、protect… 修饰的成员变量

  • Student.java

public class Student {
    public String name;
    public int age;

    public String gender;
    private int money = 300;

    //3个public 仅仅int money一个private
}

  • Field[] getFields() 返回所有公共成员变量对象的数组 (仅仅public)

public static void main(String[] args) throws Exception {
        //Field[] getFields()	返回所有公共成员变量对象的数组
        //1.第一步永远还是获取对呀类的Class对象
        Class clazz = Class.forName("cn.whu.myreflect3.Student");
        //2.第二步:获取Field对象
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field); //所有public成员变量
        }
    }

15-基础加强1-类加载器&反射_开发语言_21

  • Field[] getDeclaredFields() 返回所有成员变量对象的数组 (包括私有)

public static void main(String[] args) throws Exception {
        //Field[] getDeclaredFields()	返回所有成员变量对象的数组 (包括私有)
        //1.第一步永远还是获取对呀类的Class对象
        Class clazz = Class.forName("cn.whu.myreflect3.Student");
        //2.第二步:获取Field对象
        Field[] declaredFields = clazz.getDeclaredFields();

        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
    }

15-基础加强1-类加载器&反射_构造方法_22

  • Field getField(String name) 返回单个公共成员变量对象 (仅仅public)

public static void main(String[] args) throws Exception {
        //Field getField(String name)	返回单个公共成员变量对象
        //1.第一步永远还是获取对呀类的Class对象
        Class clazz = Class.forName("cn.whu.myreflect3.Student");
        //2.第二步:获取Field对象
        Field age = clazz.getField("age"); //传入变量名即可
        //Field age = clazz.getField("age1"); //倘若没有这个变量 则会报错
        //Field money = clazz.getField("money"); //私有的也会报错

        System.out.println(age);
   }

15-基础加强1-类加载器&反射_构造方法_23

  • Field getDeclaredField(String name) 返回单个成员变量对象 (包括私有)

public static void main(String[] args) throws Exception {        
        //Field getDeclaredField(String name)	返回单个成员变量对象
        //1.第一步永远还是获取对呀类的Class对象
        Class clazz = Class.forName("cn.whu.myreflect3.Student");
        //2.第二步:获取Field对象
        Field age = clazz.getDeclaredField("age"); // 传入变量名 获取公有变量
        Field money = clazz.getDeclaredField("money"); // 私有的也可以获取
        System.out.println(age);
        System.out.println(money);
   }

15-基础加强1-类加载器&反射_jvm_24

2.4.2Field类用于给成员变量赋值的方法 (第3步:使用成员变量 (前面已经获取到了成员变量对象了))

  • 方法介绍

方法名

说明

void set(Object obj, Object value)

赋值

Object get(Object obj)

获取值

第一个参数就是要赋值或者获取值的 具体对象 (一个类好多对象 到底赋值给哪个对象,肯定要说明一下的)

  • 示例代码
  • void set(Object obj, Object value) 赋值

public static void main(String[] args) throws Exception {
        //void set(Object obj, Object value)	赋值
        //1.第一步永远还是获取对呀类的Class对象
        Class clazz = Class.forName("cn.whu.myreflect3.Student");

        //2.获取age这个Filed对象
        Field age = clazz.getField("age");

        //3.利用set方法进行赋值
        //3.1先创建一个Student对象 (不然赋值给谁呢?)
        Student student = (Student) clazz.newInstance();//空参的简写形式(跳过了获取构造方法那步)
        //3.2有了对象才可以给指定对象进行赋值
        age.set(student,18); //给student对象的age属性赋值18

        System.out.println(student.age);//18
    }

15-基础加强1-类加载器&反射_构造方法_25

  • Object get(Object obj) 获取值
    访问私有成员,都必须取消访问检查

public static void main(String[] args) throws Exception {
        //Object get(Object obj)	获取值
        //1.第一步永远还是获取对呀类的Class对象
        Class clazz = Class.forName("cn.whu.myreflect3.Student");

        //2.获取age这个Filed对象
        Field money = clazz.getDeclaredField("money");//直接获取一个私有的

        //3.☆想再下面访问私有成员,都必须取消访问检查
        money.setAccessible(true);

        //4.调用get方法,获取money值
        //4.1 还是得提前创建实际对象
        Student student = (Student) clazz.newInstance();
        //4.2 获取指定对象的money值
        Object val = money.get(student);
        System.out.println(val);//300
    }

15-基础加强1-类加载器&反射_构造方法_26

2.5反射获取成员方法并使用【应用】

2.5.1Class类获取成员方法对象的方法 (第2步:用Class类对象获取成员方法)

  • 方法分类

方法名

说明

Method[] getMethods()

返回所有公共成员方法对象的数组,包括继承的

Method[] getDeclaredMethods()

返回所有成员方法对象的数组,不包括继承的

Method getMethod(String name, Class<?>… parameterTypes)

返回单个公共成员方法对象

Method getDeclaredMethod(String name, Class<?>… parameterTypes)

返回单个成员方法对象

  • 示例代码
  • Student.java

public class Student {
    // 私有,无参,无返回值
    private void fun(){
        System.out.println("私有的show方法,无参,无返回值");
    }

    // 公共,无参,无返回值
    public void fun1(){
        System.out.println("公共的fun1方法,无参,无返回值");
    }

    // 公共,有参,无返回值
    public void fun2(String name){
        System.out.println("公共的fun2方法,有参,无返回值, 参数为:"+name);
    }

    // 公共,无参,有返回值
    public String fun3(){
        System.out.println("公共的fun3方法,无参,有返回值, 参数为:");
        return "zhangsan";
    }

    // 公共,有参,有返回值
    public String fun4(String name){
        System.out.println("公共的fun4方法,有参,有返回值, 参数为:"+name);
        return "zhangsan";
    }
}

  • Method[] getMethods() 返回所有公共成员方法对象的数组,包括继承的

public static void main(String[] args) throws Exception {
        //Method[] getMethods()	返回所有公共成员方法对象的数组,包括继承的
        //1.第一步永远是先获取Class对象
        Class clazz = Class.forName("cn.whu.myreflect4.Student");
        //2.获取成员方法对象
        Method[] methods = clazz.getMethods();//所有公共成员方法

        for (Method method : methods) {
            System.out.println(method); // 所有public都打印出来了 (包括一大堆从Object里继承的)
        }
    }

15-基础加强1-类加载器&反射_jvm_27

  • Method[] getDeclaredMethods() 返回所有成员方法对象的数组,不包括继承的

public static void main(String[] args) throws Exception {
        //extracted1();
        //Method[] getDeclaredMethods()	返回所有成员方法对象的数组,不包括继承的
        //1.第一步永远是先获取Class对象
        Class clazz = Class.forName("cn.whu.myreflect4.Student");
        //2.获取成员方法对象
        Method[] declaredMethods = clazz.getDeclaredMethods();//所有方法,包括私有 (但继承的就获取不到了 (私有的也不会被继承))
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
    }

15-基础加强1-类加载器&反射_构造方法_28

  • Method getMethod(String name, Class<?>… parameterTypes) 返回单个公共成员方法对象

public static void main(String[] args) throws Exception {
        //Method getMethod(String name, Class<?>… parameterTypes)	返回单个公共成员方法对象
        //1.第一步永远是先获取Class对象
        Class clazz = Class.forName("cn.whu.myreflect4.Student");
        //2.获取成员方法对象
        Method fun1 = clazz.getMethod("fun1");//第一个参数方法名,该方法本身有参数就接着写在后面
        System.out.println(fun1); // public void cn.whu.myreflect4.Student.fun1()

        //获取有形参的方法
        Method fun2 = clazz.getMethod("fun2", String.class); // 方法名,形参1.class,形参2.class ....
        System.out.println(fun2); // public void cn.whu.myreflect4.Student.fun2(java.lang.String)
    }

  • Method getDeclaredMethod(String name, Class<?>… parameterTypes) 返回单个成员方法对象 (主要用来获取私有成员)

public static void main(String[] args) throws Exception {
        //Method getDeclaredMethod(String name, Class<?>… parameterTypes)	返回单个成员方法对象
        //1.第一步永远是先获取Class对象
        Class clazz = Class.forName("cn.whu.myreflect4.Student");
        //2.获取成员方法对象 私有fun方法
        Method fun = clazz.getDeclaredMethod("fun");

        System.out.println(fun);//只是看一下 完全可以(不必取消访问检查)
    }

15-基础加强1-类加载器&反射_java_29

2.5.2Method类用于执行方法的方法 (第3步:前面已经获取了成员方法,这里该执行成员方法了)

  • 方法介绍

方法名

说明

Object invoke(Object obj, Object… args)

运行方法

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

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

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

  • 示例代码

public static void main(String[] args) throws Exception {
        //Object invoke(Object obj, Object… args)	运行方法
        //参数一: 用obj对象调用该方法
        //参数二: 调用方法的传递的实际参数(如果没有就不写)
        //返回值: 方法的返回值(如果没有就不写)

        //1. 第一步永远是先获取Class对象
        Class clazz = Class.forName("cn.whu.myreflect4.Student");
        //2. 获取里面的Method对象, fun4 (最难的,有参,有返回值)
        Method fun4 = clazz.getMethod("fun4", String.class);//要指定方法参数类型
        //3. 运行方法
        //3.1 先得创建实际对象,作为方法的调用者(对象调用方法运行嘛)
        Student student = (Student) clazz.newInstance();//又是简写形式(跳过了获取构造器的一步)
        //3.2 有了对象,就可以在该对象上执行方法了
        Object ret = fun4.invoke(student,"myname"); //实参 依次写在后面  有返回值就直接接收就行了
        
        System.out.println(ret);
    }

15-基础加强1-类加载器&反射_jvm_30

小结:反射根据配置文件动态创建对象并执行方法

小结:
1、获取Class对象
Class clazz = Class.forName("cn.whu.myreflect1.Student");
Class clazz2 = Student.class;
Class clazz3 = new Student().getClass();

2、通过Class对象获取三类成员
Constructor constructor = clazz.getConstructor(); // 获取构造器 (详细介绍了多种方式)
Method method = clazz.getMethod("name"); //获取方法 (详细介绍了多种方式)
Field field clazz.getField(String name) // 获取变量名 (详细介绍了多种方式)

3、通过获取的构造器创建对象
Object o = constructor.newInstance();

4、通过对象和方法,执行对应方法
method.invoke(o);//学生在学习

反射可以根据配置文件,动态创建对象,并调用对象的方法

15-基础加强1-类加载器&反射_构造方法_31

ReflectDemo2.java

package cn.whu.myreflect1;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 根据配置文件创建对象,并执行对象方法
 */
public class ReflectDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, IOException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        //获取系统类加载器,加载prop.properties文件
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("prop.properties");
        //得先创建一个Properties集合
        Properties prop = new Properties();
        //将文件中的数据读取到集合中
        prop.load(is);
        is.close();

        //---- 下面利用【反射】创建对象并调用方法 ----
        // 死步骤 能看懂 最好是记住

        //获取字节码文件对象
        Class clazz = Class.forName(prop.getProperty("className"));//配置文件里className配置好的全路径名
        //(通过类Class对象)获取构造器对象
        Constructor constructor = clazz.getConstructor();
        //利用构造器创建一个对象
        Object o = constructor.newInstance();
        //获取方法对象
        Method method = clazz.getMethod(prop.getProperty("methodName"));//配置文件里配置好的方法名
        //运行方法
        method.invoke(o);//学生在学习
    }
}

prop.properties

className=cn.whu.myreflect1.Worker
methodName=work

15-基础加强1-类加载器&反射_java_32

LX 再手敲一遍,读取配置文件,动态创建类对象,获取方法并执行

propLX.properties

className=cn.whu.LX.Worker
methodName=show

Worker.java

package cn.whu.LX;

public class Worker {
    private String name;
    private int age;


    public Worker() {
    }

    public Worker(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String show(){
        System.out.println("我叫"+name+" 我今年"+age+"岁啦");//成员变量 类内部可以随便访问
        return "明年就"+(age+1)+"岁啦";
    }

}

myreflectLX.java

package cn.whu.LX;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

public class myreflectLX {
    public static void main(String[] args) throws Exception {
        // 1.类加载器获取输入流 读取Property配置文件 获取配置信息
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("propLX.properties");
        Properties prop = new Properties();
        prop.load(is);
        is.close();

        System.out.println("prop = "+prop);
        String className = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");
        System.out.println("className = "+className);
        System.out.println("methodName = "+methodName);

        //2.反射 动态根据(类名className)和(其方法名methodName) 创建对象 并用对象调用该方法
        //2.1 获取Class对象
        Class clazz = Class.forName(className);//有了Class对象 啥都能获取了
        //2.2 获取有参数构造并创建对象
        Constructor constructor = clazz.getConstructor(String.class, int.class);
        Worker worker = (Worker) constructor.newInstance("紫英", 24);
        //2.3 获取方法
        Method method = clazz.getMethod(methodName);

        //2.4 用对象调用方法
        Object ret = method.invoke(worker);//该方法有返回值就接收
        System.out.println(ret);
    }
}

15-基础加强1-类加载器&反射_构造方法_33


举报

相关推荐

0 条评论