Java的反射

Java源代码编译后生成class文件,下图是一个class文件的结构图,截自《Java虚拟机规范》。

Java程序运行过程中,ClassLoader会根据需要加载这些class文件。每一个class文件加载完成后,虚拟机都会为其生成一个Class对象,可以通过类名.class或者实例引用.getClass()获取该对象。通过Class对象,我们就可以获取class文件中绝大部分信息,这就是Java反射。

Java的泛型

类型参数

相对于类型参数,我们应该更熟悉方法参数。当我们定义一个方法的时候,都会定义参数列表(形参),方法执行过程中,根据传参(实参)就能完成差异化逻辑。这就是封装方法的意义。

在Java中,相对于方法,类型是更高一个维度的概念,它也需要参数来完成更好的封装。例如:Java web的开发中,前后端交互的所有接口,都应该有统一的数据格式

public class Response {

private Object data;

public Object getData() {return data;}

public void setData(Object data) {this.data = data;}

}

然后接口代码:

public Response listUser() {

User user = ...;

Response resp = new Response();

resp.setData(user);

return resp;

}

上面的代码运行起来没有任何的问题,Response类也很通用。但这种通用是弱化了编译器静态检查功能换来的,listUser方法隐含了将User类型的值设置到Response.data的约束,但是编译器无法获知这一点,也就无法为你做这个检查。使用类型参数,我们可以将隐含的含义告知编译器,这样编译器就能为我们做编译检查了,如:

public class Response {

private T data;

public T getData() {return data;}

public void setData(T data) {this.data = data;}

}

接口代码:

public Response listUser() {

User user = ...;

Response resp = new Response<>();

resp.setData(user);

return resp;

}

类型参数,就是Java泛型,泛型的本质就是参数化类型。

类型擦除

Java泛型是Java 1.5之后才引入的。为了兼容历史版本,Java将泛型实现在Java语言层面(语法糖),也就是类型擦除。代码示例:

public static void main(String[] args) {

Response r1 = new Response<>();

Response r2 = new Response<>();

System.out.println(r1.getClass() == r2.getClass()); // 输出:true

}

输出true,说明Response和Response是同一种类型,程序在运行过程中是不携带类型实参的。通过Javap反汇编上面的代码:

0: new #2 // class com/yangqingbang/Response

3: dup

4: invokespecial #3 // Method com/yangqingbang/Response."":()V

7: astore_1

8: new #2 // class com/yangqingbang/Response

11: dup

12: invokespecial #3 // Method com/yangqingbang/Response."":()V

15: astore_2

可以看到,两次都是new com/yangqingbang/Response(),说明编译后的字节码中就没携带类型实参。

反射获取类型参数

前文说到,Java的泛型是类型擦除的,那么为什么反射又能获取到泛型相关信息呢?这个得从前面的class文件结构图说起,重点关注attribute_info域,也就是属性表。请注意,类、字段、方法均包含属性表,分别位于各自的结构内。属性表中包含一个Signature属性,截自《Java虚拟机规范》:

可见,类型擦取仅是指方法编译后的字节码中不携带类型参数,但在class文件结构中,还是携带了类型参数的。看下面两个例子:

public class Response {}

// javap反汇编

javap -v Response.class

# 省略无关信息,可见Signature中携带了类型参数

Signature: #14 // Ljava/lang/Object;

SourceFile: "Response.java"

public class UserResponse extends Response {}

// javap反汇编

javap -v UserResponse.class

# 省略无关信息,可见Signature中携带了类型参数

Signature: #12 // Lcom/yangqingbang/Response;

SourceFile: "UserResponse.java"

泛型的使用

很多资料把泛型的使用方式划分为3种:泛型类、泛型接口、泛型方法。在我看来,泛型接口在泛型的使用上是泛型类的一个子集,这里不进行细分了。

泛型类

public class UserService {

private E default;

public List list(E param) {return null;}

}

泛型类中的类型参数V,E在类被继承或类实例化时候被指定。

泛型方法

public class BeanFactory {

public T createInstance(Class clazz) throws Exception {

return clazz.getConstructor().newInstance();

}

}

泛型方法中的类型参数可以根据调用参数、返回值指定。

反射与泛型 java_深入理解Java的反射和泛型相关推荐

  1. java xml 反射_Java 读取XML文件以及Java 的反射机制实现

    Java 读取XML文件以及Java 的反射机制实现 代码部分 import java.io.File; import javax.xml.parsers.DocumentBuilder; impor ...

  2. android 反射调用方法可不可以重载,使用Java进行反射投射和重载方法调度

    请注意,所有代码都是一个简化示例,目的是仅传达我的问题的核心思想.它应该都经过轻微的编辑后编译并运行.使用Java进行反射投射和重载方法调度 我有几个类都实现了一个通用接口. public inter ...

  3. 深入理解Java Class反射机制

    本篇主要是深入对Java中的Class对象进行分析,这对后续深入理解反射技术非常重要,这篇有点偏向内功类文章. 深入理解Class对象 RRTI的概念以及Class对象作用 认识Class对象之前,先 ...

  4. 我爸是李刚 java_深入理解java继承从“我爸是李刚”讲起

    前言 本文主要多方面讲解java继承,旨在让初学者通俗易懂,至于"我爸是李刚",反正楼主也不知道谁爸是李刚. @ 1.继承的概述 1.1.继承的由来 至于由来简单一句话:多个类中存 ...

  5. volite java_如何理解 JAVA volatile 关键字

    最近在重新梳理多线程,同步相关的知识点.关于 volatile 关键字阅读了好多博客文章,发现质量高适合小白的不多,最终找到一篇英文的非常通俗易懂.所以学习过程中顺手翻译下来,一方面巩固知识,一方面希 ...

  6. this指针 java_彻底理解Java中this指针

    每次看到Java中的this指针,总摸不着头绪.在网上看了很多人的讲解,还是不知道this指针到底是什么东西,今天的的这篇日志可以让你看清this到底是谁.(内容摘自:http://www.mathc ...

  7. 龙卷风java_程序设计-理解java继承-遁地龙卷风

    (0)写在前面 编程和现实世界是息息相关的,你是如何理解现实世界中的继承呢? 继承在编程中应理解为:对父类资源(本文只讨论方法)的使用,父类方法只提供类基本的功能,父类方法之间不存在调用关系. (1) ...

  8. Java通过反射了解集合泛型的本质(Class反射都是在运行时执行的)

    目录 理论 实例 理论 Class的反射都是运行时候来执行的,Java中集合的泛型是为了防止错误的输入,只在编译阶段有效,绕过编译就无效了. 下面演示用反射绕过编译器, 实例 程序结构: 运行截图如下 ...

  9. 深入理解 Java 反射:Class (反射的入口)

    深入理解 Java 反射系列: 深入理解 Java 反射:Class (反射的入口) 深入理解 Java 反射:Field (成员变量) 深入理解 Java 反射:Method (成员方法) 读完本文 ...

最新文章

  1. oracle学习 sql基本语法(三),Oracle数据库学习三
  2. 注册表故障恢复 必须使用记录或另一备份以恢复包含系统注册表数据的文件。恢复成功...
  3. 抢劫(01背包+对立事件)
  4. SpringBoot @Valid各种注解使用说明
  5. 基本数据类型之间的运算
  6. 《Unit Testing》1.4. 成功的测试套件拥有哪些属性?
  7. impala的substr从第几位截到最后一位_冰雪奇缘2彩蛋:片名内含深意,艾莎是第13位公主象征着背叛...
  8. 虚拟化VMware ESXi 6.7服务器安装配置详细步骤图文
  9. RequireJS对文件合并与压缩实现方法
  10. ORACLE数据库与Navicat安装 随手笔记
  11. 百度大脑5.0实现史上最大升级,发布远场语音交互芯片“鸿鹄”
  12. 仅需一行代码,小白也可以制作自己的专属二维码!
  13. 【计算机】数据结构-严蔚敏/清华大学P1
  14. Python学习手册之控制结构(二)
  15. 计算机游戏物体运动代码,Flash游戏教程:控制物体运动三法 -电脑资料
  16. 各个数据库的空间函数
  17. 简直太猛了!GitHub《植物大战僵尸》重磅开源,两天就破千Star!
  18. CSS和js和HTML一起做出网页版别踩白块游戏
  19. 数值策划的自我修养(一):任务流程的修改
  20. atom编辑器Linux中文版,linux atom 怎么支持中文 Linux下Atom编辑器不支持中文解决方法...

热门文章

  1. 今天诛仙3服务器维护么2014年4月27,诛仙2021年3月4日更新维护公告 诛仙2021年3月4日更新维护内容一览_手心游戏...
  2. 小明利用计算机软件绘制函数,2019年人大附中初二下期末模拟数学试题
  3. 关闭windows hello然后尝试再次运行安装程序_蜂鸟E203系列——Windows下运行hello world例程...
  4. c语言动态双端栈的原理,数据结构(C语言版)例题(第三章:栈和队列)
  5. bzoj 1562 [NOI2009]变换序列 二分图
  6. 7. Reverse Integer(反转整数)
  7. UVa 10570 - Meeting with Aliens
  8. Adaboost、RandomFrest、GBRT的区别
  9. HTML5中input标签有用的新属性
  10. jQuery全局Ajax事件处理器