Java032——反射(Reflection)

news2024/10/6 20:39:36

一、Java中的反射及作用

Java的反射(reflection)机制是指在程序的运行状态中:

  1. 可以构造任意一个类的对象,
  2. 可以了解任意一个对象所属的类,
  3. 可以了解任意一个类的成员变量和方法,
  4. 可以调用任意一个对象的属性和方法。

一句话:这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。

二 认识.class类对象

这里回忆以下类的对象,然后举例说明.Class 类对象

2.1、类的对象

什么是类对象? 比如Dog类 Dog dog = new Dog();
dog 就是Dog类的对象。

2.2、Class 类型的对象

  1. 因为在Java中万物皆为对象,所以Dog 类也是一个对象,那他是谁的对象呢?
  2. 加载完类之后,在堆内存的方法区中就 产生了一个Class类型的对象(一个类只有一个Class对象),例如Dog类加载完成后,就会产生一个Dog 的Class类型对象
  3. 这个对象就像一面镜子,透过这个镜子看到类的结构,所以,才称这个为: 反射
  4. 这个对象包含了完整的类结构的信息( 类名 包名 实现接口 继承类 属性 方法 构造器 注解.... )

三、获取.class类对象

正常情况下,我们定义了一个类,要获得它的实例,是需要通过new关键字获取的,例如

class Dog{//定义了一个Dog
    //私有属性
    private String name = "Tom";
    //公有属性
    public int age = 18;
    
    //构造方法
    public Dog() {
    
    }
    //私有方法
    private void say(){
        System.out.println("private say()...");
    }
    //公有方法
    public void run(){
        System.out.println("狗急跳墙");
    }
}

class TestDemo{
    public static void main(String[] args) {
        Dog dog = new Dog();//通过关键字new获得Dog的一个对象dog

        dog.run();//dog对象调用run方法
    }
}

//运行结果
狗急跳墙

3.1、反射机制获取

一个类被加载后,类的整个结构都会被封装在Class对象中
在这里插入图片描述
下面创建一个Dod类,类里面只有一个成员方法run()

package MyPackage;

class Dog{//一个类被加载后,类的整个结构都会被封装在Class对象中
    //公有方法
    public void run(){
        System.out.println("狗急跳墙");
    }
}

public class TestDemo{
    public static void main(String[] args) throws ClassNotFoundException {
//      1、方式一:通过对象获得
//      通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object
//      类型的对象,而我不知道你具体是什么类,用这种方法
        Dog dog = new Dog();
        Class c1 = dog.getClass();

        //2、方式二:通过类名 .class 获得
        // 该方法最为安全可靠,程序性能更高
        // 这说明任何一个类都有一个隐含的静态成员变量 class
        Class c2 = Dog.class;

        //3、 方式三:forName获得
        Class c3 = Class.forName("MyPackage.Dog");

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);

    }
}

//运行结果
class MyPackage.Dog
class MyPackage.Dog
class MyPackage.Dog

四、反射一般都用来做什么

  1. 可以构造任意一个类的对象,
  2. 可以了解任意一个对象所属的类,
  3. 可以了解任意一个类的成员变量和方法,
  4. 可以调用任意一个对象的属性和方法。

4.1、构造类的对象

package MyPackage;

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

class Dog {//一个类被加载后,类的整个结构都会被封装在Class对象中
    //私有属性
    private String name = "旺财";
    //公有属性
    public int age = 2;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //无参构造方法
    public Dog() {

    }

    //有参构造方法
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //公有方法
    public void run() {
        System.out.println(this.name+"狗急跳墙,"+this.age+"岁");
    }
}

public class TestDemo {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

        Class c1 = Class.forName("MyPackage.Dog");
        //1.通过动态调用构造方法,构造对象
        System.out.println("-------------------");
        Dog dog1 = (Dog) c1.newInstance();
        dog1.run();

        //2.通过有参构造创建对象
        System.out.println("-------------------");
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class);
        Dog dog2 = (Dog)declaredConstructor.newInstance("小黑",4);
        dog2.run();

       // 3.调用普通方法
        System.out.println("-------------------");
        Dog dog3 = (Dog)c1.newInstance();
        Method setName = c1.getDeclaredMethod("setName", String.class);
        Method setAge = c1.getDeclaredMethod("setAge", int.class);
        setName.invoke(dog3,"小黄");
        setAge.invoke(dog3,1);
        dog3.run();

        // 4.获得指定成员变量
        System.out.println("--------------------");
        Dog dog4 = (Dog)c1.newInstance();
        Field name = c1.getDeclaredField("name");
        Field age = c1.getDeclaredField("age");
        name.setAccessible(true);

        name.set(dog4,"小白");
        age.set(dog4,3);

        dog4.run();
    }
}

//运行结果
-------------------
旺财狗急跳墙,2-------------------
小黑狗急跳墙,4-------------------
小黄狗急跳墙,1--------------------
小白狗急跳墙,3

4.2、获得类的信息

4.2.1、通过反射可访问的主要描述信息

在这里插入图片描述

4.3、访问构造方法

4.3.1、Constructor 类的常用方法

在这里插入图片描述
通过 java.langreflect.Modifier 类可以解析出 getModifiers0方法的返回值所表示的修饰符信息,在该类中提供了一系列用来解析的静态方法,既能查看是否被指定的修饰符修饰,又能以字符串的形式获得所有修饰符。

Modifier 类中的常用解析方法
在这里插入图片描述
例如,判断对象 constructor 所代表的构造方法是否被 private 修饰,以及以字符串形式获得该构造方法的所有修饰符的典型代码如下:

int modifiers = constructor.getModifiers();
boolean isEmbellishByPrivate = Modifier.isPrivate(modifiers);
String embellishment = Modifier.toString(modifiers);

4.4、访问成员变量

4.4.1、Field 类的常用方法

在这里插入图片描述

4.5、访问成员方法

4.5.1、Method 类的常用方法

在这里插入图片描述

五、java类反射中所必须的类

java的类反射所需要的类并不多,它们分别是:field、constructor、method、class、object,下面将对这些类做一个简单的说明。

5.1、field类

提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。

5.2、constructor类

提供关于类的单个构造方法的信息以及对它的访问权限。这个类和field类不同,field类封装了反射类的属性,而constructor类则封装了反射类的构造方法。

5.3、method类

提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。这个类不难理解,它是用来封装反射类方法的一个类。

5.4、class类

类的实例表示正在运行的 java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 class 对象。

5.5、object类

每个类都使用 object 作为超类。所有对象(包括数组)都实现这个类的方法。

5.6、示例

  1. 获取类对象
    可以使用Class.forName()方法通过类的全限定名获取类对象。

    Class<?> cls = Class.forName("com.example.MyClass");
    
  2. 创建对象
    使用类对象的newInstance()方法可以创建类的实例。

    Object obj = cls.newInstance();
    
  3. 获取方法
    使用类对象的getMethod()方法可以获取指定名称和参数类型的公共方法。

    Method method = cls.getMethod("methodName", parameterTypes);
    
  4. 调用方法
    使用方法对象的invoke()方法可以调用方法。

    Object result = method.invoke(obj, args);
    
  5. 获取字段
    使用类对象的getField()方法可以获取指定名称的公共字段。

    Field field = cls.getField("fieldName");
    
  6. 设置字段的值
    使用字段对象的set()方法可以设置字段的值。

    field.set(obj, value);
    

以上仅是一些基本的反射操作示例,反射还有很多其他强大的功能,比如获取和操作私有方法/字段、获取注解信息、动态代理等。

需要注意的是,反射操作可能会带来性能上的开销,并且因为绕过了编译时的类型检查,容易导致类型错误,在使用反射时需要谨慎操作。

六、基本的反射操作示例

package MyPackage;

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

class Dog {//一个类被加载后,类的整个结构都会被封装在Class对象中
    //私有属性
    private String name = "旺财";
    //公有属性
    public int age = 2;

    protected String color="土黄色";

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //无参构造方法
    public Dog() {

    }

    //有参构造方法
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //私有方法
    private void say() {
        System.out.println("我叫"+this.name+"今年"+this.age+"岁");
    }


    //公有方法
    public void run() {
        System.out.println(this.name+"狗急跳墙,"+this.age+"岁");
    }
}

public class TestDemo {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

        //获得名字
        System.out.println("--------------------获得名字");
        Class c1 = Class.forName("MyPackage.Dog");
        System.out.println(c1.getName());//获得类完整的名字,包括包名
        System.out.println(c1.getSimpleName());//只有方法名

        //获得类的public类型的属性(只能获取public修饰的)
        System.out.println("--------------------获得属性(只能获取public修饰的)");
        Field[] fields = c1.getFields();//获得类的public属性
        for (Field field : fields) {
            System.out.println(field);
        }

        //获得类的全部属性。包括私有的
        System.out.println("--------------------获得类的全部属性");
        Field[] declaredFields = c1.getDeclaredFields();//获得类的全部属性
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        //获得类的public类型的方法。这里包括 Object 类的一些方法
        System.out.println("--------------------获得方法");
        Method[] methods = c1.getMethods();//获得本类及其父类的所有public方法
        for (Method method : methods) {
            System.out.println(method);
        }

        //获得本类所有方法
        System.out.println("--------------------获得本类所有方法");
        Method[] declaredMethods = c1.getDeclaredMethods();//获得本类所有方法
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        //获得指定的属性
        System.out.println("--------------------获得指定的属性");
        Field age = c1.getField("age");
        System.out.println(age);

        //获得指定的私有属性
        System.out.println("--------------------获得指定的私有属性");
        Field name= c1.getDeclaredField("name");
		//启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消
        name.setAccessible(true);
        System.out.println(name);

        //获取所有构造方法
        System.out.println("--------------------获取所有构造方法");
        Constructor[] constructors = c1.getConstructors();
        for(Constructor constructor : constructors){
            System.out.println(constructor.toString());//public com.ys.reflex.Person()
        }
    }
}

//运行结果
--------------------获得名字
MyPackage.Dog
Dog
--------------------获得属性(只能获取public修饰的)
public int MyPackage.Dog.age
--------------------获得类的全部属性
private java.lang.String MyPackage.Dog.name
public int MyPackage.Dog.age
protected java.lang.String MyPackage.Dog.color
--------------------获得方法
public void MyPackage.Dog.setAge(int)
public void MyPackage.Dog.run()
public java.lang.String MyPackage.Dog.getName()
public void MyPackage.Dog.setName(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
--------------------获得本类所有方法
public void MyPackage.Dog.setAge(int)
private void MyPackage.Dog.say()
public void MyPackage.Dog.run()
public java.lang.String MyPackage.Dog.getName()
public void MyPackage.Dog.setName(java.lang.String)
--------------------获得指定的属性
public int MyPackage.Dog.age
--------------------获得指定的私有属性
private java.lang.String MyPackage.Dog.name
--------------------获取所有构造方法
public MyPackage.Dog(java.lang.String,int)
public MyPackage.Dog()

Process finished with exit code 0

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

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

相关文章

数据结构day2(2023.7.15)

一、Xmind整理&#xff1a; 二、课上练习&#xff1a; 练习1&#xff1a;定义车的信息&#xff1a;品牌&#xff0c;单价&#xff0c;颜色&#xff0c;车牌号 struct Car{char name[20]; //品牌int price; //单价char color[10] //颜色char id[20] //车牌…

Spring【 Spring整合MyBatis、SpringAOP(AOP简介 、AOP相关术语、AOP入门)】(五)-全面详解(学习总结---从入门到深化)

目录 Spring整合MyBatis_准备数据库和实体类 Spring整合MyBatis_编写持久层接口和service类 Spring整合MyBatis_Spring整合Junit进行单元测试 Spring整合MyBatis_自动创建代理对象 SpringAOP_AOP简介 SpringAOP_AOP相关术语 SpringAOP_AOP入门 Spring整合MyBatis_准备数据…

推荐几个github上非常受欢迎的库

推荐几个github上非常受欢迎的库 The Book of Secret Knowledge the-book-of-secret-knowledge 这个仓库里边包含了一系列非常有趣的手册、备忘单、博客、黑客、单行话、cli/web 工具等。 Coding Interview University coding-interview-university 这里列出的项目可以帮助…

基于Ubuntu20.4的TMS320C6678开发环境(CCS8.3.1)的搭建

网上关于ccs的安装大多是基于ccs5及以前的版本安装介绍或基于windows版本的ccs软件的安装,没有关于linux系统上安装CCS8.3.1的集成开发环境。本文介绍在ubuntu20.4的系统上安装ccs8.3.1的DSP开发环境&#xff0c;本文包括CCS软件和插件的下载&#xff0c;安装。本文在ubuntu20.…

fpga下载程序到flash后无法在重新上电后自动加载程序

可能是接的调试器没有断电&#xff0c;断电一次再给调试器上电。如果调试器一直连着可以连续断电上电fpga开发板&#xff0c;直到成功。fpga貌似上电后什么程序都不加载则引脚为高电平&#xff0c;而vivado默认.xdc的BITSTREAM.CONFIG.UNUSEDPIN&#xff08;未使用的引脚&#…

vue3 - 01搭建工程

1. 使用vue-cli创建工程 1. 命令&#xff1a;vue create xxx2. 选择vue3版本3. 进入目录4. 运行&#xff1a; npm run serve 在执行完运行指令后如果报错请查看是否是以下错误&#xff0c;如果是可以按以下步骤进行解决&#xff1a; ERROR in Conflict: Multiple assets emit …

命令执行绕过

首先以一道BUUCTF题目来开下胃 查看flag&#xff1a; 其次给大家上主菜-----命令执行绕过 命令执行漏洞绕过方式&#xff1a; 管道符 windows中常见管道符&#xff1a; | 直接执行后面的语句 || 如果前面命令是错的那么就执行后面的语句&#xff0c;否则只执行前面的语…

DEV C++ 更改界面语言

第一步&#xff1a;选中tools&#xff0c;然后从里面找Environment optional 第二步&#xff1a;从里面找到Language选项&#xff0c;找到简体中文 选中简体中文后点击“OK”就可以了

go语言 socket: too many open files 错误分析

问题背景&#xff1a; 近期针对老的PHP接口做了迁移重构&#xff0c;用golang重新实现&#xff0c;在上线之前&#xff0c;测试进行了压测&#xff0c;压测的量级为&#xff1a;200请求/s, 连续请求10s&#xff0c;发现接口出现大量超时错误&#xff0c;查看日志发现错误信息为…

前缀和模板算法

一)模板前缀和 【模板】前缀和_牛客题霸_牛客网 (nowcoder.com) 前缀和:快速的得出数组中某一段连续区间的和 暴力破解的话需要从头到尾的进行遍历&#xff0c;时间复杂度就可以达到O(N)&#xff0c;而前缀和时间复杂度是可以达到O(1)的 第一步:预处理创建出一个前缀和数组dp&a…

RTMP简介

简介 RTMP协议是Real Time Message Protocal(实时传输协议的缩写)&#xff0c;同时Adobe公司提供的一种应用层协议&#xff0c;用来解决多没意思数据流传输的 多路复用和分包问题。 RTMP是应用层协议&#xff0c;采用TCP来保证可靠的传输在TCP完成握手连接建立后&#xff0c…

【动手学深度学习】--03.多层感知机MLP

文章目录 多层感知机1.原理1.1感知机1.2多层感知机MLP1.3激活函数 2.从零开始实现多层感知机2.1初始化模型参数2.2激活函数2.3 模型2.4损失函数2.5训练 3.多层感知机的简洁实现3.1模型3.2训练 多层感知机 1.原理 官方笔记&#xff1a;多层感知机 1.1感知机 训练感知机 收敛定…

SEO 基础知识? 2023学习SEO最佳指南

文章目录 搜索引擎优化基础知识什么是搜索引擎优化&#xff1f;为什么搜索引擎优化很重要&#xff1f;SEO有什么好处&#xff1f;如何做搜索引擎优化关键词研究内容优化网站结构优化&#xff08;页面SEO&#xff09;外部链接优化移动优化分析和迭代(技术SEO) 为 SEO 成功做好准…

蓝牙技术|低功耗蓝牙和LE Audio助力游戏设备行业发展

去年&#xff0c;蓝牙技术联盟官方宣布推出LE Audio&#xff0c;它以BLE为基础&#xff0c;旨在更好地兼顾音频质量和低功耗&#xff0c;以在多种潜在应用中显著增强用户体验。这在游戏行业中引起了轰动&#xff0c;由于其延迟显著降低&#xff0c;LE Audio在增强游戏体验方面展…

单片机第一季:零基础9——直流电机和步进电机

目录 1&#xff0c;直流电机 2&#xff0c;步进电机 1&#xff0c;直流电机 直流电机是指能将直流电能转换成机械能&#xff08;直流电动机&#xff09;或将机械能转换成直流电能&#xff08;直流发电机&#xff09;的旋转电机。它是能实现直流电能和机械能互相转换的电机。…

Jenkins的安装部署以及基本使用

前言&#xff1a; 今天有空大概记录的一个作为一个测试人员日常中Jenkins的使用。 一、环境准备 在安装使用Jenkins前我们要先安装jdk&#xff0c;这里博主选择的是jdk11。我们先删除旧的jdk然后安装全新的jdk。 1、先看下当前我们的jdk版本。 2、查看jdk安装路径&#xff1…

Simulink仿真模块 - Unit Delay

Unit Delay:将信号延迟一个采样期间 在仿真库中的位置为:Simulink / Discrete HDL Coder / Discret 模型为: 双击模型打开参数设置界面,如图所示: 说明 Unit Delay 模块按指定的采样期间保持和延迟输入。当放置于迭代子系统中时,该模块将其输入保持并延迟一个迭代。此…

视频文件一键批量去除水印需要用到什么剪辑软件

刚接触视频剪辑这个行业的小伙伴在找视频素材的过程中&#xff0c;如果发现视频带有水印是不是非常头疼&#xff0c;不知道怎么处理这件事。那今天我们就来聊聊怎么才能快速批量去除视频的水印呢&#xff1f;今天小编给大家带来一个好方法&#xff0c;一起来看看吧。 一、首先我…

Redis实战案例17-Redisson可重入的原理

可重入原理分析 为什么自定义的Redis实现分布式锁不能实现可重入 method1中调用了method2方法&#xff0c;属于是同一线程内的操作&#xff0c;但是当method1中获取了锁之后&#xff0c;method2中就无法获取锁了&#xff0c;这就是同一线程无法实现可重入&#xff1b; 如何解决…

Windows上查看服务器上tensorboad内容

文章目录 前言一、SSH的设置二、tensorboard命令 前言 本篇文章是针对于局域网内的服务器的tensorboard可视化&#xff0c;由于设置方式稍微有点复杂&#xff0c;导致我每次隔了一段时间之后&#xff0c;就不知道该怎么查看tensorboard了&#xff0c;每次都要百度搜一大堆资料…