点击上方蓝色“程序猿DD”,选择“设为星标”

回复“资源”获取独家整理的学习资料!

作者 | 火星十一郎

来源 | https://www.cnblogs.com/hxsyl

一.概念

反射就是把Java的各种成分映射成相应的Java类。

Class类的构造方法是private,由JVM创建。

反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。(来自Sun)

JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。

反射是从1.2就有的,后面的三大框架都会用到反射机制,涉及到类"Class",无法直接new CLass(),其对象是内存里的一份字节码.  

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

基本的 Java类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。Class 没有公共构造方法。

Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

Person p1 = new Person();
//下面的这三种方式都可以得到字节码
CLass c1 = Date.class();
p1.getClass();
//若存在则加载,否则新建,往往使用第三种,类的名字在写源程序时不需要知道,到运行时再传递过来
Class.forName("java.lang.String");

Class.forName()字节码已经加载到java虚拟机中,去得到字节码;java虚拟机中还没有生成字节码 用类加载器进行加载,加载的字节码缓冲到虚拟机中。 

考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。

import java.lang.reflect.*;    public class DumpMethods {    public static void main(String args[]) {    try {    Class c = Class.forName("java.util.Stack");    Method m[] = c.getDeclaredMethods();    for (int i = 0; i < m.length; i++)    System.out.println(m[i].toString());    }    catch (Throwable e){    System.err.println(e);    }    }
}  public synchronized java.lang.Object java.util.Stack.pop()
public java.lang.Object java.util.Stack.push(java.lang.Object)
public boolean java.util.Stack.empty()
public synchronized java.lang.Object java.util.Stack.peek()
public synchronized int java.util.Stack.search(java.lang.Object)

这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。

以下示例使用 Class 对象来显示对象的类名:

void printClassName(Object obj) {  System.out.println("The class of " + obj +  " is " + obj.getClass().getName());
}

还可以使用一个类字面值(JLS Section 15.8.2)来获取指定类型(或 void)的 Class 对象。例如:

System.out.println("The name of class Foo is: "+Foo.class.getName());

在没有对象实例的时候,主要有两种办法。

//获得类类型的两种方式
Class cls1 = Role.class;
Class cls2 = Class.forName("yui.Role");

注意第二种方式中,forName中的参数一定是完整的类名(包名+类名),并且这个方法需要捕获异常。现在得到cls1就可以创建一个Role类的实例了,利用Class的newInstance方法相当于调用类的默认的构造器。

Object o = cls1.newInstance();
//创建一个实例
//Object o1 = new Role();   //与上面的方法等价

二.常用方法  

1.isPrimitive(判断是否是基本类型的字节码)

public class TestReflect {  public static void main(String[] args) {  // TODO Auto-generated method stub  String str = "abc";  Class cls1 = str.getClass();  Class cls2 = String.class;  Class cls3 = null;//必须要加上null  try {  cls3 = Class.forName("java.lang.String");  } catch (ClassNotFoundException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  System.out.println(cls1==cls2);  System.out.println(cls1==cls3);  System.out.println(cls1.isPrimitive());  System.out.println(int.class.isPrimitive());//判定指定的 Class 对象是否表示一个基本类型。  System.out.println(int.class == Integer.class);  System.out.println(int.class == Integer.TYPE);  System.out.println(int[].class.isPrimitive());  System.out.println(int[].class.isArray());  }
}

结果:

true
true
false
true
false
true
false
true

2.getConstructor和getConstructors()

java中构造方法没有先后顺序,通过类型和参数个数区分。 

public class TestReflect {  public static void main(String[] args) throws SecurityException, NoSuchMethodException {  // TODO Auto-generated method stub  String str = "abc";  System.out.println(String.class.getConstructor(StringBuffer.class));  }
}

3.Filed类代表某一类中的一个成员变量。

import java.lang.reflect.Field;
public class TestReflect {  public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {  ReflectPointer rp1 = new ReflectPointer(3,4);  Field fieldx = rp1.getClass().getField("x");//必须是x或者y  System.out.println(fieldx.get(rp1));  /*  * private的成员变量必须使用getDeclaredField,并setAccessible(true),否则看得到拿不到  */  Field fieldy = rp1.getClass().getDeclaredField("y");  fieldy.setAccessible(true);//暴力反射  System.out.println(fieldy.get(rp1));  }
}  class ReflectPointer {  public int x = 0;  private int y = 0;  public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source  super();  // TODO Auto-generated constructor stub  this.x = x;  this.y = y;  }
}

三.典型例题

1.将所有String类型的成员变量里的b改成a。

import java.lang.reflect.Field;
public class TestReflect {  public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {  ReflectPointer rp1 = new ReflectPointer(3,4);  changeBtoA(rp1);  System.out.println(rp1);  }  private static void changeBtoA(Object obj) throws RuntimeException, Exception {  Field[] fields = obj.getClass().getFields();  for(Field field : fields) {  //if(field.getType().equals(String.class))  //由于字节码只有一份,用equals语义不准确  if(field.getType()==String.class) {  String oldValue = (String)field.get(obj);  String newValue = oldValue.replace('b', 'a');  field.set(obj,newValue);  }  }  }
}  class ReflectPointer {  private int x = 0;  public int y = 0;  public String str1 = "ball";  public String str2 = "basketball";  public String str3 = "itcat";  public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source  super();  // TODO Auto-generated constructor stub  this.x = x;  this.y = y;  }  @Override  public String toString() {  return "ReflectPointer [str1=" + str1 + ", str2=" + str2 + ", str3="  + str3 + "]";  }
}

2.写一个程序根据用户提供的类名,调用该类的里的main方法。

为什么要用反射的方式呢?

import java.lang.reflect.Field;
import java.lang.reflect.Method;  public class TestReflect {  public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {  String str = args[0];  /*  * 这样会数组角标越界,因为压根没有这个字符数组  * 需要右键在run as-configurations-arguments里输入b.Inter(完整类名)  *   */  Method m = Class.forName(str).getMethod("main",String[].class);  //下面这两种方式都可以,main方法需要一个参数  m.invoke(null, new Object[]{new String[]{"111","222","333"}});  m.invoke(null, (Object)new String[]{"111","222","333"});//这个可以说明,数组也是Object  /*  * m.invoke(null, new String[]{"111","222","333"})  * 上面的不可以,因为java会自动拆包  */  }
}  class Inter {  public static void main(String[] args) {  for(Object obj : args) {  System.out.println(obj);  }  }
}

3.模拟 instanceof 操作符

class S {
}     public class IsInstance {    public static void main(String args[]) {    try {    Class cls = Class.forName("S");    boolean b1 = cls.isInstance(new Integer(37));    System.out.println(b1);    boolean b2 = cls.isInstance(new S());    System.out.println(b2);    }    catch (Throwable e) {    System.err.println(e);    }    }
}

在这个例子中创建了一个S 类的 Class 对象,然后检查一些对象是否是S的实例。Integer(37) 不是,但 new S()是。

推荐阅读:instanceof、isInstance、isAssignableFrom

四.Method类

代表类(不是对象)中的某一方法。

import java.lang.reflect.Field;
import java.lang.reflect.Method;
/*  * 人在黑板上画圆,涉及三个对象,画圆需要圆心和半径,但是是私有的,画圆的方法  * 分配给人不合适。  *   * 司机踩刹车,司机只是给列车发出指令,刹车的动作还需要列车去完成。  *   * 面试经常考面向对象的设计,比如人关门,人只是去推门。  *   * 这就是专家模式:谁拥有数据,谁就是专家,方法就分配给谁  */
public class TestReflect {  public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {  String str = "shfsfs";  //包开头是com表示是sun内部用的,java打头的才是用户的  Method mtCharAt = String.class.getMethod("charAt", int.class);  Object ch = mtCharAt.invoke(str,1);//若第一个参数是null,则肯定是静态方法  System.out.println(ch);  System.out.println(mtCharAt.invoke(str, new Object[]{2}));//1.4语法  }  }

五.数组的反射

Array工具类用于完成数组的反射操作。

同类型同纬度有相同的字节码。

int.class和Integer.class不是同一份字节码,Integer.TYPE,TYPE代表包装类对应的基本类的字节码 int.class==Integer.TYPE。

import java.util.Arrays;  /*  * 从这个例子看出即便字节码相同但是对象也不一定相同,根本不是一回事  *   */
public class TestReflect {  public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {  int[] a = new int[3];  int[] b = new int[]{4,5,5};//直接赋值后不可以指定长度,否则CE  int[][] c = new int[3][2];  String[] d = new String[]{"jjj","kkkk"};  System.out.println(a==b);//false  System.out.println(a.getClass()==b.getClass());//true  //System.out.println(a.getClass()==d.getClass());    //比较字节码a和cd也没法比  System.out.println(a.getClass());//输出class [I  System.out.println(a.getClass().getName());//输出[I,中括号表示数组,I表示整数  System.out.println(a.getClass().getSuperclass());//输出class java.lang.Object  System.out.println(d.getClass().getSuperclass());//输出class java.lang.Object  //由于父类都是Object,下面都是可以的  Object obj1 = a;//不可是Object[]  Object obj2 = b;  Object[] obj3 = c;//基本类型的一位数组只可以当做Object,非得还可以当做Object[]  Object obj4 = d;  //注意asList处理int[]和String[]的区别  System.out.println(Arrays.asList(b));//1.4没有可变参数,使用的是数组,[[I@1bc4459]  System.out.println(Arrays.asList(d));//[jjj, kkkk]  }
}

六.结束语

以上就是反射机制的简单的使用,显然学过spring的朋友一定明白了,为什么可以通过配置文件就可以让我们获得指定的方法和变量,在我们创建对象的时候都是通过传进string实现的,就好像你需要什么,我们去为你生产,还有我们一直在用Object,这就说明java语言的动态特性,依赖性大大的降低了。

本文版权归作者火星十一郎所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

往期推荐

四种常见的系统架构,目前你处于哪个阶段呢?

Spring Boot“内存泄漏”?看看美团大牛是如何排查的

提升系统 10 倍性能的 10 个建议!

Redis 创始人宣布退居二线:我写代码只是为了表达自己!

10 个牛逼的单行代码编程技巧,你会用吗?

「程序猿 DD」星球活动第一期,将在 7 月 9 日晚 20:00 整开放,持续一周

「程序猿 DD」星球是什么?

「程序猿 DD」星球,是一个汇聚互联网技术人的社群。

我们创建于 2017 年,已运行 3 年。这个圈子不贵,但超值!我们励志打造一个垂直服务于技术人的成长类星球!在这里,我们除了要在技术上有所突破,更要在综合认知上有所长进!因此,在本星球中设立 2 大系列精华分享1000 + 个提问的用心回答,覆盖技术各个领域,少讲大道理,只会分享、讨论以及职场心得。

「程序猿 DD」社群的价值是什么?

在星球除了能看到 DD 的分享外,每周三六固定会有专栏干货分享,如:

  • 周三 「#技术人」系列分享技术高手行走江湖的绝技以及职场心得;

  • 周六 「#社会人」系列分享踏入社会切身相关需要知道知识与思维;

在星球里,我们将围绕下面两个话题展开:

「技术人」系列,更新时间:每周三

抛不开的老本行话题,这里会分享各种我见到的觉得不错的分享、讨论以及职场心得。同时,也收录星球中不错的问题讨论,很多讨论放到现在依然可以持续进行,欢迎你的加入!多一点不一样的声音,可能就打开了一种全新的问题解决思路!

「社会人」系列,更新时间:每周六

当我们离开学校踏入社会,我们所要面对的一切都变的复杂起来。我们的关注点需要扩大,因为你已经成为了一名标准的社会人。如果你认为从学生到社会人只需要把原来的学习精力转移到工作精力就好,那么就完全错了。除了工作之外,你有不少知识要补,有不少思维需要转变。这个系列将带着你了解那些可能你平时不去关注,但又与我们切身相关的政策变化等话题。

星球里有技术非常牛逼的一帮人

> Java 劝退师
> JVM 资深研究大佬
> 源码研究系列博主大佬
> 淘宝集团中间件开发大佬
> 支付宝高级设计专家
> 等等

类似这样的人会不断的邀请进来,给大家分享分享他们看到的学到的。


看到一半,那么如何加入「程序猿 DD」星球第一期活动?
心动不如行动,目前优惠活动:早鸟用户(现价 99¥/年,原价 199 ¥/年)

  • 早鸟用户将享受推广期限时折扣,请及时关注当前的最新优惠活动。

  • 支持 3 天无理由退款

  • 优惠在 7 月 9 日晚 20:00 整开放,持续一周


????扫一扫二维码,免费预约

Java反射是什么?看这篇绝对会了!相关推荐

  1. Java应用系统监控看这篇就够了

    Java应用系统监控看这篇就够了 文章目录 业务背景 系统监控发展历程 技术方案 日志监控技术方案 Grafana+阿里云SLS日志服务 分布式链路追踪技术方案 阿里云jaeger方案 开源框架sky ...

  2. 女生就不适合学Java吗_女生不适合学java?给他看这篇文章,女生其实更适合学java,更好就业!...

    原标题:女生不适合学java?给他看这篇文章,女生其实更适合学java,更好就业! 女生适合学java吗?女生做IT怎么样 首先要表明我的观点,编程是不分男女,什么女生不适合学编程的说法,从客观上来说 ...

  3. Java 集合框架,看这篇真的够了!

    话不多说,直接上图: Java 集合,也称作容器,主要是由两大接口 (Interface) 派生出来的: Collection 和 Map 顾名思义,容器就是用来存放数据的. 那么这两大接口的不同之处 ...

  4. 搞懂Java分布式锁实现看这篇文章就对了

    2019独角兽企业重金招聘Python工程师标准>>> 前言: 随着微处理机技术的发展,人们只需花几百美元就能买到一个CPU芯片,这个芯片每秒钟执行的指令比80年代最大的大型机的处理 ...

  5. java空间大战,看这篇足矣了!

    开头 在找工作的过程中,对于 Redis 技术知识的掌握已经成为必须的技能.美团面试常常就会被问到Redis相关知识,而这次我就差点倒在了美团3面,面试官连问我以下几个Redis的问题,然后就卡壳了- ...

  6. Jaeger的客户端采样配置(Java版)(1),看这篇文章准没错

    echo "启动docker-compose" cd jaeger-service-provider && docker-compose up -d &&a ...

  7. java集合大全,看这篇足够理解了

    一.集合入门总结 集合框架: Java中的集合框架大类可分为Collection和Map:两者的区别: 1.Collection是单列集合:Map是双列集合 2.Collection中只有Set系列要 ...

  8. Java集合知识点,看这篇就够了,还有月薪3万简历模板+BAT面试题,帮你进大厂!

    Java集合知识点,猿人花了几天时间整理,还有Java超神之路脑图.月薪3万Java优秀简历模板.全网最全一线大厂Java笔试面试题.1000+本Java开发精华电子书送给大家,希望大家认真学习哦! ...

  9. 大家都说 Java 反射效率低,你知道原因在哪里么

    [这是 ZY 第 17 篇原创技术文章] 预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低的原因 文章概览 我们在 Java 开发中, ...

  10. dwr java有返回值但是js获取不到返回值_一探究竟:Java反射效率低的原因到底在哪?...

    预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低的原因 文章概览 我们在 Java 开发中,难免会接触到反射,而在一些框架中,反射的运 ...

最新文章

  1. 浏览器兼容:IE6,IE7,IE8,FIREFOX,Chrome
  2. Gamma校正及其OpenCV实现
  3. 为什么你喜欢的女生不喜欢你
  4. AtomicIntegerArray类详解
  5. java开发和python哪个好学_学编程,Python和Java哪个更好?
  6. macOS Big Sur Wi-Fi 网络无法连接如何解决
  7. 【AI视野·今日NLP 自然语言处理论文速览 第十五期】Fri, 25 Jun 2021
  8. 【Tyvj3500】【BZOJ1031】字符加密,后缀数组
  9. Java B2B2C o2o多用户商城 springcloud架构-docker-feign-hystrix(六)
  10. 客户端调用服务器端方法——ASP.NET AJAX(Atlas)、Anthem.NET和Ajax.NET Professional实现之小小比较[转]...
  11. 基于力学分析的系泊系统优化设计-第三题
  12. 向量空间相关概念总结-基
  13. 6个实例电路,详解雷击浪涌的防护
  14. SkeyeLive同屏直播库库功能介绍和接口说明与调用
  15. 你还记得当年上课天天玩 JAVA游戏吗
  16. php+vue基于微信小程序的叽喳音乐播放小程序
  17. BPM 应用系统开发案例实战
  18. REW声学测试(一):麦克风校准
  19. kubelet源码分析(三)之 startKubelet
  20. Leetcode 905 c#

热门文章

  1. 供应链攻击已成全球企业的“心腹大患”
  2. java ide编辑器 idea 配置 与 插件
  3. python3 pip 更换国内 pypi 镜像 源
  4. linux acl 权限 给任何用户或用户组设置任何文件/目录的访问权限
  5. linux /etc/hosts.allow和/etc/hosts.deny 限制 禁止 ip连接 黑名单 白名单
  6. linux c 指针 内存 泄漏几种情况
  7. linux centos 下载rpm源码包
  8. linux gcc make cmake 三工具的关系
  9. Nmap源码分析(脚本引擎)
  10. libc.so.6(GLIBC_2.14)(64bit) is needed by...问题的解决办法