JavaSE之反射

本文探讨了如何利用反射API通过Properties文件动态加载`Cat`类并调用方法,展示了如何通过`forName`和`getMethod`实现程序配置的灵活性。同时,通过对比不同调用方式(传统与反射)分析了反射的性能,包括关闭访问检查的优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.一个需求引出反射

  1. 反射前置知识Properties类
  2. 如下案例

在这里插入图片描述
Cat类

public class Cat {
    private String name="招财猫";
    public int age=10;

    public Cat() {
    }

    public Cat(String name) {
        this.name = name;
    }

    public void hi(){ //常用方法
        //System.out.println("hi"+name);
    }
    public void  cry(){
        System.out.println(name+"喵喵叫");
    }
}

2.反射引出的问题

public class ReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //根据配臀文件re,properties指定信总,创建Cat对象并调川方法hi
        //老韩同忆
        //传统的方式new对象-》调用方法
        Cat cat=new Cat();
        cat.hi();
        //我们尝试做一做   ->明白反射

        //1.使用Properties 类 ,可以读写配置文件
        Properties properties=new Properties();
        properties.load(new FileInputStream("src/main/java/com/ReflexReview/re.properties"));
        //就是getproperty底层还是get方法
        String classfullpath=properties.get("classfullpath").toString();
        String methodName=properties.get("method").toString();
        System.out.println("classfullpath="+classfullpath);
        System.out.println("method="+methodName);

        //即通过外部文件配置 在不修改源码的情况下 来控制程序 也符合设计模式OCP原则(开闭原则:不修改源码 ,来扩展功能)
        //3.使用反射机制解决
        //(1)加载类 ,返回Class类型的对象cls
        Class cls=Class.forName(classfullpath); //Class就是一个类 类的名字叫Class
        //(2) 通过cls得到加载的类 com.ReflexReview.hspedu.Cat的对象实例
//        Cat o=(Cat)cls.newInstance();
        Object o=cls.newInstance();
        System.out.println("o的运行时类型"+o.getClass()); //Object方法返回该类运行时类
        //(3)通过cls 通过cls得到加载的类 com.ReflexReview.hspedu.Cat 的 methodName"hi"方法对象
        //  即 :在反射中,可以把方法视为对象(万物皆为对象)
        Method method1=cls.getMethod(methodName);
        //(4) 通过method1调用方法 即通过方法对象来实现调用方法
        System.out.println("=================");
        method1.invoke(o);//专统方法对象,方法(),反射机制方法.invoke(对象)

    }
}

3.反射快速入门

forname方法会导致类的加载

package com.ReflexReview.hspedu.reflectionquestion;

import com.ReflexReview.hspedu.Cat;

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

/**
 * 反射问题的引入
 */
public class ReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //根据配臀文件re,properties指定信总,创建Cat对象并调川方法hi
        //老韩同忆
        //传统的方式new对象-》调用方法
        Cat cat=new Cat();
        cat.hi();
        //我们尝试做一做   ->明白反射

        //1.使用Properties 类 ,可以读写配置文件
        Properties properties=new Properties();
        properties.load(new FileInputStream("src/main/java/com/ReflexReview/re.properties"));
        //就是getproperty底层还是get方法
        String classfullpath=properties.get("classfullpath").toString();
        String methodName=properties.get("method").toString();
        System.out.println("classfullpath="+classfullpath);
        System.out.println("method="+methodName);

        //即通过外部文件配置 在不修改源码的情况下 来控制程序 也符合设计模式OCP原则(开闭原则:不修改源码 ,来扩展功能)
        //3.使用反射机制解决
      /*  forName
        public static 类<?> forName(String className)
                        throws ClassNotFoundException
        返回与给定字符串名称的类或接口相关联的类对象。 调用此方法相当于:
        Class.forName(className, true, currentLoader)
        其中currentLoader表示当前类的定义类加载器。*/
        //(1)加载类 ,返回Class类型的对象cls
        //Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。
        Class cls=Class.forName(classfullpath); //Class就是一个类 类的名字叫Class
        //(2) 通过cls得到加载的类 com.ReflexReview.hspedu.Cat的对象实例
//        Cat o=(Cat)cls.newInstance();
        Object o=cls.newInstance();
        System.out.println("o的运行时类型"+o.getClass()); //Object方法返回该类运行时类
        //(3)通过cls 通过cls得到加载的类 com.ReflexReview.hspedu.Cat 的 methodName"hi"方法对象
        //  即 :在反射中,可以把方法视为对象(万物皆为对象)
//        forName
//        public static 类<?> forName(String className)
//                        throws ClassNotFoundException
//        返回与给定字符串名称的类或接口相关联的类对象。 调用此方法相当于:
//        Class.forName(className, true, currentLoader)
//        其中currentLoader表示当前类的定义类加载器。
        Method method1=cls.getMethod(methodName);
        //(4) 通过method1调用方法 即通过方法对象来实现调用方法
        System.out.println("=================");
        method1.invoke(o);//专统方法对象,方法(),反射机制方法.invoke(对象)

    }
}

4.反射机制

在这里插入图片描述

package com.ReflexReview.hspedu;

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

public class Reflection01 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //1.使用Properties 类 ,可以读写配置文件
        Properties properties=new Properties();
        properties.load(new FileInputStream("src/main/java/com/ReflexReview/re.properties"));
        //就是getproperty底层还是get方法
        String classfullpath=properties.get("classfullpath").toString();
        String methodName=properties.get("method").toString();
        //3.使用反射机制解决
        //(1)加载类 ,返回Class类型的对象cls
        //返回与给定的字符串名称的类或接口相关的 类对象。调用此方法等效于
        Class cls=Class.forName(classfullpath); //Class就是一个类 类的名字叫Class
        //(2) 通过cls得到加载的类 com.ReflexReview.hspedu.Cat的对象实例
//        Cat o=(Cat)cls.newInstance();
        Object o=cls.newInstance();
        System.out.println("o的运行时类型"+o.getClass()); //Object方法返回该类运行时类
        //(3)通过cls 通过cls得到加载的类 com.ReflexReview.hspedu.Cat 的 methodName"hi"方法对象
        //  即 :在反射中,可以把方法视为对象(万物皆为对象)
        Method method1=cls.getMethod(methodName);
        //(4) 通过method1调用方法 即通过方法对象来实现调用方法
        System.out.println("=================");
        method1.invoke(o);//专统方法对象,方法(),反射机制方法.invoke(对象)

        //java,Lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量
        //得到name字段 得不到报异常。因为name是private私有属性
      /*  Field name=cls.getField("name");
      异常了
        Exception in thread "main" java.lang.NoSuchFieldException: name
        at java.lang.Class.getField(Class.java:1703)
        at com.ReflexReview.hspedu.Reflection01.main(Reflection01.java:36)
        Disconnected from the target VM, address: '127.0.0.1:10997', transport: 'socket'

        Process finished with exit code 1*/

        //getField不能得到私有的属性
        Field nameFileld=cls.getField("age");
        System.out.println(nameFileld);
        System.out.println(nameFileld.get(o));//传统写法对象.成员变量,反射:成员变量对象.get(对象) 招财猫喵喵叫
        //java.Lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器
        Constructor constructor=cls.getConstructor();//()中可以指定构造器参数类型,返同无参构造器
        System.out.println(constructor);//Cat()
        //搞出这个类的 public Cat(String name) 有一个参数的构造器
        Constructor constructor2=cls.getConstructor(String.class);//这里老师传入的String.class就是String类的Class对象
        System.out.println(constructor2);//Cat(string name)
    }
}

o的运行时类型class com.ReflexReview.hspedu.Cat
=================
招财猫喵喵叫
public int com.ReflexReview.hspedu.Cat.age
10
public com.ReflexReview.hspedu.Cat()
public com.ReflexReview.hspedu.Cat(java.lang.String)

反射机制原理图

在这里插入图片描述
1.对于第一个箭头ClassLoder 就体现了反射
如果new cat()会导致类的加载 加载cat.class字节码文件到内存的堆区域 class类对象 这里有成员变量 构造器 成员方法 注解 泛型
怎么就会生成一个class对象放在堆区里面呢?
这里有一个特别重要的东西 叫做类的加载器
class类对象在堆还有个数据结构 变成可以操作的数据了
底层会把成员变量映射成一个对象Field[]数组对象 构造器Constructor[] cons因为构造器可能有多个 成员方法Method[] ms
类的加载完就生成对象了 相当于往运行堆区复制东西
2.类的加载完成后会生成一个对象 这个对象在运行阶段堆区而不是类对象/堆区中 同时该对象知道他是属于哪个Class对象的
他们之间是有映射关系的
3.得到Class对象后
1.创建对象,调用对象方法2.操作它的属性等等
1.2体现JVM底层实现
3.是应用程序员的应用

5.反射相关类

一.反射机制可以帮组我们完成的事情

在这里插入图片描述

二.反射相关的主要类

在这里插入图片描述
对于1的理解 1个class类对象就代表一个class字节码文件的感觉
对于理解2 Method表示类的方法 他的一个Method对象表示某个类的方法
理解3 Field代表某个类的成员变量 它的一个对象代表某个类的字段成员变量了44444444444444444444444

6. 反射优点和缺点

在这里插入图片描述

一.案例

package com.ReflexReview.hspedu;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 测试反射调用的性能,和优化方案
 */
public class Reflection02 {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
       // Field
        m1();
        m2();
        m3();
    }
    //传统方法调用hi
    public static void m1(){
        Cat cat=new Cat();
        long start=System.currentTimeMillis();
        for(int i=0;i<90000;i++){
            cat.hi();
        }
        long end=System.currentTimeMillis();
        System.out.println("传统方式来调用hi耗时间"+(end-start));
    }
    //反射机制调用方法hi
    public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class cls=Class.forName("com.ReflexReview.hspedu.Cat");
        Object o=cls.newInstance();
        Method hi=cls.getMethod("hi");

        long start=System.currentTimeMillis();
        for(int i=0;i<90000;i++){
            hi.invoke(o);
        }
        long end=System.currentTimeMillis();
        System.out.println("m2()耗时"+(end-start));
    }
    //反射调优+关闭访问检查
    public static void m3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class cls=Class.forName("com.ReflexReview.hspedu.Cat");
        Object o=cls.newInstance();
        Method hi=cls.getMethod("hi");
        hi.setAccessible(true);//在反射调用方法时,取消访问检查
        long start=System.currentTimeMillis();
        for(int i=0;i<90000;i++){
            hi.invoke(o);
        }
        long end=System.currentTimeMillis();
        System.out.println("m3()耗时"+(end-start));
    }
}

二. 反射调用优化-关闭访问检查

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

传统方式来调用hi耗时间4
m2()耗时13
m3()耗时9

7.Class类分析

新开

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值