反射
使用反射获取程序运行时的对象和类的真实信息。

获取 Class 对象
每个类被加载之后,系统会为该类生成一个对应的 Class 对象,通过该 Class 对象可以访问到 JVM 中的这个类。
使用 Class 类的 forName(String clazzName) 静态方法。字符串参数的值是某个类的全限定类名,必须包含完整的包名。
调用某个类的 class 属性。
调用某个对象的 getClass() 方法。该方法是 java.lang.Object 类中的一个方法,所有的 Java 对象都可以调用,返回该对象所属类对应的 Class 对象。

获取 Class 对象中信息
Class 类提供了大量的实例方法来获取该 class 对象所对应的类的详细信息。更多请参考 API。

import java.lang.reflect.*;
import java.lang.annotation.*;public class ClassTest {private ClassTest() {}public ClassTest(String name) {System.out.println("执行有参数的构造器");}public void info() {System.out.println("执行无参数的info方法");}public void info(String str) {System.out.println("执行有参数的info方法" + ",其 str 参数值: " + str);}class Inner {}public static void main(String[] args) throws Exception {Class<ClassTest> clazz = ClassTest.class;// 获取 clazz 对象所对应类的全部构造器Constructor<?>[] ctros = clazz.getDeclaredConstructors();System.out.println("ClassTest 的全部构造器如下: ");for (Constructor c : ctros) {System.out.println(c);}// 获取 clazz 对象所对应类的全部 public 构造器Constructor<?>[] publicCtors = clazz.getConstructors();System.out.println("ClassTest的全部public构造器如下:");for (Constructor c : publicCtors) {System.out.println(c);}// 获取 clazz 对象所对应类的全部 public 方法Method[] mtds = clazz.getMethods();System.out.println("ClassTest 的全部 public 方法如下: ");for (Method md : mtds) {System.out.println(md);}// 获取 clazz 对象所对应类的指定方法System.out.println("ClassTest 里带一个字符串参数的 info 方法为:" + clazz.getMethod("info", String.class));// 获取 clazz 对象所对应类的全部注解Annotation[] anns = clazz.getAnnotations();System.out.println("ClassTest 的全部 Annotation 如下: ");for (Annotation an : anns) {System.out.println(an);}// 获取 clazz 对象所对应类的全部内部类Class<?>[] inners = clazz.getDeclaredClasses();System.out.println("ClassTest 的全部内部类如下: ");for (Class c : inners) {System.out.println(c);}// 使用 Class.forName() 方法加载 ClassTest 的 Inner 内部类Class inClazz = Class.forName("ClassTest$Inner");// 访问该类所在的外部类System.out.println("inClazz 对应类的外部类为: " + inClazz.getDeclaringClass());System.out.println("ClassTest 的包为:" + clazz.getPackage());System.out.println("ClassTest 的父类为:" + clazz.getSuperclass());}
}

应用
Class 对象可以获得对应类的方法(由 Method 表示)、构造器(由 Constructor 表示)、成员变量(由 Field 对象表示),且这个三个类都实现了 java.lang.reflect.Member 接口。程序可以通过 Method 对象来执行对应的方法,通过 Constructor 对象来调用对应的构造器创建实例,通过 Field 对象直接访问并修改对象的成员变量值。

创建对象
使用 Class 对象的 newInstance() 方法来创建 Class 对象对应类的实例。要求该 Class 对象的对应类有默认构造器
先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance() 方法来创建该 Class 对象对应类的实例。这种方式可以选择使用指定的构造器来创建实例

方式一
实现了一个简单的对象池,该对象池会根据配置文件读取 key-value 对,然后创建这些对象并放入 HashMap 中

import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;public class ObjectPoolFactory {private Map<String, Object> objectPool = new HashMap<>();private Object createObject(String clazzName) throws InstantiationException, IllegalAccessException, ClassNotFoundException {Class<?> clazz = Class.forName(clazzName);// 使用 Class 对象对应的类的默认构造器return clazz.newInstance();}public void initPool(String fileName) throws InstantiationException, IllegalAccessException, ClassNotFoundException {try (FileInputStream fis = new FileInputStream(fileName)) {Properties props = new Properties();props.load(fis);for ( String name: props.stringPropertyNames()) {objectPool.put(name, createObject(props.getProperty(name)));}} catch (IOException ex) {System.out.println("读取" + fileName + "异常");}}public Object getObject(String name) {return objectPool.get(name);}public static void main(String[] args) throws Exception{ObjectPoolFactory pf = new ObjectPoolFactory();pf.initPool("obj.txt");System.out.println(pf.getObject("a"));System.out.println(pf.getObject("b"));}
}

方式二

import java.lang.reflect.Constructor;public class CreateJFrame {public static void main(String[] args) throws Exception {Class<?> jframeClazz = Class.forName("javax.swing.JFrame");// 选择使用指定的构造器Constructor ctor = jframeClazz.getConstructor(String.class);Object obj = ctor.newInstance("测试窗口");System.out.println(obj);}
}

调用方法
每个 Method 对象对应一个方法,获得 Method 对象后,就可以通过该 Method 来调用它对应的方法。
Method 包含一个 invoke() 方法,该方法的签名如下:
Object invoke(Object obj, Object... args):该方法中的 obj 是执行方法的主调(即类的实例对象),后面的 args 是执行该方法的实参
下面是对之前的对象工厂池进行增强,允许在配置文件中增加配置对象的成员变量值,对象池工厂会读取该对象配置的成员变量值,并利用该对象对应的 setter 方法设置成员变量的值:

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;public class ExtendedObjectPoolFactory {// 定义一个对象池,前面是对象名,后面是实际的对象private Map<String, Object> objectPool = new HashMap<>();private Properties config = new Properties();// 从指定文件中初始化 Properties 对象public void init(String fileName) {try (FileInputStream fis = new FileInputStream(fileName);) {config.load(fis);} catch (IOException ex) {System.out.println("读取" + fileName + "异常");}}// 定义创建对象的方法private Object createObject(String clazzName) throws InstantiationException, IllegalAccessException, ClassNotFoundException {// 根据字符串来获取对应的 Class 对象Class<?> clazz = Class.forName(clazzName);// 使用 clazz 对应类的默认构造器创建实例return clazz.newInstance();}// 初始化对象池public void initPool() throws InstantiationException, IllegalAccessException, ClassNotFoundException {for (String name : config.stringPropertyNames()) {if (!name.contains("%")) {objectPool.put(name, createObject(config.getProperty(name)));}}}// 根据属性文件来调用指定对象的 setter 方法public void initProperty() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {for (String name : config.stringPropertyNames()) {if (name.contains("%")) {String[] objAndProp = name.split("%");Object target = getObject(objAndProp[0]);String mtdName = "set" + objAndProp[1].substring(1);// 通过 target 的 getClass() 获取它的实现类所对应的 Class 对象Class<?> targetClass = target.getClass();// 获取希望调用的 setter 方法Method mtd = targetClass.getMethod(mtdName, String.class);// 通过 Method 的 invoke 方法执行 setter 方法mtd.invoke(target, config.getProperty(name));}}}public Object getObject(String name) {// 从 objectPool 中取出指定 name 对应的对象return objectPool.get(name);}public static void main(String[] args) throws Exception {ExtendedObjectPoolFactory epf = new ExtendedObjectPoolFactory();epf.init("extObj.txt");epf.initPool();epf.initProperty();System.out.println(epf.getObject("a"));}
}

PS:当通过 Method 的 invoke() 方法来调用对应的方法时,Java 会要求程序必须有调用该方法的权限。如果需要调用某个对象的 private 方法,则可以先调用 Method 对象的如下方法:
setAccessible(boolean flag):值为 true,表示该 Method 在使用时取消访问权限检查
访问成员变量值#
Filed 提供如下两组方法来读取或设置成员变量值:
getXxx(Object obj):获取 obj 对象的该成员变量的值。此处的 Xxx 对应 8 中基本类型。如果成员变量的类型是引用类型,则直接使用 get
setXxx(Object obj, Xxx val):将 obj 对象的成员变量值设为 val 值。此处的 Xxx 对应 8 中基本类型。如果成员变量的类型是引用类型,则直接使用 set

public class Person {private String name;private int age;public String toString() {return "Person[name:" + name + ", age:" + age + "]";}
}
public class FieldTest {public static void main(String[] args) throws Exception {Person p = new Person();Class<Person> personClazz = Person.class;Field nameField = personClazz.getDeclaredField("name");nameField.setAccessible(true);nameField.set(p, "crazy");Field ageField = personClazz.getDeclaredField("age");ageField.setAccessible(true);ageField.setInt(p, 30);System.out.println(p);}
}

泛型在反射中的应用
在反射中使用泛型,反射生成的对象就不需要进行强制类型转换。

import java.util.Date;public class CrazyitObjectFactory {public static <T> T getinstance(Class<T> cls) {try {return cls.newInstance();} catch (Exception e) {e.printStackTrace();return null;}}public static void main(String[] args) {// 获取实例后无需进行类型转换Date d = CrazyitObjectFactory.getinstance(Date.class);}
}

学习大数据:Java基础篇之反射相关推荐

  1. 菜鸟学习笔记:Java基础篇7(包装类、时间相关类、文件类、异常处理类)

    菜鸟学习笔记:Java其他常用类 基本数据类型包装类 时间处理和文件处理相关类 Date时间类 SimpleDateFormat Calendar日历类 文件类 异常机制 异常的概念 Java异常处理 ...

  2. 菜鸟学习笔记:Java基础篇6(数组、字符串)

    菜鸟学习笔记:Java常用类(数组.字符串) 数组 概述 数组的定义 二维数组 数组查找和排序 查找 排序 数组运用--字符串 不可变字符序列(String) 可变字符序列(StringBuilder ...

  3. 菜鸟学习笔记:Java基础篇4(面向对象三大特征)

    菜鸟学习笔记:Java面向对象篇中 继承 概念 方法重写(override) Object类 Super关键字 组合 final关键字补充 封装 访问控制符 多态 继承 概念 继续上一篇的例子: #m ...

  4. 菜鸟学习笔记:Java基础篇3(面向对象思想、程序执行过程内存分析、面向对象重要概念)

    菜鸟学习笔记:Java面向对象篇上 Java面向对象的思想 Java程序执行过程内存分析 Java垃圾回收机制 构造方法 方法重载(overload) static关键字 this关键字 Java面向 ...

  5. 菜鸟学习笔记:Java基础篇2(变量、运算符、流程控制语句、方法)

    菜鸟学习笔记:Java基础篇2 变量 基本概念 变量作用域 final关键字 运算符 算术运算符 比较运算符 逻辑运算符 位运算符 赋值运算符 条件运算符 运算符优先级 Java三种流程控制语句 顺序 ...

  6. 菜鸟学习笔记:Java基础篇5(抽象类与接口、回调函数、内部类)

    菜鸟学习笔记:Java面向对象篇下 抽象类 接口 回调函数 内部类 成员内部类 匿名内部类 抽象类 通过前面知识的学习,抽象类这个概念应该不难理解,但比较容易和后面要说的接口混淆,而且在面试中也比较爱 ...

  7. 【全集】大数据Java基础

    课程介绍 本课程是由猎豹移动大数据架构师,根据Java在公司大数据开发中的实际应用,精心设计和打磨的大数据必备Java课程.通过本课程的学习大数据新手能够少走弯路,以较短的时间系统掌握大数据开发必备语 ...

  8. 大数据java基础吗?

    大数据必备 关于大数据基础知识,以前浪尖写过一篇文章,也多次在 知识星球里分享过经验. 具体学习内容,可以参看如下文章: 入门大数据必读 这个可以看到做大数据的话java是必需品,因为基本所有的大数据 ...

  9. 大数据入门-基础篇01-hadoop框架简介

    声明:本文主要根据八斗学院孙国宇老师的Hadoop大数据实战手册进行的整理,仅限入门学习! 第一章 hadoop简介 Hadoop 是一个由 Apache 基金会所开发的 开源分布式系统基础架构.用户 ...

  10. 大数据 -- java基础8 接口特点和用法

    1.接口:interface关键字     (1)语句定义格式: interface 接口名{} (2)接口是如何实现的呢?         接口不能直接实例化,需要一个关键字供其他类实现该接口:im ...

最新文章

  1. 【深度学习】(2) 数据加载,前向传播2,附python完整代码
  2. java怎么xml文件解析_Java对Xml文件解析
  3. 图:BFS(深度优先搜索)图解分析代码实现
  4. 上传图片之上传前判断文件格式与大小
  5. macOS如何使用命令启动服务/停止服务/查看服务
  6. 求最大素数和最小素数
  7. 理解Python的With语句
  8. 用计算机名怎么共享电视盒,机顶盒怎么通过电脑实现局域网共享
  9. 第一次注册苹果开发者账号
  10. C4996 'sprintf': This function or variable may be unsafe.
  11. KKK下拉框lookupedit绑定数据时,添加一条固定数据
  12. 戴尔t30服务器装系统6,手把手为你演示win7系统戴尔t30装win7的具体办法
  13. 双绞线有两种接法:EIA/TIA 568B标准和EIA/TIA 568A标准。
  14. Windows文件搜索工具(文件、文件夹、文件内容搜索,支持大小写、全字、正则表达式搜索条件)
  15. 前端面试题(css)
  16. RT-Thread Studio 项目实战教程 | 快速打造一个桌面mini网络时钟
  17. CSDN日报20170727——《想提高团队技术,来试试这个套路!》
  18. 基本函数画图软件(直接下载,一元二次方程图像,幂函数图像,指数图像,三角函数图像,反三角函数图像)
  19. epoll反应堆模型
  20. UiPath 安装与下载

热门文章

  1. linux 板卡驱动开源项目Comedi使用编译流程
  2. mysql表关联_MySQL表关联的几种常用方式
  3. Java SE基础(更新中)
  4. 视频提取关键帧工具类KeyFramesExtractUtils.py,动态支持三种取帧方式,关键参数可配置,代码经过优化处理,效果和性能更好。
  5. java计算机毕业设计基于安卓Android的运动管理软件app
  6. 我国计算机的最新进展,我国计算机最新进展
  7. [微积分笔记]第二类曲线/面积分总结
  8. 平面点云面积计算的两种方式
  9. 说服的传播模型(转载)
  10. 非专业老师上怎么计算机课,非计算机专业计算机基础教学研究