java—类反射机制

news2024/11/27 18:50:34

简述

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

        类一旦加载,在堆中会产生一个Class类型的对象,这个对象包含了类的完整结构信息。通过这个对象可以获得这个类的结构。

java反射机制相关类

         java作为面向对象的编程语言,万物皆对象,在反射机制中,将类的各个成员都当做一个类的对象

    ①java.lang.Class:Class对象表示某个类加载后在堆中的对象
    ②java.lang.reflect.Method:代表类的方法
    ③java.lang.reflect.Field:代表类的成员变量
    ④java.lang.reflect.Constructor:代表类的构造器

反射机制优缺点

优点:可以动态的创建和使用对象,使用灵活,反射机制就是框架的底层支撑
缺点:使用反射的运行效率较慢

反射机制优化

        关闭访问检查,Method,Field,Constructor均有setAccessible(boolean b)方法,作用是开启或关闭访问安全检查开关,参数为true时关闭访问检查,提高反射的效率;参数为false则表示开启访问检查

Class

①Class类也是一个类,只是类名就叫做Class,因此也继承Object类
②Class类对象不是new Class()的形式创建的,而是由系统创建
③对于某一个类的Class类对象,在内存中只有一份,因此类在内存中只加载一次
④通过Class类对象可以获取所加载类的所有接信息
⑤Class对象存放在堆中。

具有Class对象的类型

类,接口,数组,枚举,注解,基本数据类型,void

代码示例:

package com.flash.class_;

import java.io.Serializable;

/**
 * @author flash
 * @date 2024/06/18 18:08
 * 功能描述:枚举拥有 Class 对象的类型
 */
public class AllTypeClass {
    public static void main(String[] args) {
        // 类
        Class<String> cls1 = String.class;
        // 接口
        Class<Serializable> cls2 = Serializable.class;
        // 一维数组
        Class<Integer[]> cls3 = Integer[].class;
        // 二维数组
        Class<float[][]> cls4 = float[][].class;
        // 注解
        Class<Deprecated> cls5 = Deprecated.class;
        // 枚举
        Class<Thread.State> cls6 = Thread.State.class;
        // 基本数据类型
        Class<Long> cls7 = long.class;
        // void
        Class<Void> cls8 = void.class;
        // Class
        Class<Class> cls9 = Class.class;

        System.out.println("cls1 = " + cls1);
        System.out.println("cls2 = " + cls2);
        System.out.println("cls3 = " + cls3);
        System.out.println("cls4 = " + cls4);
        System.out.println("cls5 = " + cls5);
        System.out.println("cls6 = " + cls6);
        System.out.println("cls7 = " + cls7);
        System.out.println("cls8 = " + cls8);
        System.out.println("cls9 = " + cls9);
    }
}

运行结果:

类加载

基本说明:反射机制是java实现动态语言的关键, 也就是通过反射实现类动态加载
        ①静态加载:编译时加载相关的类, 如果没有直接报错, 依赖性强
        ②动态加载:运行时加载需要的类, 如果运行时没有用到该类, 即使不存在这个类也不会报错, 依赖性较弱
类加载时机:
        ①当创建对象时(new) 静态加载
        ②当子类被加载时, 父类也被加载 静态加载
        ③调用类中的静态成员时 静态加载
        ④反射机制 动态加载

Class类对象创建方式

import com.flash.classReflex.Car;

/**
 * @author flash
 * @date 2024/06/18 16:28
 * 功能描述:演示得到 Class类 对象的各种方式
 */
public class CreateClassInstance {
    public static void main(String[] args) throws ClassNotFoundException {
        // 1.class.forName
        String classAllPath = "com.flash.classReflex.Car";// 通过读取配置文件获取
        Class<?> cls1 = Class.forName(classAllPath);
        System.out.println("cls1 = " + cls1);

        // 2.类名.class, 应用场景: 用于参数传递
        Class<Car> cls2 = Car.class;
        System.out.println("cls2 = " + cls2);

        // 3.通过已有类调用 getClass() 方法, getClass()获得的就是这个对象关联的 Class 的对象
        Car car = new Car();
        Class<? extends Car> cls3 = car.getClass();
        System.out.println("cls3 = " + cls3);

        // 4.通过类加载器获取到类的 Class 对象, 共4种
        // 先得到类加载器 car
        ClassLoader classLoader = car.getClass().getClassLoader();
        // 通过类加载器得到 Class 对象
        Class<?> cls4 = classLoader.loadClass(classAllPath);
        System.out.println("cls4 = " + cls4);


        // cls1, cls2, cls3, cls4 一模一样
        System.out.println("cls1.hashCode = " + cls1.hashCode());
        System.out.println("cls2.hashCode = " + cls2.hashCode());
        System.out.println("cls3.hashCode = " + cls3.hashCode());
        System.out.println("cls4.hashCode = " + cls4.hashCode());

        // 5.基本数据类型按如下方式跌倒CLass类对象
        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.class;
        Class<Boolean> booleanClass = boolean.class;
        // 输出的还是基本数据类型, 有一个自动装箱、拆箱的过程
        System.out.println("integerClass = " + integerClass);// int
        System.out.println("characterClass = " + characterClass);// char
        System.out.println("booleanClass = " + booleanClass);// boolean

        // 6.基本数据类型对应的包装类, 可以通过 .TYPE 对到 Class类对象
        Class<Integer> type = Integer.TYPE;
        Class<Character> type1 = Character.TYPE;
        Class<Boolean> type2 = Boolean.TYPE;
        // 还是会自动装箱拆箱
        System.out.println("type = " + type);
        System.out.println("type1 = " + type1);
        System.out.println("type2 = " + type2);

        System.out.println("integerClass.hashCode = " + integerClass.hashCode());// 1163157884
        System.out.println("type.hashCode = " + type.hashCode());// 1163157884
        // 二者相等, 说明基本数据类型及他的包装类的 Class类对象 是同一个
    }
}

运行结果:

反射获取类的结构信息

代码示例:

// 测试所用类
class PersonDad {
    public String dept;

    public PersonDad() {
    }

    public PersonDad(String dept) {
        this.dept = dept;
    }

    public void dadMethod() {
    }
}

interface PersonInterface {

}

@Deprecated // 弃用注解
class Person extends PersonDad implements PersonInterface {
    // 属性
    public String name = "JSON";
    protected int age = 20;
    String job = "study";
    private double sal = -100;
    static int a;
    final int b = 10;

    public Person() {
    }

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

    private Person(String dept, String job) {
        super(dept);
        this.job = job;
    }


    protected Person(String name, String job, String dept) {
        super(dept);
        this.name = name;
        this.job = job;
    }

    public Person(String dept, String name, int age, String job, double sal) {
        super(dept);
        this.name = name;
        this.age = age;
        this.job = job;
        this.sal = sal;
    }

    // 方法
    public void m1(String name, int age) {
    }

    protected int m2() {
        return 0;
    }

    String m3() {
        return null;
    }

    private void m4() {
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", job='" + job + '\'' +
                ", sal=" + sal +
                ", b=" + b +
                '}';
    }
}

获取类名

package com.flash.class_;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author flash
 * @date 2024/06/19 14:05
 * 功能描述:通过反射获取类的结构信息
 */
public class GetClassMessage {
    public static void main(String[] args) throws Exception {
        // 得到 Class 对象
        Class<?> personClass = Class.forName("com.flash.class_.Person");
        // getName:获取全类名
        System.out.println("获取全类名");
        System.out.println("name = " + personClass.getName());
        System.out.println("========================================");

        // getSimpleName:获取简单类名
        System.out.println("获取简单类名");
        System.out.println("SimpleName = " + personClass.getSimpleName());
        System.out.println("========================================");

运行结果:

获取属性

		// getFields:获取所有本类及其父类 public 修饰的属性
        System.out.println("获取所有本类及其父类 public 修饰的属性");
        for (Field field : personClass.getFields()) {
            System.out.println(field.getName());
        }
        System.out.println("========================================");

        // getDeclaredFields:获取本类所有属性, 只有本类的
        System.out.println("获取本类所有属性, 只有本类的");
        for (Field declaredField : personClass.getDeclaredFields()) {
            /*
            属性修饰符的值说明:
                默认修饰符: 0
                public: 1
                private: 2
                protected: 4
                static: 8
                final :16
                多修饰符时值相加
             */
            System.out.println(declaredField.getType().getSimpleName() + " " + declaredField.getName() + " 属性修饰符的值 = " + declaredField.getModifiers());
        }
        System.out.println("========================================");

运行结果:

获取方法

        // getMethods:获取本类及其父类 public 方法
        System.out.println("获取本类及其父类 public 方法");
        for (Method method : personClass.getMethods()) {
            System.out.println(method.getName());
        }
        System.out.println("========================================");

        // getDeclaredMethods:获取本类所有方法, 只有本类的
        System.out.println("获取本类所有方法, 只有本类的");
        for (Method declaredMethod : personClass.getDeclaredMethods()) {
            System.out.println(declaredMethod.getReturnType().getSimpleName() + " " + declaredMethod.getName() + " 方法修饰符的值 = " + declaredMethod.getModifiers());
            System.out.print("参数:");
            for (Class<?> parameterType : declaredMethod.getParameterTypes()) {
                System.out.print(parameterType.getSimpleName() + " ");
            }
            System.out.println();
        }
        System.out.println("========================================");

运行结果:

获取构造器

        // getConstructors:获取本类 public 构造器
        System.out.println("获取本类 public 构造器");
        for (Constructor<?> constructor : personClass.getConstructors()) {
            System.out.println(constructor.getName());
        }
        System.out.println("========================================");

        // getDeclaredConstructors:获取本类所有构造器
        System.out.println("获取本类所有构造器");
        for (Constructor<?> declaredConstructor : personClass.getDeclaredConstructors()) {
            System.out.println(declaredConstructor.getName());
            System.out.print("参数:");
            for (Class<?> parameterType : declaredConstructor.getParameterTypes()) {
                System.out.print(parameterType.getSimpleName() + " ");
            }
            System.out.println();
        }
        System.out.println("========================================");

运行结果:

获取包信息、父类、实现接口、注解信息

        // getPackage:获取包信息
        System.out.println("获取包信息");
        System.out.println("Package = " + personClass.getPackage());
        System.out.println("========================================");

        // getSuperclass:获取父类
        System.out.println("获取父类");
        System.out.println(personClass.getSuperclass());
        System.out.println("========================================");

        // getInterfaces:获取本类实现的接口
        System.out.println("获取本类实现的接口");
        for (Class<?> anInterface : personClass.getInterfaces()) {
            System.out.println(anInterface.getName());
        }
        System.out.println("========================================");

        // getAnnotations:获取注解信息
        System.out.println("获取注解信息");
        for (Annotation annotation : personClass.getAnnotations()) {
            System.out.println("annotation = " + annotation);
        }
    }
}

运行结果:

反射创建实例对象

package com.flash.class_;

import java.lang.reflect.Constructor;

/**
 * @author flash
 * @date 2024/06/19 15:11
 * 功能描述:通过反射创建对象
 */
public class CreateInstance {
    public static void main(String[] args) throws Exception {
        // 1.获取 Person 类的 Class对象
        Class<?> userClass = Class.forName("com.flash.class_.Person");

        // 2.通过public无参构造器创建实例对象
        Object o = userClass.newInstance();
        System.out.println("o = " + o);

        // 3.通过public构造器创建实例对象
        // 3.1 创建对应构造器
        Constructor<?> constructor = userClass.getConstructor(String.class);
        /*
            此时 constructor构造器 对应
                public Person(String name) {
                    this.name = name;
                }
         */
        // 3.2 通过刚才创建的构造器对象传入实参创建对应对象
        Object o1 = constructor.newInstance("张三");
        System.out.println("o1 = " + o1);

        // 4.调用非public构造器
        // 4.1 创建对应构造器
        Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(String.class, String.class);
        // 4.2 本身不能使用 私有 的构造器, 可以设置允许使用, 暂时先理解为暴力破解
        declaredConstructor.setAccessible(true);
        // 4.3 创建对象
        Object o2 = declaredConstructor.newInstance("山理工", "李四");
        System.out.println("o2 = " + o2);
        System.out.println(userClass.getField("dept").get(o2));

        // 5.试一下protected
        Constructor<?> constructor1 = userClass.getDeclaredConstructor(String.class, String.class, String.class);
        // 非私有的构造方法方法不需要破解也可以使用
        Object o3 = constructor1.newInstance("老六", "happy", "打妖怪");
        System.out.println("o3 = " + o3);
        System.out.println(userClass.getField("dept").get(o3));
    }
}

运行结果:

反射访问属性

package com.flash.class_;

import java.lang.reflect.Field;

/**
 * @author flash
 * @date 2024/06/19 16:13
 * 功能描述:反射访问类中的属性及修改
 */
public class AskProperty {
    public static void main(String[] args) throws Exception {
        Class<?> stuClass = Class.forName("com.flash.class_.Student");
        Object o = stuClass.newInstance();
        // o的运行类型已经是 Student 了
        System.out.println("o的运行类型 = " + o.getClass());
        // 使用反射得到 age 属性对象
        Field age = stuClass.getField("age");
        age.set(o, 88);
        System.out.println(o);
        // 使用反射操作 name 属性, 私有且静态
        Field name = stuClass.getDeclaredField("name");
        // 破解
        name.setAccessible(true);
        // 赋值
        name.set(null, "JSON");// 可以为 null, 因为 name 属性就是静态的
        // name.set(o, "JSON");
        // 输出
        System.out.println(o);
        // 获取单一属性
        System.out.println(name.get(o));// 获取属性 name 的值
    }
}

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

    public Student() {
    }

    private static String staticMethod() {
        System.out.println("我是私有的静态方法");
        return "私有的静态方法";
    }

    public void hi(String s) {
        System.out.println("hi~" + s);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name=" + name + ", " +
                "age=" + age +
                '}';
    }
}

运行结果:

反射调用方法

package com.flash.class_;

import java.lang.reflect.Method;

/**
 * @author flash
 * @date 2024/06/19 16:24
 * 功能描述:通过反射调用方法
 */
public class UseMethod {
    public static void main(String[] args) throws Exception {
        Class<?> stuClass = Class.forName("com.flash.class_.Student");
        // 创建一个 Student 对象
//        Object o = stuClass.newInstance();
        Object o = stuClass.getConstructor().newInstance();

        // 调用 public 方法
        Method hi = stuClass.getMethod("hi", String.class);
//        Method hi = stuClass.getDeclaredMethod("hi", String.class);
        // 调用 对象o 的 hi 方法
        hi.invoke(o, "JSON");

        // 调用私有的静态方法
        Method staticMethod = stuClass.getDeclaredMethod("staticMethod");
        // 爆破
        staticMethod.setAccessible(true);
        // 调用方法
        Object invoke = staticMethod.invoke(null);// 返回类型统一为 Object类型, 运行类型该是什么还是什么
        System.out.println("返回值invoke运行类型: " + invoke.getClass());
        System.out.println("invoke = " + invoke);
//        System.out.println(staticMethod.invoke(o));// 因为是静态方法, 所以有没有指定对象都可以调用
    }
}

运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1851728.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

扫码称重上位机

目录 一 设计原型 二 后台代码 一 设计原型 模拟工具: 二 后台代码 主程序&#xff1a; using System.IO.Ports; using System.Net; using System.Net.Sockets; using System.Text;namespace 扫码称重上位机 {public partial class Form1 : Form{public Form1(){Initialize…

人脸特征标注——OpenCV

特征标注 导入必要的库创建窗口显示原始图片和标注后的图片存储用户选择的图片路径字体样式和大小定义了select_image函数定义了annotate_landmarks()函数设置按钮调整图片标签的位置设置图片位置主事件循环运行显示&#xff1a;全部代码 导入必要的库 import tkinter as tk: 导…

docker 环境部署

1.Redis部署 用docker拉取redis镜像 docker pull redis 用docker查看拉取的镜像版本号&#xff0c;这里查到的是 6.2.6 版本 docker inspect redis 通过wget指令下载对应版本的tar包&#xff0c;下载完成后解压 wget https://download.redis.io/releases/redis-6.2.6.tar.gz …

多客陪玩系统源码支持二次开发陪玩预约系统搭建,打造专业游戏陪玩平台

简述 随着电竞行业的快速发展&#xff0c;电竞陪玩APP正在逐渐成为用户在休闲娱乐时的首选。为了吸引用户和提高用户体验&#xff0c;电竞陪玩APP开发需要定制一些特色功能&#xff0c;并通过合适的盈利模式来获得收益。本文将为您介绍电竞陪玩APP开发需要定制的特色功能以及常…

算法05 模拟算法之二维数组相关内容详解【C++实现】

大家好&#xff0c;我是bigbigli&#xff0c;前面一节我们一节讲过一维数组的模拟了&#xff0c;如果还没看的话&#xff0c;可以&#x1f449;点击此处。模拟算法还有很多内容需要讲&#xff0c;比如图像、日期相关的模拟算法&#xff0c;后续将继续更新&#xff0c;今天先来讲…

遗传算法求解时间窗车辆路径规划问题(附python代码)

摘要 本研究提出了一种基于遗传算法的车辆路径规划&#xff08;VRP&#xff09;问题求解框架&#xff0c;它能够有效地处理一系列复杂约束&#xff0c;包括软时间窗、硬时间窗、行驶距离限制、车辆最大载重量、多个配送中心的协调、特定的配送顺序&#xff0c;以及多种车型的选…

MyBatis-Plus 查询不到数据,但使用 SQL 可以查询到数据的问题排查

目录 前言 一、问题描述 示例代码 二、排查步骤 1. 检查数据源配置 2. 检查实体类与数据库表结构 3. 检查 Mapper 接口 4. 检查 MyBatis-Plus 配置 5. 排查查询条件 6. 检查日志输出 7. 检查数据库连接问题 8. 检查全局配置和插件 三、解决方案 前言 在开发过程中&…

【docker入门】

在软件开发过程中&#xff0c;环境配置是一个至关重要的步骤&#xff0c;它不仅影响开发效率&#xff0c;也直接关联到软件的最终质量。正确的环境配置可以极大地减少开发中的潜在问题&#xff0c;提升软件发布的流畅度和稳定性。以下是几个关键方面&#xff0c;以及如何优化环…

《窄门》读后感

《窄门》这本书是端午节期间在地铁和高铁上看完的&#xff0c;书的故事很简单&#xff0c;描绘的是一段爱而不得的感情。但是&#xff0c;这本书写的爱而不得和其他地方的爱而不得完全不是一码事&#xff0c;其他地方的爱而不得要么是“落花有意随流水&#xff0c;流水无意恋落…

EasyX 文本输出(自定义)函数报错

EasyX 文本输出&#xff08;自定义&#xff09;函数报错记录 原因:EasyX与字符串相关的函数,都有字符集问题 UNICODE 多字节字符集

java干货,spring声明式事务

文章目录 一、编程式事务1.1 什么是编程式事务1.2 编程式事务的优缺点 二、声明式事务2.1 什么是声明式事务2.2 声明式事务的优点2.3 Spring 事务管理器2.4 spring 声明式事务使用 一、编程式事务 1.1 什么是编程式事务 编程式事务是指通过手动编写程序来管理事务&#xff0c…

C#利用SignalR实现通信事例Demo

1.服务端安装SignalR的Nuget包 dotnet add package Microsoft.AspNet.SignalR --version 2.4.3 2.接下来&#xff0c;创建一个ChatHub类&#xff0c;它是SignalR通信的核心&#xff1a; using Microsoft.AspNetCore.SignalR;public class ChatHub : Hub {public static Dict…

苹果mac电脑救星CleanMyMac让我的电脑重获新生!

&#x1f389; 发现电脑的救星&#xff01;CleanMyMac让我的电脑重获新生&#xff01; CleanMyMac绿色免费版下载如下&#xff1a;记得保存哈&#xff0c;以防失效&#xff1a; https://pan.quark.cn/s/9b08114cf404 CleanMyMac X2024全新版下载如下: https://wm.makeding.…

awdawdad

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年6月20日 最后&#xff1a; 十分感谢你可以耐着性子把它读完和我可以坚持写到这里&#xff0c;送几句话&#xff0c;对你&#xff0c;也对我&#xff1a; 1.一个冷知识&#xff1a; …

多路h265监控录放开发-(9)通过拖拽到窗口完成渲染

xcamera_widget.h class XCameraWidget :public QWidget {Q_OBJECTpublic:XCameraWidget(QWidget* p nullptr);//渲染视频void Draw();//123//清理资源,再一个窗口被覆盖后 清理之前窗口生成的资源1~XCameraWidget();//123 private:XDecodeTask* decode_ nullptr;//123XDemu…

高考填报志愿选专业,要善于发掘自身优势

每年的高考季&#xff0c;如何填报志愿又再成为困扰家长以及学生的难题&#xff0c;可能在面对大量的专业时&#xff0c;无论是考生还是家长都不知道应该如何选择&#xff0c;好的专业孩子不一定有优势&#xff0c;感兴趣的冷门专业又担心日后找工作难。 实际上&#xff0c;专业…

购买服务器,并安装宝塔

前言&#xff1a; 我们在开发项目时&#xff0c;总会遇到一个问题&#xff0c;就是将我们开发好的项目上传的公网中。对于中小型的项目&#xff0c;我们可以通过购买服务器进行项目的上线。 我们的项目一般是部署在Linux环境中。如果你不是专业的运维人员&#xff0c;可能对于…

『这世界上有无忧无虑的孩子,和永远焦虑的父母』

昨天&#xff0c;准确说是今天&#xff0c;凌晨两点多&#xff0c;被队友薅起来&#xff0c;严肃认真地讨论孩子的教育问题。 我们家的小神兽六岁&#xff0c;一年级了。从去年幼升小的阶段&#xff0c;我们就计划着好好培养孩子&#xff0c;在这一年间&#xff0c;给小朋友报过…

Linux下VSCode的安装和基本使用

应用场景&#xff1a;嵌入式开发。 基本只需要良好的编辑环境&#xff0c;能支持文件搜索和跳转&#xff0c;就挺OK的。 之所以要在Linux下安装&#xff0c;是因为在WIN11上安装后&#xff0c;搜索功能基本废了&#xff0c;咋弄都弄不好&#xff0c;又不方便重装win系统&#x…

HTTP网络协议

1.HTTP &#xff08;1&#xff09;概念&#xff1a; Hyper Text Transfer Protocol&#xff0c;超文本传输协议规定了浏览器和服务器之间数据传输的规则。 &#xff08;2&#xff09;特点 基于TCP协议:面向连接&#xff0c;安全基于请求-响应模型的:一次请求对应一次响应HTTP协…