反射(一)

反射知识点总结,总结自韩顺平老师循序渐进学java视频。

一.引出反射

img

开闭原则:不修改源码扩展功能

 

二.Java Reflection

1.反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(比如成员表量,构造器,成员方法等),并能操作对象的属性及方法,反射在设计模式和框架底层都会用到。

2.加载完类之后,在中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息,通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以称之为反射。(创建对象的时候会加载类,调用子类的时候会加载父类)。

3.Java反射机制可以完成:

1)在运行时判断任意一个对象所属的类

2)在运行时构造任意一个类的对象

3)在运行时得到任意一个类所具有的成员变量和方法

4)在运行时调用任意一个对象的成员变量和方法

5)生成动态代理

 

三.Java反射机制原理示意图

java程序在计算机中有三个阶段:

img

详解流程:

现在我们有一个Cat类的源码,探究java程序在计算机中的三个阶段。

① 首先在编译期,JVM检查是否有语法错误,如果没有就将其翻译成字节码文件。即.class文件,生成Cat.class字节码文件。

② 在运行阶段,我们要创建一个Cat对象。

③ 当我们要创建一个Cat对象,这时会将Cat.class字节码文件通过类加载器(ClassLoader)加载到堆中,为Class类对象,这里就体现出了反射,这个Class类对象中包含了完整的Cat类中的数据。

④ 类加载之后生成一个Cat对象,该对象知道它是属于哪个Class对象,而且我们拥有了Class类对象后,也可以使用反射机制进行各种操作。

 

四.反射相关的主要类

1.java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象

2.java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法

3.java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量

4.java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示构造器

    
复制代码
//创建对象,使用反射机制
        //(1)加载类,返回Class类型的对象cls
        //Class为一个类
        Class cls = Class.forName(classfullpath);
        //(2)通过cls得到你加载的类 com.hspedu.Cat的对象实例
        Object obj = cls.newInstance();
        //newInstance()方法实际上就是使用对应类的无参构造方法来创建该类的实例
        //这里当然可以将obj由Object类型转为Cat类型,然后就能调用其中的hi方法,但是我们的业务要求是我们可能并不知道配置文件中写的是hi方法,所以我们在这也不会
        //将hi方法写死,而是利用反射获取Cat中的方法。
        //Cat cat1 = (Cat)obj;
        //cat1.hi();
        //(3)通过cls得到你加载的类com.hspedu.Cat的methodName "hi"的方法对象
        
        //在反射中,可以把方法视为对象(万物皆对象)
        Method method1 = cls.getMethod(method);
        //(4)通过method1调用方法:即通过方法对象来实现方法调用
        System.out.println("==================================================");
        method1.invoke(obj);//传统方法:对象.方法(),反射机制方法:方法.invoke(对象)
//Field的使用,获取成员变量
        Field namefield = cls.getField("name");//报错:NoSuchFieldException: name
        //getField不能得到非public的成员属性
        System.out.println(namefield.get(obj));//传统写法是 对象.成员变量,在反射中:成员变量的对象.get(对象)
//Constructor的使用,获取构造器
        Constructor constructor1 = cls.getConstructor();//()中可以指定构造器的参数类型.若为空则为无参构造器
        Constructor constructor2 = cls.getConstructor(String.class,String.class);//这里传人的String.class就是String这个类的class对象
        System.out.println(constructor1);//public com.hspedu.Cat()
        System.out.println(constructor2);//public com.hspedu.Cat(java.lang.String)
复制代码

 

 

五.反射调用优化

1.反射的优点和缺点

1)优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支持。

2)缺点:使用反射基本是解释执行,对执行速度有影响。

耗时实例:

复制代码
public class Time_Test {
    public static void main(String[] args) throws Exception {
        m1();
        m2();
    }
    //传统方法来调用hi
    public static void m1(){
        Cat cat = new Cat();
        long start = System.currentTimeMillis();
        for(int i = 0;i<1000000000;i++){
            cat.hi();
        }
        long end = System.currentTimeMillis();
​
        System.out.println("传统方式耗时:"+(end-start)+"ms");
    }
    //反射机制调用方法hi
    public static void m2() throws Exception {
        Class cat = Class.forName("com.hspedu.Cat");
        Object obj = cat.newInstance();
        Method method = cat.getMethod("hi");
        long start = System.currentTimeMillis();
        for(int i = 0;i<1000000000;i++){
            method.invoke(obj);
        }
        long end = System.currentTimeMillis();
​
        System.out.println("反射方式耗时:"+(end-start)+"ms");
    }
}
输出:
    传统方式耗时:8ms
    反射方式耗时:4049ms
复制代码

 

 

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

1)Method和Field、Constructor对象都有setAccessible()方法。

2)setAccessible作用是启动和禁用访问安全检查的开关。

3)参数值为true表示反射的对象在使用时取消访问检查,提睾反射效率,参数值为false则表示反射的对象执行访问检查。

由类图可以看出,以Field为例:

AccessibleObject为其父类。

举例:

复制代码
//反射机制调用方法hi
public static void m2() throws Exception {
    Class cat = Class.forName("com.hspedu.Cat");
    Object obj = cat.newInstance();
    Method method = cat.getMethod("hi");
    method.setAccessible(true);//在反射调用方法时取消访问检查
    long start = System.currentTimeMillis();
    for(int i = 0;i<1000000000;i++){
        method.invoke(obj);
    }
    long end = System.currentTimeMillis();
​
    System.out.println("反射方式耗时:"+(end-start)+"ms");
}
输出:
    传统方式耗时:5ms
    反射方式耗时:2602ms
复制代码

可见是可以一定程度上提高执行效率。

未完待续...

作者:Noob-Green-Hand

出处:https://www.cnblogs.com/Noob-Green-Hand/p/17306776.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   StormArcita  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示