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

获取 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 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 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"));

}

}

/*

obj.txt 内容:

a=java.util.Date

b=javax.swing.JFrame

*/

方式二

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 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"));

}

}

/* extObj.txt 内容

a=java.util.Date

b=javax.swing.JFrame

# set the title of a

a%title=Test Title

*/

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 + "]";

}

}

import java.lang.reflect.Field;

public class FieldTest {

public static void main(String[] args) throws Exception {

Person p = new Person();

Class 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 getinstance(Class 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 getinstance 反射_Java 基础篇之反射相关推荐

  1. java单线程循环调度_Java基础篇之Java线程模型

    原标题:Java基础篇之Java线程模型 Java运行系统在很多方面依赖于线程,所有的类库设计都考虑到多线程.实际上,Java使用线程来使整个环境异步.这有利于通过防止CPU循环的浪费来减少无效部分. ...

  2. java分层命名_JAVA基础篇(5)-POJO的命名规则

    源起于alibaba的开发手册类的命名规范 参考自--知乎上的回答 变脸命名规范 不同类型的对象在架构设计中用于不同的用途,如下的分层架构表示各个POJO的用途.为什么要在分层架构中国,定义这些POJ ...

  3. java 线程模型_Java基础篇之Java线程模型

    Java运行系统在很多方面依赖于线程,所有的类库设计都考虑到多线程.实际上,Java使用线程来使整个环境异步.这有利于通过防止CPU循环的浪费来减少无效部分. 为更好的理解多线程环境的优势可以将它与它 ...

  4. Java学习笔记之基础篇

    Java学习笔记之基础篇 目录 Java如何体现平台的无关性? 面向对象(OO)的理解 面向对象和面向过程编程的区别 面向对象三大特征 静态绑定和动态绑定(后期绑定) 延伸:类之间的关系 组合(聚合) ...

  5. Java程序设计语言(基础篇)机械工业出版社 原属第10版

    链接:https://pan.baidu.com/s/1txoB3sk0SdT1u8RpS2x-Kg  提取码:rxkd  Java程序设计语言(基础篇)机械工业出版社 原属第10版 外加一本Java ...

  6. [转载] JAVA语言程序设计(基础篇)第十版课后题答案(第一章)

    参考链接: Java中的Scanner和nextChar() JAVA语言程序设计(基础篇)第十版课后题答案 第一章 第二题 /** Created by ysy on 2018/7/6. */ pu ...

  7. java语言程序设计基础篇课后答案_《Java语言程序设计:基础篇》课后复习题答案-第十五章.pdf...

    <Java语言程序设计:基础篇>课后复习题答案-第十五章 Chapter15Graphics 1. Theycoordinateshouldincreaseandthexcoordinat ...

  8. Java学习---Day16_IO流基础篇

    Java学习-Day16_IO流基础篇 文件操作 操作磁盘上的某一个文件或某一个文件夹,可以对他们进行创建或删除.移动.属性获取.属性设置等操作.但是,不包含读取文件的内容.拷贝文件 ps:java中 ...

  9. invader的java学习第一天基础篇

    invader的java学习第一天基础篇 一.java主要历史 ①java是Sun公司的产品,09年被Oracle公司收购. ②java语言之父:詹姆士高斯林 二.jdk.jre.jvm三者关系 jd ...

最新文章

  1. 简单比较搜索引擎与推荐系统
  2. VC中的Attach和Detach
  3. 适用于单片机的数据加密算法:xxtea
  4. android MotionEvent中getX()和getRawX()的区别
  5. 不常用≠没用 Win7容易忽略的四个功能
  6. JavaScript面向对象编程指南(五) 原型
  7. [转]【高并发】高并发秒杀系统架构解密,不是所有的秒杀都是秒杀!
  8. lnmp无法远程连接mysql_MySQL(一):设置root 可以远程连接MySQL
  9. 机器学习中的数学(二)--梯度下降法
  10. Android开发之TextView排版问题
  11. 零基础机器学习(1)- 我们为什么要学习Python?
  12. Exchange服务器系统蓝屏及脱域后解决办法
  13. 数据库封装 sql server mysql_sqlserver数据库操作封装
  14. ajax的结果处理,jQuery ajax返回数据的后续处理
  15. Csharp develop
  16. 机器学习--决策树(熵、信息增益(ID3)、C4.5、多方式源码实战)
  17. android 5.0 lg g2,升级到Android 5.0 的LG G2怎样Root?
  18. Excepted in :flat namespace
  19. PIC16 F887 单片机 直流电机PWM调速 PID调速 PID算法
  20. 如何防御DDOS等流量攻击

热门文章

  1. html5实现定位签到,H5+百度地图实现移动端考勤定位打卡
  2. 【redis问题】无限Waiting for the cluster to join......
  3. 质量保障与管理——各大厂质量保障实践分享汇总
  4. 【C++ 程序】 Fractal Designer 0.2
  5. 2.8 其他快速入门必要知识
  6. 区块链革命,革的是哪些“黑中介”的命?
  7. 如何判断一笔交易是否属于欺诈 数据挖掘算法与现实生活中的应用案例
  8. altium designer创建圆形实心填充
  9. android字体图形绘制,android paint api drawText 绘制字体字形
  10. ipxe无盘服务器,ipxe uefi pxe HTTP启动文件及启动菜单的个人体会