如果你被问到:什么是反射?为什么需要反射、以及反射的应用?你会如何回答呢?

本篇会带大家初识反射,了解反射概念和基本应用。反射的原理以及深入源码的探究将会在后面几篇介绍。

一、什么是反射?

要理解什么是反射,我们先看看什么是「正射」,一个常见的获取Student的正射如下:

  1. Student student = new Student();

通常 我们都是直接声明,或者通过 new Student() 直接获取一个 Student 类,然后再使用。而一个反射的例子如下:

  1. // 这里的“com.demo.Student”是需要反射的类的全限定名(包名+类名)
  2. Class clz = Class.forName("com.demo.Student")
  3. Object stu = clz.newInstance();

先获取实例的Class类,然后再通过其Class类生成一个Student的Instance。以上两种方式(new Student和clz.newInstance)是效果是等价的,都是获取到了一个Student 的实例。

那么什么是反射呢?反射是Java中的一个重要的特性,使用反射可以在运行时动态生成对象、获取对象属性以及调用对象方法。

Oracle 官方对反射的解释是:

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.

The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

反射的问题:

这里先简单提一下:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 Java 代码要慢很多。

二、为什么需要反射?

举一个直观的例子(仅为了说明其中一种用法):

如果我让你写一个根据运行时输入的名字进行打印输出,你会写出类似下面的代码:

  1. public void sayHello(String name) {
  2. // 在运行前根本不知道 name 是什么,只有在运行时 name 才会被确认并打印出来
  3. System.out.println("hello, " + name);
  4. }

那么同样的,在写代码时可能也不知道要用什么类,运行时才知道。比如加载数据库驱动的时候,你可以直接 new 出来具体的驱动类,但要是换了数据库呢,还要修改源码重新打包更新么?

  1. new com.mysql.jdbc.Driver();

那你可能会说,我多写几个 if else 不就行了,类似下面这样:

  1. if ( xxx == "mysql") {
  2. new com.mysql.jdbc.Driver();
  3. else if ( xxx == "redis" ) {
  4. new com.redis.jdbc.Driver();
  5. else if ( ... ){
  6. }

这样的问题是,在编译期就要凑齐所有的 jdbc 连接库,甭管用不用这些都会被加载到内存中,数据库类型多了会有极大的浪费。

那么这种情况,就可以用反射来解决,在运行时才去动态的加载对应类。你也可以在配置文件中指明要使用哪种数据库类,连接不同的数据库都可以使用这一份程序。

  1. // 反射的方式动态加载类
  2. Class.forName("com.mysql.jdbc.Driver");

三、反射的基本使用

下面介绍通过反射都能做什么:

一)获得 Class 对象

  1. // 1 使用 Class 类的 forName 静态方法
  2. Class.forName(driver);
  3. // 2 直接获取某一个对象的 class
  4. Class<?> cl = int.class;
  5. // 3 调用某个对象的 getClass() 方法
  6. StringBuilder str = new StringBuilder("123");
  7. Class<?> klass = str.getClass();

二)判断是否为某个类的实例

  1. public static void displayObjectClass(Object o) {
  2. if (o instanceof Vector)
  3. System.out.println("对象是 java.util.Vector 类的实例");
  4. else if (o instanceof ArrayList)
  5. System.out.println("对象是 java.util.ArrayList 类的实例");
  6. else
  7. System.out.println("对象是 " + o.getClass() + " 类的实例");
  8. }

三)创建实例

  1. Class<?> c = String.class;
  2. Object str = c.newInstance();

四)获取方法

getDeclaredMethods() 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

getMethods() 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。

getMethod() 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。

  1. public class ReflectDemo {
  2. public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
  3. Class<?> c = MyClass.class;
  4. Method[] methods = c.getMethods();
  5. Method[] declaredMethods = c.getDeclaredMethods();
  6. Method method = c.getMethod("add", int.class, int.class);
  7. System.out.println("getMethods获取的方法:");
  8. for(Method m:methods)
  9. System.out.println(m);
  10. System.out.println("getDeclaredMethods获取的方法:");
  11. for(Method m:declaredMethods)
  12. System.out.println(m);
  13. }
  14. }
  15. class MyClass {
  16. public int add(int a, int b) {
  17. return a + b;
  18. }
  19. public int sub(int a, int b) {
  20. return a - b;
  21. }
  22. }
  23. // 输出
  24. /*
  25. getMethods获取的方法:
  26. public int com.shuofxz.basic.ReflectDemo$MyClass.add(int,int)
  27. public int com.shuofxz.basic.ReflectDemo$MyClass.sub(int,int)
  28. public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
  29. public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
  30. public final void java.lang.Object.wait() throws java.lang.InterruptedException
  31. public boolean java.lang.Object.equals(java.lang.Object)
  32. public java.lang.String java.lang.Object.toString()
  33. public native int java.lang.Object.hashCode()
  34. public final native java.lang.Class java.lang.Object.getClass()
  35. public final native void java.lang.Object.notify()
  36. public final native void java.lang.Object.notifyAll()
  37. getDeclaredMethods获取的方法:
  38. public int com.shuofxz.basic.ReflectDemo$MyClass.add(int,int)
  39. public int com.shuofxz.basic.ReflectDemo$MyClass.sub(int,int)
  40. */

五)调用方法

当我们从类中获取了一个方法后,我们就可以用 invoke() 来调用这个方法。

  1. public class ReflectDemo {
  2. public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
  3. Class<?> mc = MyClass.class;
  4. Object obj = mc.newInstance();
  5. //获取methodClass类的add方法
  6. Method method = mc.getMethod("add", int.class, int.class);
  7. //调用method对应的方法 => add(1,4)
  8. Object result = method.invoke(obj, 1, 4);
  9. System.out.println(result);
  10. }
  11. }

六)获取构造器、类的成员变量(字段)信息

  • 通过 Class 类的 getConstructor 方法得到 Constructor 类的一个实例
  • getFiled:访问公有的成员变量
  • getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量

四、小结

本篇文章初步介绍了反射机制。让大家了解了反射是什么,为什么会有反射这个功能,以及一些基本使用方式。后续文章将会反射的机制和原理做进一步的讲解。

【Java面试指北】反射(1) 初识反射的更多相关文章

  1. Java面试指北!13个认证授权常见面试题/知识点总结!| JavaGuide

    大家好,我是 Guide哥!端午已过,又要开始工作学习啦! 我发现有很多小伙伴对认证授权方面的知识不是特别了解,搞不清 Session 认证.JWT 以及 Cookie 这些概念. 所以,根据我根据日 ...

  2. java面试-反射

    1.什么是反射?有什么优缺点?   反射就是动态加载对象,并对对象进行剖析.在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法.对于任意一个对象,都能够调用它的任意一个方法.这种动态获取信 ...

  3. 慕课网:剑指Java面试-Offer直通车视频课程

    慕课网:剑指Java面试-Offer直通车视频课程,一共有10个章节. 目录结构如下: 目录:/2020036-慕课网:剑指Java面试-Offer直通车 [6G] ┣━━第10章 Java常用类库与 ...

  4. Java高质量代码之 — 泛型与反射

    在Java5后推出了泛型,使我们在编译期间操作集合或类时更加的安全,更方便代码的阅读,而让身为编译性语言的Java提供动态性的反射技术,更是在框架开发中大行其道,从而让Java活起来,下面看一下在使用 ...

  5. Android(java)学习笔记108:通过反射获取私有构造方法并且使用

    反射获取私有构造方法并且使用: 1.获取字节码文件.class对象:          Class c = Class.forName("cn.itcast_01.Person") ...

  6. Java实现在访问者模式中使用反射

    集合类型在面向对象编程中很常用,这也带来一些代码相关的问题.比如,“怎么操作集合中不同类型的对象?” 一种做法就是遍历集合中的每个元素,然后根据它的类型而做具体的操作.这会很复杂,尤其当你不知道集合中 ...

  7. Java 反射机制[Method反射]

    Java 反射机制[Method反射] 接着上一篇Java 反射机制[Field反射],通过调用Person类的setName方法将obj的name字段的Value设置为"callPerso ...

  8. Java开发培训基础知识解析之反射机制

    Java是老牌编程语言,是当前应用最广泛的编程语言之一.想要学习Java你就一定要掌握Java基础知识,而反射对于初学Java的人来说绝对是非常重要的知识点.什么是反射?如何理解反射机制?如何使用反射 ...

  9. python学习之老男孩python全栈第九期_day026知识点总结——封装、property、类方法、初识反射

    一. 封装 class Room: def __init__(self, name, length, width): self.__name = name self.__length = length ...

  10. Java 反射机制[Field反射]

    Java 反射机制[Field反射] 1.  反射概念及功能 反射就是把Java类中的各种成分映射成对应的Java类.比如一个Java类中用一个Class类的对象来表示. 一个类中的组成部分分为成员变 ...

随机推荐

  1. PHP全栈开发(八):CSS Ⅷ border margin padding

    在CSS里面,所有的HTML元素都可以看成是一个盒子. 那么在设计和布局的时候,最常用的,也就是用来定义这个盒子的外边距的就是margin 定义这个盒子的内边距的就是padding 元素的内容所占的宽 ...

  2. zookeeper之安装

    zookeeper之安装 一.准备条件 1.1 最低三个服务器(一主多从,1个leader,多个flower)1.2 将zookeeper安装包上传到集群并解压zookeeper 二.将conf目录下 ...

  3. java中实现File文件的重命名(renameTo)、将文件移动到其他目录下、文件的复制(copy)、目录和文件的组合(更加灵活方便)

    欢迎加入刚建立的社区:http://t.csdn.cn/Q52km 加入社区的好处: 1.专栏更加明确.便于学习 2.覆盖的知识点更多.便于发散学习 3.大家共同学习进步 3.不定时的发现金红包(不多 ...

  4. 微服务系列之分布式日志 ELK

    1.ELK简介 ELK是ElasticSearch+LogStash+Kibana的缩写,是现代微服务架构流行的分布式日志解决方案,旨在大规模服务的日志集中管理查看,极大的为微服务开发人员提供了排查生 ...

  5. 齐博X1-栏目的调用5

    本节继续说明栏目的调用父级.同级.子级三层的栏目调用 父级.同级.子级三层的栏目调用 fun('sort@family',$fid,'cms') 比如下面栏目10利用这个函数,就可以调用出 父级9 同 ...

  6. 齐博x1APP要实现直播的关键两步

    大家务必要注意,缺少这两步,你的APP将不能实现直播, 也即点击直播按钮无法启动直播推流 https://www.maxdo.tech/

  7. Hadoop集群简单入门

    Hadoop集群搭建 自己配置Hadoop的话太过复杂了,因为自己着急学习,就使用了黑马的快照.如果小伙伴们也想的话可以直接看黑马的课程,快照的话关注黑马程序员公众号,输入Hadoop就能获取资料,到 ...

  8. 你给文字描述,AI艺术作画,精美无比!附源码,快来试试!

    作者:韩信子@ShowMeAI 深度学习实战系列:https://www.showmeai.tech/tutorials/42 TensorFlow 实战系列:https://www.showmeai ...

  9. c语言求输入的任一整数的各位数之和

    c语言求解代码: # include<stdio.h> int main(void){ int a,i=0,sum=0; scanf("%d",&a); if( ...

  10. 常用CSS样式属性

    01.常用样式 1.1.background背景 设置元素背景的样式 background,更好的衬托内容. 属性 描述 值 background 背景属性简写.支持多组背景设置,逗号,隔开 back ...