反射获取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密钥。 您必须创建一个示例…

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

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

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

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

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

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

axure怎么做5秒倒计时_五个月宝宝早教,5个月婴儿早教怎么做

五个月宝宝早教,5个月婴儿早教怎么做,5个月宝宝是需要开始有意识的进行精细动作的家庭训练了5个月宝宝的一般特点:到了5个月时,能用眼睛观察周围的物体了,而且对什么都感到新奇好玩,能在眼睛的支配下抓住东…

图像融合亮度一致_重磅干货低光图像处理方案

点击上方“AIWalker”,选择加“星标”或“置顶” 重磅干货,第一时间送达Tips:一点点提示,因内容较多建议先关注,再置顶,最后端杯茶来精心浏览。背景低光图像是夜晚拍照时极为常见的一种现象。不充分的光…

Adobe PhotoShop(PS) for Mac 如何隐藏切片框?

如何取消显示如下图所示的切片框: 打开『视图』➟ 『显示』,把『切片』前面的勾去掉,如下图所示:

邮宝打印面单尺寸调整_如何打印身份证的实际尺寸?怎样用照片打印身份证复印件...

点击上面 蓝色 文字关注我们,了解选购百科知识,快乐健康不停!怎样打印身份证复印件?可以把身份证的照片导入电脑或者扫描件打印黑白的即可。如何打印身份证的实际尺寸?二代身份证的实际尺寸是:85.6MM X 54M…

取模和求余运算

文章目录背景探究总结被除数 dividend 用 a 表示; 除数 divisor 用 b 表示; 商 quotient 用 q 表示; 余 remainder 用 rem 表示; 模 modulo 用 mod 表示。 背景 最近在一道 Java 习题中,看到这样的一道题:…

图像重建算法_基于深度学习图像重建算法(DLIR)对CT图像质量和剂量优化的研究:体模实验...

编者按:今年Jol Greffier博士等在European Radiology (IF 4.1)上发表了题为《Image quality and dose reduction opportunity of deep learning image reconstruction algorithm for CT: a phantom study》的文章,通过与混合迭代重建算法(IR)对比&#x…

oracle中sp怎么写_校招简历中的实习和项目经历该怎么写?

在2017年和2018年,我针对校招生的简历分别写了两篇文章,一篇是《秋招中的互联网产品、运营岗,该如何准备?》,里面有一部分内容是关于简历的准备;另一篇是《如何用产品思维解决简历问题?七步简历…

自然语言处理领域基本概念笔记

自然语言处理 词向量: 自然语言处理问题要转化为机器学习的问题,首先就要把单词数学化表示,就是用n维实数向量来代表一个单词。 对话系统 对话系统发展历程的三个阶段: 1.基于符号规则和模板的对话系统 2.基于统计机器学习的…

如何理解 inode

一、inode是什么? 理解inode,要从文件储存说起。 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector)。每个扇区储存512字节(相当于0.5KB)。 操作系统读取硬盘的时候&#xff0c…

java api 开发_Java开发人员应该知道的前20个库和API

java api 开发优秀且经验丰富的Java开发人员的特征之一是对API的广泛了解,包括JDK和第三方库。 我花了很多时间来学习API,尤其是在阅读了Effective Java 3rd Edition之后 ,Joshua Bloch建议在Java 3rd Edition中使用现有的API进行开发&#x…

Linux 系统的硬链接和软链接详解

文章目录什么是链接链接用来干什么的硬链接和软链接的区别硬链接和软链接的图示总结我们知道文件都有文件名与数据,这在 Linux 上被分成两个部分:用户数据 (user data) 与元数据 (metadata)。用户数据,即文件数据块 (data block),…

okta-spring_通过Okta的单点登录保护Spring Boot Web App的安全

okta-spring“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。 您可以使用SpringBoot和Okta在不到20分钟的时间内启动具有完整用户身份和…

apache poi_将HTML转换为Apache POI的RichTextString

apache poi1.概述 在本教程中,我们将构建一个将HTML作为输入的应用程序,并使用提供HTML的RichText表示形式创建Microsoft Excel工作簿。 为了生成Microsoft Excel工作簿,我们将使用Apache POI 。 为了分析HTML,我们将使用Jericho。…

Windows 下有哪些逆天的软件?

文章目录逆天软件系列1:Everything逆天软件系列2:Total Commander逆天软件系列3:Snipaste逆天软件系列4:Microsoft To-Do逆天软件系列5:ScreenToGIF逆天软件系列6:Geek Uninstaller逆天软件系列7&#xff1…

oracle adf_Fn函数来构建Oracle ADF应用程序

oracle adf在我之前的一篇文章中,我描述了如何创建一个Docker容器作为ADF应用程序的构建器。 在这里,我将展示如何将此容器用作 在FN平台的功能 。 首先,让我们更新容器,使其符合功能要求,这意味着可以将其作为接受某…

Sublime Text 4.0 4102 安装插件的问题

文章目录安装包控件(Package Control)如何安装插件打开 Install Package 面板搜索和安装插件无法打开 Install Package 面板的问题故障排除安装包控件(Package Control) 要安装插件,必须先安装 Package Control&#…