反射获取list泛型_Android 从浅到懂使用反射机制

定义

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

使用场景

反射是在运行时获取确定类型,绑定对象。

常见的两个使用场景

  1. 运行时获取对象的所有信息
  2. 泛型擦除

在运行时获取类

这里的运行时指的是程序在运行后。相应的还有编译时,编译时是编译器将源代码翻译成机器能识别的代码。

举个例子说明编译时和运行时的区别:155750c0c8c5046a5d731ae6d4fad955.png

泛型擦除

示例:设定集合是Int,但是最后输出的集合中包含String,这就实现了泛型擦除功能。

val list = arrayListOf(1,2,3)
val clz = Class.forName("java.util.ArrayList")
val method = clz.getMethod("add", Object::class.java)method.invoke(list,"hhh")Log.e(TAG,"list:${list.toString()}")
输出:
list:[1, 2, 3, hhh]

反射的利弊

  • 运行时类型的判断
  • 动态类加载,动态代理使用反射。

  • 性能问题,反射相当于一系列解释操作。
  • JVM 不会去优化这部分代码
  • 代码不易阅读

为什么会出现性能问题?

  1. Method#invoke 方法会对参数做封装和解封操作
  2. 需要检查方法可见性
  3. 需要校验参数
  4. 反射方法难以内联
  5. JVM 无法优化: Java 文档中介绍

invoke方法源码:

class Class {
    @CallerSensitive
    public Method getMethod(String name, Class>... parameterTypes)throws NoSuchMethodException, SecurityException {
        Objects.requireNonNull(name);
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // 1. 检查方法权限
            checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
        }
        // 2. 获取方法
        Method method = getMethod0(name, parameterTypes);
        if (method == null) {
            throw new NoSuchMethodException(methodToString(name, parameterTypes));
        }
        // 3. 返回方法的拷贝
        return getReflectionFactory().copyMethod(method);
    }

    @CallerSensitive
    public Method getDeclaredMethod(String name, Class>... parameterTypes)throws NoSuchMethodException, SecurityException {
        Objects.requireNonNull(name);
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // 1. 检查方法权限
            checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
        }
        // 2. 获取方法
        Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
        if (method == null) {
            throw new NoSuchMethodException(methodToString(name, parameterTypes));
        }
        // 3. 返回方法的拷贝
        return getReflectionFactory().copyMethod(method);
    }
}

如何使用

想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象。

获取字节码文件对象

  • 1、根据类名:类名.class
  • 2、根据对象:对象.getClass()
  • 3、根据全限定类名:Class.forName(全限定类名)

常用的是第一种。

获取构造函数

构造函数分为两种:带参和不带参

  • 获取不带参构造函数
Class classs = Class.forName("com.xxx.xxx.User");
Constructor constructor = classs.getDeclaredConstructor();
Object user = constructor.newInstance();
  • 获取带参构造函数
Class classs = Class.forName("com.xxx.xxx.User");
Constructor constructor = classs.getConstructor(int.class,String.class);
Object user = constructor.newInstance(1,"张三");

获取成员变量

成员变量一般为公有和私有

  • 获取公有成员变量
Class classs = Class.forName("com.xxx.xxx.User");
Constructor constructor = classs.getConstructor();
Object user = constructor.newInstance();
Field declaredField = classs.getField("userName");
// 赋新值
declaredField.set(user, "李四");
  • 获取私有成员变量
Class classs = Class.forName("com.xxx.xxx.User");
Constructor constructor = classs.getConstructor();
Object user = constructor.newInstance();
Field declaredField = classs.getDeclaredField("userName");
// 因为属性是私有的,所有需要打开可见权限
declaredField.setAccessible(true);
// 赋新值
declaredField.set(user, "李四");

获取方法

成员方法一般为公有和私有,同时方法也分有参和无参

  • 获取公有成员无参方法
Class classs = Class.forName("com.xxx.xxx.User");
Constructor constructor = classs.getConstructor();
Object user = constructor.newInstance();
Method method = classs.getMethod("getUserName");
method.invoke(user);
  • 获取公有成员有参方法
Class classs = Class.forName("com.xxx.xxx.User");
Constructor constructor = classs.getConstructor();
Object user = constructor.newInstance();
Method method = classs.getMethod("getUserName", String.class);
method.invoke(user, "王五");
  • 获取私有成员无参方法
Class classs = Class.forName("com.xxx.xxx.User");
Constructor constructor = classs.getConstructor();
Object user = constructor.newInstance();
Method method = classs.getDeclaredMethod("getUserName");
// 因为属性是私有的,所有需要打开可见权限
method.setAccessible(true);
method.invoke(user);
  • 获取私有成员有参方法
Class classs = Class.forName("com.xxx.xxx.User");
Constructor constructor = classs.getConstructor();
Object user =  constructor.newInstance();
Method method = classs.getDeclaredMethod("getUserName",String.class);
// 因为属性是私有的,所有需要打开可见权限
method.setAccessible(true);
method.invoke(user, "王五");

Tip

  1. 一般来说,构造函数大部分是 public ,而成员变量和方法大部分是private。public 权限直接正常调用即可、private需要在调用前增加 setAccessible(true)
  2. 获取构造函数、成员变量、成员方法都有一个获取所有的方法,根据需要去调用。如:getConstructor:获取单个构造函数,getConstructors:获取所有构造函数

总结

反射的作用是在运行时动态获取对象信息。

实现步骤:

  1. 获取 Class:有三种方式,常用的是 Class.forName("类全名称")
  2. 获取构造函数:通过 Class 对象调用 如:clz.getConstructor() 得到构造函数
  3. 创建对象:通过构造函数创建对象 如:con.newInstance()

没有 Declared 前缀会返回所有的 public 方法,包括父类的方法。而加 Declared 前缀会返回所有自己定义的方法,public,protected,private 都在此,但是不包括父类的方法。

这也正是 getMethodgetDeclaredMethod 的区别。

  • 获取私有构造函数
Class classs = Class.forName("com.xxx.xxx.User");
Constructor constructor = classs.getDeclaredConstructor();
// 因为属性是私有的,所有需要打开可见权限
constructor.setAccessible(true);
Object user = constructor.newInstance();

  • 获取私有成员变量
...
Field declaredField = classs.getDeclaredField("userName");
// 因为属性是私有的,所有需要打开可见权限
declaredField.setAccessible(true);

  • 获取私有成员方法
...
Method method = classs.getDeclaredMethod("getUserName");
// 因为属性是私有的,所有需要打开可见权限
method.setAccessible(true);

反射耗时的原因:

  • invoke方法需要做封装和解封操作
  • 需要类型检查、权限检查
  • 需要校验参数
  • 需要检查方法的可见性
  • JVM无法做优化

参考

  • Reflection:Java反射机制的应用场景
  • 深入浅出Java反射原理和使用场景
  • java反射机制详解
  • Java 反射 -超详细讲解(附源码)
  • java反射为什么慢
  • 强大的反射库 FreeReflection

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

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

相关文章

谷歌 recaptcha_在Spring Boot应用程序中使用Google reCaptcha

谷歌 recaptcha介绍 Google的reCaptcha是一个库,用于防止漫游器将数据提交到您的公共表单或访问您的公共数据。 在本文中,我们将研究如何将reCaptcha与基于Spring Boot的Web应用程序集成 设置验证码 您应该从管理面板创建API密钥。 您必须创建一个示例…

数学建模python教材推荐_数模竞赛专攻python应该准备什么?

想起以前打开Matlab就不忍心关掉的阴影(无SSD打开及其慢)。没有什么非要二选一,喜欢哪个用哪个都行,两个都试试比一比也行,比赛更不会关心你的结果图哪儿来的(小孩才。。。大人全都。。。)。Matlab有Matlab的好处,非常成熟的软件包…

python中if __name__ == ‘__main__‘:的简单理解

举例说明,这里有两个模块 # ni模块 print("这是1.") if __name__ __main__:print("这是2.")输出结果: 这是1.这是2. #wo模块 import ni print("这是3.")输出结果: 这是1这是3 总结: 运行自己的模块时会运行if _…

Linux 命令之 wget -- 下载文件工具

文章目录一、命令介绍二、命令语法三、常用选项四、命令示例(一)下载并以不同的文件名保存(二)下载单个文件(三)限速下载(四)断点续传(五)使用 wget 后台下载…

创建react应用程序_使用SpringWebFlux的React式Web应用程序

创建react应用程序1.React式编程简介 React式编程是为具有以下特征的应用程序创造的术语: 非阻塞应用 事件驱动和异步 需要少量线程来垂直扩展(即在JVM中) 就像面向对象的编程,函数式编程或过程式编程一样,React式…

获取当地天气_Mac 天气预报动态壁纸工具Living Weather HD 4.4.4

这款独特的非凡应用程序将天气呈现在您的桌面上,它能够预报天气状况,并在桌面上使用相应的美丽动态壁纸场景。 天气HD也可以用作屏保。 主要功能: ● 在桌面上了解世界各地当前的天气状况和未来状况 ● 与当前天气状况、今天或明天预报相应的…

Linux 命令之 curl 的选项(英文版)

Usage: curl [options...] <url> Options: (H) means HTTP/HTTPS only, (F) means FTP only--anyauth Pick "any" authentication method (H) 可以使用“任何”身份验证方法-a, --append Append to target file when uploading (F/SFTP) 上传文件…

获取文件夹下的文件名并存入txt中

import os path_imgsC:/Users/13451/Desktop/pic #图片存放的地址 for files in os.listdir(path_imgs): #listdir函数获取文件夹下图片的名字,返回包含所有文件名字的列表with open(C:/Users/13451/Desktop/train_data.txt,a) as f: f.write(files.rstrip(.png)) #只保存名…

javaparser_JavaParser生成,分析和修改Java代码

javaparser作为开发人员&#xff0c;我们经常鄙视手动进行重复工作的人员。 我们认为&#xff0c; 他们应该实现这一目标 。 尽管如此&#xff0c;我们还是进行与编码有关的所有活动。 当然&#xff0c;我们使用的高级IDE可以为我们执行一些重构&#xff0c;但这基本上就结束…

计算机系统组成_网络教育统考计算机应用基础题库(计算机系统的组成2)

点击蓝字关注我哦11在微型计算机的各种设备中&#xff0c;既用于输入又可用于输出的设备是____。A、磁盘驱动器B、键盘C、鼠标D、绘图仪点击空白处查看答案参考答案:A12计算机的硬件系统由五大部分组成&#xff0c;下列各项中不属于这五大部分的是______。A、运算器B、软件C、I…

深度学习基础实战使用MNIST数据集对图片分类

本文代码完全借鉴pytorch中文手册 我们找到数据集&#xff0c;对数据做预处理&#xff0c;定义我们的模型&#xff0c;调整超参数&#xff0c;测试训练&#xff0c;再通过训练结果对超参数进行调整或者对模型进行调整。 import torch import torch.nn as nn import torch.nn.f…

Linux 命令之 curl -- 文件传输工具/下载工具/网络接口调试

文章目录 一、命令介绍二、常用选项三、wget 与 curl 对比四、命令示例(一)以 post 方式提交数据/以 post 方式传递请求参数(二)查看网页的源码内容(三)保存访问的网页源码内容(四)将服务器的回应保存成文件/将输出保存成文件(五)显示 http response 头信息,打印出服…

python cookie使用_Python使用cookielib模块操作cookie的实例教程

cookielib是一个自动处理cookies的模块&#xff0c;如果我们在使用爬虫等技术的时候需要保存cookie&#xff0c;那么cookielib会让你事半功倍&#xff01;他最常见的搭档模块就是python下的urllib和request。核心类1.Cookie该类实现了Netscape and RFC 2965 cookies定义的cooki…

pytorch中unsqueeze()函数理解

unsqueeze()函数起升维的作用,参数表示在哪个地方加一个维度。 在第一个维度(中括号)的每个元素加中括号 0表示在张量最外层加一个中括号变成第一维。 直接看例子: import torch inputtorch.arange(0,6) print(input) print(input.shape) 结果&#xff1a; tensor([0, 1, 2, 3…

Linux 命令之 ifconfig -- 配置和显示网卡的网络参数

文章目录一、命令介绍二、常用选项三、参考示例&#xff08;一&#xff09;显示网络设备信息&#xff08;激活状态的&#xff09;&#xff08;二&#xff09;启动关闭指定网卡&#xff08;三&#xff09;显示所有配置的网络接口&#xff0c;不论其是否激活&#xff08;四&#…

版本交付_连续交付友好的Maven版本

版本交付持续交付管道需要可预测的软件和依赖版本。 Maven软件项目中常见的快照版本与“持续交付”背后的动机背道而驰。 为了将快照版本更新为发行版本&#xff0c;开发人员通常手动或通过诸如maven-release-plugin来编辑pom.xml文件。 但是&#xff0c;Maven还提供了将版本号…

shell开启飞行模式_今天才知道,原来手机的飞行模式用处那么多,看完涨知识了...

想必大家都知道&#xff0c;手机里有个飞行模式&#xff0c;是在乘坐飞机时使用的。其实除了这个功能之外&#xff0c;飞行模式还有很多其他的妙用&#xff0c;下面笔者就为大家一一进行介绍。一、 加快充电速度有些特殊情况你想加快手机的充电速度时&#xff0c;可以试着开启飞…

Anaconda安装库

有时候pip安装库特别慢&#xff0c;就采用conda别的方法装 conda install -c conda-forge 库名#如pydicom,gdcm

Linux 如何安装 SRPM 包(源代码 rpm 软件包,以 .src.rpm 为后缀名)/rpm 格式的源码软件包/源码包

文章目录一、SRPM 介绍二、SRPM 命名格式三、SRPM 的安装&#xff08;一&#xff09;直接使用命令 rpmbuild&#xff08;二&#xff09;利用 *.spec 文件编译&#xff08;三&#xff09;使用命令 make 编译和安装四、写在最后一、SRPM 介绍 SRPM 包&#xff0c;比 RPM 包多了一…

payara 创建 集群_在Payara Server和GlassFish中配置密码

payara 创建 集群回答Stackoverflow问题可以为我发现我最喜欢的开源工具的正式文档中的空白提供很好的反馈。 我在这里回答的问题之一是如何在docker容器中更改Payara Server主密码 。 显然&#xff0c;在标准服务器安装中&#xff0c;这很简单–只需使用asadmin change-master…