Java 基础知识-反射

大家好我是苏麟 , 今天聊聊反射 .

反射

专业的解释:

 反射允许对封装类的字段,方法和构造函数的信息进行编程访问

 是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法

​ 对于任意一个对象,都能够调用它的任意属性和方法

​ 这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制

通俗的理解:

  • 利用反射创建的对象可以无视修饰符调用类里面的内容

  • 可以跟配置文件结合起来使用,把要创建的对象信息和方法写在配置文件中。

    读取到什么类,就创建什么类的对象

    读取到什么方法,就调用什么方法

    此时当需求变更的时候不需要修改代码,只要修改配置文件即可。

反射涉及到四个核心类:

  • java.lang.Class.java:类对象;
  • java.lang.reflect.Constructor.java:类的构造器对象;
  • java.lang.reflect.Method.java:类的方法对象;
  • java.lang.reflect.Field.java:类的属性对象;

学什么?

反射都是从class字节码文件中获取的内容。

  • 如何获取class字节码文件的对象
  • 利用反射如何获取构造方法(创建对象)
  • 利用反射如何获取成员变量(赋值,获取值)
  • 利用反射如何获取成员方法(运行)

获取字节码文件对象的三种方式

        //1.Class这个类里面的静态方法forName//Class.forName("类的全类名"): 全类名 = 包名 + 类名Class user = Class.forName("org.example.User");//源代码阶段获取 --- 先把User加载到内存中,再获取字节码文件的对象//clazz 就表示User这个类的字节码文件对象。//就是当User.class这个文件加载到内存之后,产生的字节码文件对象
        //2.通过class属性获取//类名.classClass userClass = User.class;//因为class文件在硬盘中是唯一的,所以,当这个文件加载到内存之后产生的对象也是唯一的System.out.println(user == userClass);//true
        //3.通过Student对象获取字节码文件对象User u = new User();Class us = u.getClass();System.out.println(user == userClass);//trueSystem.out.println(userClass == us);//true

哪些类型可以获取class

public static void main(String[] args) {String s = new String("1");//继承Class aClass = s.getClass();//.classClass stringClass = String.class;Class<Integer> integerClass = int.class;Class<int[]> aClass1 = int[].class;Class<Void> voidClass = void.class;Class<Runnable> runnableClass = Runnable.class;
}

 字节码文件和字节码文件对象

java文件:就是我们自己编写的java代码。

字节码文件:就是通过java文件编译之后的class文件(是在硬盘上真实存在的,用眼睛能看到的)

字节码文件对象:当class文件加载到内存之后,虚拟机自动创建出来的对象。

​ 这个对象里面至少包含了:构造方法,成员变量,成员方法。

而我们的反射获取的是什么?字节码文件对象,这个对象在内存中是唯一的。

创建对象

一般情况下我们通过反射创建类对象主要有两种方式:

  • 通过 Class 对象的 newInstance() 方法
  • 通过 Constructor 对象的 newInstance() 方法
// 通过 Class 对象的 newInstance() 方法。       
Class user = Class.forName("org.example.User");
User newUser = (User) user.newInstance();
//通过 Constructor 对象的 newInstance() 方法
Class user = Class.forName("org.example.User");
User newUser = (User) user.getConstructor().newInstance();

通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法

API 可以看到 Class 有很多方法:

  • getName():获得类的完整名字。
  • getFields():获得类的public类型的属性。
  • getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
  • getMethods():获得类的public类型的方法。
  • getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
  • getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
  • getDeclaredConstructors():返回类中所有的构造方法。
  • getConstructors():获得类的public类型的构造方法。
  • getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
  • newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
  • getModifiers():获取属性的修饰符列表,返回的修饰符是一个数字,每个数字是修饰符的代号【一般配合Modifier类的toString(int x)方法使用】
  • getSuperclass():返回调用类的父类。
  • getInterfaces():返回调用类实现的接口集合。

入门案例

反编译一个类

package org.example;/*** @className: User* @author: SL 苏麟**/
public class User {private String name;public User() {}public User(String name) {this.name = name;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}public String toString() {return "User{name = " + name + "}";}
}
 @Testpublic void testUser() throws Exception {StringBuffer stringBuffer = new StringBuffer();Class<?> userClass = Class.forName("org.example.User");stringBuffer.append(Modifier.toString(userClass.getModifiers()) + " class " + userClass.getSimpleName() + "{");Constructor<?>[] constructors = userClass.getDeclaredConstructors();for (Constructor<?> constructor : constructors) {stringBuffer.append("\n\t" + Modifier.toString(constructor.getModifiers()) + " " + "(");Class<?>[] parameterTypes = constructor.getParameterTypes();int flag = 0;for (Class<?> parameterType : parameterTypes) {StringBuffer buffer = flag == 0 ? stringBuffer.append(parameterType.getSimpleName()) : stringBuffer.append(" ," + parameterType.getSimpleName());flag++;}stringBuffer.append(")" + "\n");}Field[] fields = userClass.getDeclaredFields();for (Field field : fields) {stringBuffer.append("\n\t" + Modifier.toString(field.getModifiers()) + " " + field.getType().getSimpleName() + " " + field.getName() + ";\n");}Method[] methods = userClass.getDeclaredMethods();for (Method method : methods) {stringBuffer.append("\n\t" + Modifier.toString(method.getModifiers()) + " " + method.getReturnType().getSimpleName() + " " + method.getName() + "{}\n");}stringBuffer.append("}");System.out.println(stringBuffer);}

打破封装

Field类的方法

public void setAccessible(boolean flag) 默认false,设置为true为打破封装

    @Testpublic void testUserPrivate() throws Exception {Class user = Class.forName("org.example.User");Field nameField = user.getDeclaredField("name");//破坏封装nameField.setAccessible(true);User newUser = (User) user.getConstructor().newInstance();nameField.set(newUser, "sl");System.out.println(newUser);}

这期就到这里 , 下期见!

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

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

相关文章

数据库作业三

1.创建student和score表 2.为student表和score表增加记录 3.查询student表的所有记录 4.查询student表的第2条到4条记录 5.从student表查询所有学生的学号&#xff08;id&#xff09;、姓名&#xff08;name&#xff09;和院系&#xff08;department&#xff09;的信息 6.从st…

Unity中四元数常用的方法

单位四元数 #region 单位四元数print(Quaternion.identity);testObj.rotation Quaternion.identity;//初始化对象时可能会用来赋值Instantiate(testObj,Vector3.zero,Quaternion.identity);#endregion 插值运算 #region 插值运算 //四元数中也提供了如同Vector3的插值运算 /…

命令行参数环境变量和进程空间地址

文章目录 命令行参数环境变量进程地址空间 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站。 命令行参数 什么是命令行参数&#xff1f; 我…

架设一台NFS服务器,并按照以下要求配置

1、开放/nfs/shared目录&#xff0c;供所有用户查询资料 2、开放/nfs/upload目录&#xff0c;为192.168.xxx.0/24网段主机可以上传目录&#xff0c; 并将所有用户及所属的组映射为nfs-upload,其UID和GID均为210 3、将/home/tom目录仅共享给192.168.xxx.xxx这台主机&#xff0c;…

【性能调优】local模式下flink处理离线任务能力分析

文章目录 一. flink的内存管理1.Jobmanager的内存模型2.TaskManager的内存模型2.1. 模型说明2.2. 通讯、数据传输方面2.3. 框架、任务堆外内存2.4. 托管内存 3.任务分析 二. 单个节点的带宽瓶颈1. 带宽相关理论2. 使用speedtest-cli 测试带宽3. 任务分析3. 其他工具使用介绍 本…

逆商(AQ)测试(国际标准版)

人这一生的成就离不开逆商指数(也叫挫折商)&#xff0c;IQ智商,EQ情商和AQ逆商&#xff0c;组成了3Q&#xff0c;在我们努力拼搏的过程中&#xff0c;在我们追求成就的同时&#xff0c;AQ逆商一直在伴随这我们。AQ逆商是我们身处逆境中的应对能力&#xff0c;反应出我们对挫折的…

服务器运维小技巧(一)——如何进行远程协助

服务器运维中经常会遇到一些疑难问题&#xff0c;需要安全工程师&#xff0c;或者其他大神远程协助。很多人会选择使用todesk或者向日葵等一些远控软件。但使用这些软件会存在诸多问题&#xff1a; 双方都需要安装软件&#xff0c;太麻烦需要把服务器的公钥/密码交给对方不知道…

redis数据安全(四)复制

关系数据库通常会使用一个主服务器向多个从服务器发送更新&#xff0c;并使用从服务器来处理所有读请求&#xff0c;Redis也采用了同样的方法来实现自己的复制特性&#xff0c;并将其用做扩展性能的一种手段。 一、特点&#xff1a; 1、异步复制&#xff1a;Redis默认使用的是…

【Vue中使用Echarts】大屏可视化项目整体布局(pink老师vue 版)

文章目录 一、效果展示二、基本的布局三、背景四、代码布局中遇到的一些问题 一、效果展示 先看一下展示的效果&#xff0c;无论是尺寸多宽的屏幕&#xff0c;都会将内容显示完整&#xff0c;做到了正正的响应式。唯一不足的是图表中的样例&#xff0c;会随着图表的缩放而变换…

完美解决idea一直indexing,无法操作的问题

今天主要分享一下在使用idea 2020.3版本开发maven项目的时候&#xff0c;一直出现有效件index&#xff0c; 有时候是scaning indexing, 有时候是update indexing, indexing的时候&#xff0c;idea基本上就没办法操作了&#xff0c;连跳入到类或方法里都跳不了。不厌其烦。 于是…

Linux/Traceback

Enumeration nmap 使用nmap初步扫描发现只开放了22和80端口&#xff0c;端口详细扫描情况如下 先看看web是什么样子的&#xff0c;打开网站发现有一条留言&#xff0c;显示该站点已经被黑了&#xff0c; 并且留下了后门 查看源代码&#xff0c;可以看到下面的注释 <!--So…

这种网页要小心!注意你的账号密码泄露!

目录 H5是泄露账号和数据的重要渠道 代码混淆是最佳的安全保护手段 基于AI的自适应代码混淆 我们经常见到各类H5海报&#xff0c;产品展示、活动促销、招聘启事等。H5不仅能够无缝地嵌入App、小程序&#xff0c;还可以作为一个拥有独立链接地址的页面&#xff0c;直接在PC端打开…