金点网络-全网资源,一网打尽
  • 网站首页
    • 金点部落
    • 小游戏
    • OpenAPI
    • 设计资产导航
    • 升级会员
  • 技能学习
    • 体育运动
    • 办公教程
    • 口才演讲
    • 小吃技术
    • 建站教程
    • 摄影教程
    • 棋牌教程
    • 网赚教程
      • 爆粉引流
      • 自媒体
      • 贴吧引流
  • 网站源码
    • 商城/淘客/交易
    • 小说/漫画/阅读
    • 影视/音乐/视频
    • 微信/微商/微擎
    • 理财/金融/货币
    • 模板/主题/插件
  • 游戏源码
    • 精品网单
    • 端游源码
    • 手游源码
    • 页游源码
  • 素材资料
    • 电子文档
    • 综合资料
    • 考研资料
    • 设计素材
    • 音频讲座
      • 人文艺术
      • 名师讲座
      • 说书小说
  • 软件工具
    • Windows软件
    • MacOS软件
    • Android软件
  • 寄售资源
    • 游戏源码
    • 网站源码
    • 软件源码
  • 公益服
登录/注册
  • 专享大神特权
立即开通开通会员抄底价

Java 基础概念·Java 反射

作者 : jamin 本文共5973个字,预计阅读时间需要15分钟 发布时间: 2020-10-18 共1071人阅读

Java 反射

反射的概念

什么是反射

反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

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.

每个类都有一个 Class 对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。

反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。

Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:

  • Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
  • Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
  • Constructor :可以用 Constructor 创建新的对象。

Java 反射主要提供以下功能:

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用 private 方法);
  • 在运行时调用任意一个对象的方法

反射的优点

  • 可扩展性:应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。
  • 类浏览器和可视化开发环境:一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。
  • 调试器和测试工具:调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。

反射的缺点

  • 性能开销:反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
  • 安全限制:使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
  • 内部暴露:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

反射的基本作用

获取 Class 对象

首先理解 Java 对象的两个概念:

  1. Java 语言中,万事万物皆对象,但普通数据类型和静态的成员不是对象。
  2. 类是对象,类是 java.lang.Class 类的实例对象。There is a class named Class。

任何一个类都是 Class 的实例对象,这个实例对象有三种表示方式。

  • 直接获取类对象的 class,Foo.class
  • 调用类实例对象的 foo.getClass() 方法
  • 使用 Class 类的 Class.forName() 静态方法
package com.nicestar;

public class Hello {
  public static void main(String[] args) {
    // Foo 的实例对象
    Foo foo1 = new Foo();

    // Foo 这个类也是 Class 的实例对象,有三种表示方式
    // 1. 第一种表示方式:任何一个类都有一个隐含的静态成员变量 class
    Class c1 = Foo.class;

    // 2.第二种表示方式:已知该类的实例对象,使用 getClass 方法
    Class c2 = foo1.getClass();

    // 3.第三种表示方式
    Class c3 = null;
    try {
      c3 = Class.forName("com.nicestar.Foo");
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }

    // c1、c2、c3 代表了 Foo 类的类类型(class type)
    // c1 == c2 == c3,一个类只能 Class 类的一个实例对象
    // 可以通过 c1、c2、c3 来创建实例对象
    try {
      Foo foo2 = (Foo)c1.newInstance();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

class Foo {}

动态加载类

编译时加载类是静态加载类,运行时加载类是动态加载类。Class.forName("类的全称") 不仅代表了类类型(class type),还代表了动态加载类。

new 创建对象是静态加载类,在编译时刻就需要加载所有可能用到的类。通过动态加载类可以实现按需加载类。

通过动态加载类有两种创建实例对象方式:

  • 使用 Class 对象的 newInstance() 方法来创建 Class 对象对应类的实例
  • 先通过 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance() 方法来创建实例。这种方法可以用指定的构造器构造类的实例。
package com.nicestar;

public class Office {
  public static void main(String[] args) {
    try {
      // 动态加载类
      Class c = Class.forName(args[0]);
      // 通过类类型创建对象
      OfficeAble oa = (OfficeAble) c.newInstance();
      oa.start();

      //获取指定参数的构造器
      //Constructor constructor = c.getConstructor(String.class);
      //根据构造器创建实例
      //OfficeAble oa = (OfficeAble) constructor.newInstance("hello");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

class Word implements OfficeAble {
  @Override
  public void start() {
    System.out.println("wold start");
  }
}

interface OfficeAble {
  public void start();
}

获取类的信息

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

获取类类型,再通过类类型获取类名称:

Class c1 = int.class; // int 的类类型
Class c2 = String.class; // String 的类类型
Class c3 = void.class; // void 的类类型
System.out.println(c1.getName()); // int
System.out.println(c2.getName()); // java.lang.String
System.out.println(c2.getSimpleName()); // String
System.out.println(c3.getName()); // void

工具类获取类的信息:

package com.nicestar;

import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;

public class ClassUtil {
  /**
   * 打印类的信息,包括成员变量与成员函数
   * @param obj 该对象所属类的信息
   */
  public static void printClassMessage(Object obj) {
    // 首先获取类类型
    Class c = obj.getClass();
    // 获取类的名称
    System.out.println("类的名称:" + c.getName());

    /**
     * Method 类,方法对象。一个成员方法就是一个 Method 对象
     * getMethods() 方法获取所有 public 方法,包括父类继承而来的
     * getDeclaredMethods() 方法获取该类自己申明的方法,不问访问权限
     */
    Method[] ms = c.getMethods();
    for (Method m: ms) {
      // 获取方法名
      System.out.print(m.getName());
      // 获取方法返回值类型
      Class returnType = m.getReturnType();
      System.out.print("方法返回值类型:" + returnType.getName());
      // 获取参数类型
      System.out.print("  参数类型:");
      Class[] paramTypes = m.getParameterTypes();
      for (Class c1: paramTypes) {
        System.out.print(c1.getName() + ",");
      }
      System.out.println();
    }

    /**
     * 获取成员变量:java.lang.reflect.Field
     * 成员变量也是对象,Field 类封装了成员变量的操作
     * getFileds() 方法获取所有 public 变量,包括父类继承而来的
     * getDeclaredFileds() 方法获取该类自己声明的变量,不问访问权限
     */
    Field[] fs = c.getDeclaredFields();
    for(Field field: fs) {
      // 获取成员变量的名称
      String fieldName = field.getName();
      // 获取成员变量类型
      Class fieldType = field.getType();
      String typeName = fieldType.getName();
      System.out.println(fieldName + " " + typeName);
    }

    /**
     * 获取构造函数:java.lang.reflect.Constructor
     * 构造函数也是对象
     * getConstructors() 方法获取所有 public 构造函数
     * getDecleardConstructors() 获取该类自己申明的构造函数
     */
    Constructor[] cs = c.getConstructors();
    for (Constructor constructor: cs) {
      // 获取构造函数名称
      System.out.print("构造函数:" + constructor.getName() + "(");
      // 获取构造函数参数列表
      Class[] paramTypes = constructor.getParameterTypes();
      for (Class c1: paramTypes) {
        System.out.print(c1.getName() + ",");
      }
      System.out.println(")");
    }
  }
}

方法的反射

通过反射操作可以获取类的方法然后调用。

package com.nicestar;

import java.lang.reflect.Method;

public class Demo1 {
  public static void main(String[] args) {
    A a = new A();
    Class c = a.getClass();

    // 获取方法 通过名称和参数列表决定
    try {
      // 反射操作调用方法
      // Method m1 = c.getMethod("print", int.class, int.class);
      // m1.invoke(a, 10, 20);

      Method m1 = c.getMethod("print",new Class[]{int.class, int.class});
      m1.invoke(a, new Object[]{10, 20});
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

class A {
  public void print(int a, int b) {
    System.out.println(a + b);
  }

  public void print(String a, String b) {
    System.out.println(a.toUpperCase() + "," + b.toUpperCase());
  }
}

泛型的本质

泛型是参数化类型的应用,操作的数据类型不限定于特定类型,可以根据实际需要设置不同的数据类型,以实现代码复用。

Java 源代码里面类型提供实现泛型功能,而编译后 Class 文件类型就变成原生类型(即类型被擦除掉),而在引用处插入强制类型转换以实现 JVM 对泛型的支持。本质是 Java 泛型只是 Java 提供的一个语法糖。Java 中集合的泛型是防止错误输入的,只在编译阶段有效,可以通过方法的反射来绕过编辑阶段检测。

package com.nicestar;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class Demo2 {
  public static void main(String[] args) {
    ArrayList list1 = new ArrayList();
    ArrayList<String> list2 = new ArrayList<String>();
    list2.add("hello"); // ok
    // list2.add(20); 错误

    Class c1 = list1.getClass();
    Class c2 = list2.getClass();
    System.out.println(c1 == c2); // true

    /**
     * c1 == c2 返回 true 说明编译之后集合的泛型是去泛型话的
     * Java 中集合的泛型是防止错误输入的,只在编译阶段有效
     * 验证:可以通过方法的反射来绕过编辑阶段检测
     */
    try {
      Method m = c2.getMethod("add", Object.class);
      m.invoke(list2, 20); // 可以添加成功
      System.out.println("list2 length:" + list2.size());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Atom ExecutorService ForkJoin Java ReentrantLock synchronized ThreadLocal volatile 后台
本站所提供的部分资源来自于网络,版权争议与本站无关,版权归原创者所有!仅限用于学习和研究目的,不得将上述内容资源用于商业或者非法用途,否则,一切后果请用户自负。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容资源。如果上述内容资对您的版权或者利益造成损害,请提供相应的资质证明,我们将于3个工作日内予以删除。本站不保证所提供下载的资源的准确性、安全性和完整性,源码仅供下载学习之用!如用于商业或者非法用途,与本站无关,一切后果请用户自负!本站也不承担用户因使用这些下载资源对自己和他人造成任何形式的损失或伤害。如有侵权、不妥之处,请联系站长以便删除!
金点网络-全网资源,一网打尽 » Java 基础概念·Java 反射

常见问题FAQ

免费下载或者VIP会员专享资源能否直接商用?
本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。
是否提供免费更新服务?
持续更新,永久免费
是否经过安全检测?
安全无毒,放心食用
jamin

jamin 大神

下一篇
网络协议-组播介绍

相关推荐

Java 基础概念·Java 异常

Java 基础概念·Java 异常

洛奇英雄传 附【安装+工具】教程 网游单机版一键服务端网单

洛奇英雄传 附【安装+工具】教程 网游单机版一键服务端网单

Java 并发编程·volatile 关键字

Java 并发编程·volatile 关键字

天龙八部3域外神翼稀有端附语音教程+GM工具网游一键端无限元宝

天龙八部3域外神翼稀有端附语音教程+GM工具网游一键端无限元宝

Java 并发编程·ThreadLocal

Java 并发编程·ThreadLocal

标签云
Android Atom ExecutorService ForkJoin GM GM后台 GM授权后台 H5 Java Javascript Linux手工服务端 pipbestcom Python ReentrantLock synchronized ThreadLocal volatile Win一键即玩服务端 一键端 传奇 写作 创业 单机 后台 商业端 外网 安卓 安卓苹果双端 工具 手工端 手游 搭建教程 教程 数据分析 文案 游戏源码 端游 经典 网单 职场 自媒体 视频教程 详细搭建教程 运营后台 页游

近期文章

  • 回合手游【逍遥西游之繁华西游】最新整理单机一键既玩镜像服务端_Linux手工端_GM后台_教程
  • 最新整理精品回合制手游【天书奇谈3D混沌完整版】VM一键单机版_linux手工外网端_隐盟视频教程_授权GM后台_双端
  • 典藏修真页游【诸仙列传OL】最新整理Win系服务端_GM工具_详细外网搭建教程
  • MT3换皮MH【浮生若梦尊享挂机修复版】最新整理单机一键即玩镜像端_Linux手工服务端_安卓苹果双端_GM后台_详细搭建教程
  • 大话回合手游【最新引擎之缥缈西游渡劫版】最新整理Linux手工服务端_安卓苹果双端_管理后台_CDK后台_详细搭建教程_视频教程

分类

  • | wordpress插件 |
  • | wordpress模板 |
  • | 其它模板 |
  • | 帝国模板 |
  • | 织梦插件 |
  • | 织梦模板 |
  • A5源码
  • Android软件
  • APP引流
  • E语言
  • H5
  • LUA
  • QQ营销
  • SEO推广
  • Windows软件
  • 体育运动
  • 信息数据
  • 创业专题
  • 办公教程
  • 口才演讲
  • 名师讲座
  • 商城/淘客/交易
  • 小吃技术
  • 小说/漫画/阅读
  • 建站教程
  • 引流脚本
  • 影视/音乐/视频
  • 影视资源
  • 微信/微商/微擎
  • 微信小程序
  • 微信营销
  • 微擎模块
  • 手游源码
  • 技能学习
  • 抖音课程
  • 摄影教程
  • 棋牌教程
  • 模板/主题/插件
  • 游戏源码
  • 爆粉引流
  • 理财/金融/货币
  • 生活老师
  • 电商客
  • 电子文档
  • 电脑教程
  • 社群营销
  • 站长工具
  • 精品网单
  • 系统工具
  • 素材资料
  • 综合资料
  • 编程经验
  • 网站源码
  • 网络安全
  • 网赚教程
  • 网赚源码
  • 考研资料
  • 脚本/AI/智能
  • 自媒体
  • 英语学习
  • 营销软件
  • 设计素材
  • 说书小说
  • 贴吧引流
  • 软件工具
  • 软文营销
  • 逆向软件
  • 音频讲座
  • 页游源码

提供最优质的资源集合

立即加入 友好社区
金点网络-全网资源,一网打尽

新一代全网资源综合门户网(www.pipbest.com-金点网络)专注服务于互联网,提供各类最新最全的免费源码下载(PHP、ASP、JSP、.NET),更提供免费工具,免费源码下载,软件下载,素材下载,赚钱教程下载,交流论坛等网站运营相关的一切内容,为网友搜罗最有价值的网站源码下载与技术教程等服务!

服务目录
  • 金点OpenAPI
  • 金点云
  • 金点支付
友情链接
  • 数媒派
  • 国家电网
快速搜索

本站由Nice强力驱动

声明: 本站部分内容属于原创转载请注明出处 如有侵权行为请严格参照本站【版权声明】与我们联系,我们将在48小时内容进行处理!

本站部分内容属于原创转载请注明出处 如有侵权行为请严格参照本站【版权声明】与我们联系,我们将在48小时内容进行处理!
© 2016-2023 PipBest.Com - 金点网络 & 金点部落. All rights reserved 京ICP备2022005359号-1
  • 关注有礼
  • 签到
  • 客服
    官方QQ群 常见问题 FAQ

    在线客服

    点我联系

    直接说出您的需求!
    切记!带上资源连接与问题!

    工作时间: 9:30-21:30

  • 暗黑
    模式
  • 全屏
  • 投稿
    赚钱
  • 首页

  • 签到

  • 切换

  • 客服

金点网络-全网资源,一网打尽
  • 登录
  • 注册
or
or
忘记密码?
金点网络-全网资源,一网打尽
  • 网站首页 ►
    • 金点部落
    • 小游戏
    • OpenAPI
    • 设计资产导航
    • 升级会员
  • 技能学习 ►
    • 体育运动
    • 办公教程
    • 口才演讲
    • 小吃技术
    • 建站教程
    • 摄影教程
    • 棋牌教程
    • 网赚教程 ►
      • 爆粉引流
      • 自媒体
      • 贴吧引流
  • 网站源码 ►
    • 商城/淘客/交易
    • 小说/漫画/阅读
    • 影视/音乐/视频
    • 微信/微商/微擎
    • 理财/金融/货币
    • 模板/主题/插件
  • 游戏源码 ►
    • 精品网单
    • 端游源码
    • 手游源码
    • 页游源码
  • 素材资料 ►
    • 电子文档
    • 综合资料
    • 考研资料
    • 设计素材
    • 音频讲座 ►
      • 人文艺术
      • 名师讲座
      • 说书小说
  • 软件工具 ►
    • Windows软件
    • MacOS软件
    • Android软件
  • 寄售资源
    ►
    • 游戏源码
    • 网站源码
    • 软件源码
  • 公益服
×
u3** 刚刚下载了 爆款吸金文案训练

    全网资源·一网打尽

  • 金点出品,必属精品!
  • 发布原创内容,获取高额提成!
  • 我们与你共创美好数字生态!
  • 无特殊说明密码默认:pipbest.com