文章目录

  • Java反射机制
    • 动态语言
    • 什么是反射
    • 反射的应用场景
      • 编译时类型和运行时类型
      • Java反射API
      • 反射API用来生成JVM中的类、接口或对象的信息。
      • 相关API
      • 反射的使用步骤及方法(获取Class对象,调用对象的方法)
      • 获取某个类的Class对象的3种方法
      • 使用获取到的Class对象获取该类的属性和方法信息
      • 综合实例
      • 实践
      • 总结

Java反射机制

动态语言

动态语言是指程序在运行时可以改变其内部结构:比如新增成员函数,删除已有删除等结构上的一些变化。常见的动态语言有JavaScript和Ruby、Python等。而C、C++等不属于动态语言。从反射角度而言,Java属于半动态的语言。

什么是反射

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YMVIATAk-1636517914730)(https://s3.bmp.ovh/imgs/2021/11/ad0a73868854d498.png)]

反射的应用场景
编译时类型和运行时类型

在Java程序中许多对象在运行时都会出现两种类型:编译时类型和运行时类型。

  1. 编译时类型是由声名对象是所使用的类型。
  2. 运行时类型是指实际运行时由实际赋值给对象的类型决定
Person  p = new Student()
编译时类型:Person
运行时类型:Student

编译时类型是无法获取具体方法的。

程序在运行时还可能接收到外部传入的对象,该对象的编译时类型为Object,但是程序有需要调用该对象的运行时类型的方法。为了解决这些问题,程序需要在运行时发现类和对象的真实性信息。然而编译时根本无法预知该对象和类属于哪些类,程序只能依靠在运行时的信息来发现该类和对象的真实信息。此时则必须使用到反射机制。

使用反射机制可以打破封装性,导致了java对象的属性不安全。

Java反射API

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HKKRkTwG-1636517914732)(https://s3.bmp.ovh/imgs/2021/11/ad58181a1cf4bcb5.jpg)]


反射API用来生成JVM中的类、接口或对象的信息。
  1. Class类:该类是反射的核心类,可以获取类的属性、方法等信息。
  2. Field类:Java.lang.reflect包中的类,表示该类的成员变量,它可以用来获取和设置类之中的属性值
  3. Method类:Java.lang.reflect包中的类,表示该类的成员方法,它可以用来获取类中的方法信息或执行方法。
  4. Construcor类:Java.lang.reflect包中的类,表示该类的构造方法。
相关API
    getName():获得类的完整名字。getFields():获得类的public类型的属性。getDeclaredFields():获得类的所有属性。包括private 声明的和继承类getMethods():获得类的public类型的方法。getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。getConstructors():获得类的public类型的构造方法。getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
反射的使用步骤及方法(获取Class对象,调用对象的方法)
  1. 获取想要操作类的Class的对象,这是反射类的核心,通过该类可以调用任意类的方法。
  2. 调用Class类的方法,就是反射的使用阶段。
  3. 使用反射API来获取这些信息。
获取某个类的Class对象的3种方法
  • 调用某个类的getClass()方法。

    Person p = new Person()
    Class clazz = p.getClass()
    
  • 调用某个类的class属性来获取该类对应的Class对象。

    Class clazz = Person.class//该属性是该类的静态属性
    
  • 使用Class类中的forName()静态方法获取(最安全/性能最好)

    Class clazz = Class.forName('类路径');//最常用
    //但可能抛出 ClassNotFoundException 异常
    
    • 第一种方法是通过类的全路径字符串获取 Class 对象,这也是我们平时最常用的反射获取 Class 对象的方法;
    • 第二种方法有限制条件:需要导入类的包
    • 第三种方法已经有了 Student 对象,不再需要反射。
  • 通过这三种方式获取到的 Class 对象是同一个,也就是说 Java 运行时,每一个类只会生成一个 Class 对象

使用获取到的Class对象获取该类的属性和方法信息
//1.使用最常用的获取某类的Class类对象的方法
Class clazz = Class.forName('reflection.Persson');
//2.使用Class对象获取Person类的所有方法信息
Method[] methods = clazz.getDeclareMethods();
for(Method m:method){System.out.println(m.toString());
}
//3.获取Person类的所有成员属性信息(包括私有属性)
Field[] field = clazz.getDeclareFields();
for(Field f:fiedl){System.out.println(f.toString());
}
//4.获取 Person 类的所有构造方法信息
Constructor[]constructor=clazz.getDeclaredConstructors();
for(Constructor c:constructor){System.out.println(c.toString());
}
综合实例
//获得类完整的名字
String className = c2.getName();
System.out.println(className);//输出com.ys.reflex.Person//获得类的public类型的属性。
Field[] fields = c2.getFields();
for(Field field : fields){System.out.println(field.getName());//age
}//获得类的所有属性。包括私有的
Field [] allFields = c2.getDeclaredFields();
for(Field field : allFields){System.out.println(field.getName());//name    age
}//获得类的public类型的方法。这里包括 Object 类的一些方法
Method [] methods = c2.getMethods();
for(Method method : methods){System.out.println(method.getName());//work waid equls toString hashCode等
}//获得类的所有方法。
Method [] allMethods = c2.getDeclaredMethods();
for(Method method : allMethods){System.out.println(method.getName());//work say
}//获得指定的属性
Field f1 = c2.getField("age");
System.out.println(f1);
//获得指定的私有属性
Field f2 = c2.getDeclaredField("name");
//启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消
f2.setAccessible(true);
System.out.println(f2);//创建这个类的一个对象
Object p2 =  c2.newInstance();
//将 p2 对象的  f2 属性赋值为 Bob,f2 属性即为 私有属性 name
f2.set(p2,"Bob");
//使用反射机制可以打破封装性,导致了java对象的属性不安全。
System.out.println(f2.get(p2)); //Bob//获取构造方法
Constructor [] constructors = c2.getConstructors();
for(Constructor constructor : constructors){System.out.println(constructor.toString());//public com.ys.reflex.Person()
}
实践
package com.test.reflection;public class Student {private String studentName;public int studentAge;public Student() {}private Student(String studentName) {this.studentName = studentName;}public void setStudentAge(int studentAge) {this.studentAge = studentAge;}private String show(String message) {System.out.println("show: " + studentName + "," + studentAge + "," + message);return "testReturnValue";}
}
// 1.通过字符串获取Class对象,这个字符串必须带上完整路径名
Class studentClass = Class.forName("com.test.reflection.Student");
// 2.获取声明的构造方法,传入所需参数的类名,如果有多个参数,用','连接即可
Constructor studentConstructor = studentClass.getDeclaredConstructor(String.class);
// 如果是私有的构造方法,需要调用下面这一行代码使其可使用,公有的构造方法则不需要下面这一行代码
studentConstructor.setAccessible(true);
// 使用构造方法的newInstance方法创建对象,传入构造方法所需参数,如果有多个参数,用','连接即可
Object student = studentConstructor.newInstance("NameA");
// 3.获取声明的字段,传入字段名
Field studentAgeField = studentClass.getDeclaredField("studentAge");
// 如果是私有的字段,需要调用下面这一行代码使其可使用,公有的字段则不需要下面这一行代码
// studentAgeField.setAccessible(true);
// 使用字段的set方法设置字段值,传入此对象以及参数值
studentAgeField.set(student,10);
// 4.获取声明的函数,传入所需参数的类名,如果有多个参数,用','连接即可
Method studentShowMethod = studentClass.getDeclaredMethod("show",String.class);
// 如果是私有的函数,需要调用下面这一行代码使其可使用,公有的函数则不需要下面这一行代码
studentShowMethod.setAccessible(true);
// 使用函数的invoke方法调用此函数,传入此对象以及函数所需参数,如果有多个参数,用','连接即可。函数会返回一个Object对象,使用强制类型转换转成实际类型即可
Object result = studentShowMethod.invoke(student,"message");
System.out.println("result: " + result);
总结

灵活使用反射能让我们代码更加灵活,这里比如JDBC原生代码注册驱动,hibernate 的实体类,Spring 的 AOP等等都有反射的实现。但是凡事都有两面性,反射也会消耗系统的性能,增加复杂性等,合理使用才是真!

一文带你快速全面掌握Java反射机制面试题相关推荐

  1. 一文带你深入理解【Java基础】· 枚举类

    写在前面 Hello大家好, 我是[麟-小白],一位软件工程专业的学生,喜好计算机知识.希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正!谢谢大家!!! ...

  2. 一文带你深入理解【Java基础】· Java基本语法:程序流程控制

    写在前面 Hello大家好, 我是[麟-小白],一位软件工程专业的学生,喜好计算机知识.希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正!谢谢大家!!! ...

  3. 一文带你深入理解【Java基础】· 面向对象编程(下)②代码块、final和abstract

    写在前面 Hello大家好, 我是[麟-小白],一位软件工程专业的学生,喜好计算机知识.希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正!谢谢大家!!! ...

  4. 一文带你深入理解【Java基础】· 数组

    写在前面 Hello大家好, 我是[麟-小白],一位软件工程专业的学生,喜好计算机知识.希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正!谢谢大家!!! ...

  5. 一文带你了解Java反射机制

    想要获取更多文章可以访问我的博客 - 代码无止境. 上周上班的时候解决一个需求,需要将一批数据导出到Excel.本来公司的中间件组已经封装好了使用POI生成Excel的工具方法,但是无奈产品的需求里面 ...

  6. 一文读懂 Java 反射机制那些事

    作者:四夕又欠 用时:12 min 前不久学习了反射机制,来总结下.在此之前,回顾下java程序的编译运行过程,分为三个阶段:源码(.java文件)进过编译生成字节码文件(.class文件),然后jv ...

  7. java反射机制调用带参数的方法_Java反射机制:跟着代码学反射

    1. 前言 在OOP的世界里,万物皆对象.也就是说,我们可以将任何东西抽象成一个对象. 比如人,可以抽象成一个Person类,通过new Person()来实例化一个对象:再比如鸭子,可以抽象成一个D ...

  8. Java基础与提高干货系列——Java反射机制

    前言 今天介绍下Java的反射机制,以前我们获取一个类的实例都是使用new一个实例出来.那样太low了,今天跟我一起来学习学习一种更加高大上的方式来实现. 正文 Java反射机制定义 Java反射机制 ...

  9. Java 反射机制深入研究

    转载自  Java 反射机制深入研究 Java反射机制深入研究 Java 反射是Java语言的一个很重要的特征,它使得Java具体了"动态性". 在Java运行时环境中,对于任意一 ...

  10. Java反射机制深入研究

    ava 反射是Java语言的一个很重要的特征,它使得Java具体了"动态性". 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它 ...

最新文章

  1. 一个简单的程序来使用WiredTiger 存储引擎
  2. 【组队学习】【23期】Datawhale编程实践(区块链)
  3. Hadoop之Storm命令
  4. ORA-28000: the account is locked 的解决办法!
  5. markdown如何设置图片大小_Markdown编辑知乎文章的完全攻略
  6. EBS中Java并发程序笔记(1)
  7. LNMP实现服务器轮询负载均衡
  8. Android程序开发0基础教程(一)
  9. Unity2017.3来了!洪流学堂第一时间送上更新日志简报
  10. Android:Activity(三):启动其他Activity并返回结果
  11. 这个沙盒游戏建立在数字时代,你能通关吗?
  12. 【转】编辑器与IDE
  13. 查看JDK进程信息的几个命令
  14. 微型计算机的主体,以微型计算机为主体,配上系统软件和外设就组成了微型计算机系统...
  15. Zencart模板结构和设计详解
  16. VMware vCenter Server 7.0U3
  17. 高德地图的标志放大_高德地图点标注的分布与缩放
  18. 微信小程序没有找到可以构建的NPM包,请确认需要参与构建的npm在miniprogramroot目录
  19. TensorFlow 2官方教程 . Keras机器学习基础知识 . 使用TF Hub进行文本分类
  20. 【mongodb】比较符及修改器

热门文章

  1. Cesium最全源码集合
  2. 屏幕画线软件ZOOMIT
  3. 微博表情插入mysql数据库,表情都是四字节字符
  4. win10安装马上6的问题
  5. 新版vip在线解析html源码
  6. 一文让你彻底了解iOS字体相关知识
  7. JavaScript 高级程序设计笔记
  8. 微软应用商店有哪些值得推荐的应用
  9. linux装sql2008数据库,Ubuntu 16.04下安装SQL Server for Linux
  10. OCR识别扫描版PDF文件(Python版)