浅谈java发射机制
目录
什么是反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
初探
对反射的最初接触是学习jdbc时,加载数据库驱动时会这样写:Class.forName("com.mysql.jdbc.Driver"),当时似懂非懂的也不知道是什么意思,随着自己的不断学习,越来越感觉反射的神奇,让我们一起来揭开它的神秘面纱吧。
学习一个知识,自然是最先从api开始,反射涉及的类,除了Class类之外,基本上都在java.lang.reflect包里面,常用的类有Constructor,Field,Method类等,AccessibleObject类是前面三个类的基类,主要包含设置安全性检查等方法,下面,我们看一下reflect包的结构

可以看出,涉及的类并不多,让我一起来看一下其中比较常用的类的用法吧
## 初始化
测试用例采用junit+log4j,新建一个test类,一个javabean
其中name属性get,set方法用private修饰
User类
package com.test;
public class User {
  private String name = "init";
  private int age;
  public User() {}
  public User(String name, int age) {
    super();
    this.name = name;
    this.age = age;
  }
  private String getName() {
    return name;
  }
  private void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  @Override
  public String toString() {
    return "User [name=" + name + ", age=" + age + "]";
  }
}
Test类
public class ReflectTest {
  private static Logger logger = Logger.getLogger(ReflectTest.class);
  private static Class<User> userClass = User.class;
}
类
在类加载的时候,jvm会创建一个class对象
class对象是可以说是反射中最常用的,获取class对象的方式的主要有三种
- 根据类名:类名.class
- 根据对象:对象.getClass()
- 根据全限定类名:Class.forName(全限定类名)
  @Test
  public void classTest() throws Exception {
    // 获取Class对象的三种方式
    logger.info("根据类名:  \t" + User.class);
    logger.info("根据对象:  \t" + new User().getClass());
    logger.info("根据全限定类名:\t" + Class.forName("com.test.User"));
    // 常用的方法
    logger.info("获取全限定类名:\t" + userClass.getName());
    logger.info("获取类名:\t" + userClass.getSimpleName());
    logger.info("实例化:\t" + userClass.newInstance());
  }
console
根据类名:  	class com.test.User
根据对象:  	class com.test.User
根据全限定类名:	class com.test.User
获取全限定类名:	com.test.User
获取类名:	com.test.User
实例化:	User [name=init, age=0]
构造函数
构造函数是java创建对象的必经之路,所以通过反射拿到一个类的构造函数后,再去创建这个类的对象自然是易如反掌,常用的方法如下:
  @Test
  public void constructorTest() throws Exception {
    // 获取全部的构造函数
    Constructor<?>[] constructors = userClass.getConstructors();
    // 取消安全性检查,设置后才可以使用private修饰的构造函数,也可以单独对某个构造函数进行设置
    // Constructor.setAccessible(constructors, true);
    for (int i = 0; i < constructors.length; i++) {
      Class<?> parameterTypesClass[] = constructors[i].getParameterTypes();
      System.out.print("第" + i + "个构造函数:\t (");
      for (int j = 0; j < parameterTypesClass.length; j++) {
        System.out.print(parameterTypesClass[j].getName() + (j == parameterTypesClass.length - 1 ? "" : "\t"));
      }
      logger.info(")");
    }
    // 调用构造函数,实例化对象
    logger.info("实例化,调用无参构造:\t" + constructors[0].newInstance());
    logger.info("实例化,调用有参构造:\t" + constructors[1].newInstance("韦德", 35));
  }
console
第0个构造函数:	 ()
第1个构造函数:	 (java.lang.String	int)
实例化,调用无参构造:	User [name=init, age=0]
实例化,调用有参构造:	User [name=韦德, age=35]
属性
犹记得学习spring ioc之时,对未提供set方法的private属性依然可以注入感到神奇万分,现在看来,这神奇的根源自然是来自于java的反射,常用的方法如下:
  @Test
  public void fieldTest() throws Exception {
    User user = userClass.newInstance();
    // 获取当前类所有属性
    Field fields[] = userClass.getDeclaredFields();
    // 获取公有属性(包括父类)
    // Field fields[] = cl.getFields();
    // 取消安全性检查,设置后才可以获取或者修改private修饰的属性,也可以单独对某个属性进行设置
    Field.setAccessible(fields, true);
    for (Field field : fields) {
      // 获取属性名 属性值 属性类型
      logger.info("属性名:" + field.getName() + "\t属性值:" + field.get(user) + "  \t属性类型:" + field.getType());
    }
    Field fieldUserName = userClass.getDeclaredField("name");
    // 取消安全性检查,设置后才可以获取或者修改private修饰的属性,也可以批量对所有属性进行设置
    fieldUserName.setAccessible(true);
    fieldUserName.set(user, "韦德");
    // 可以直接对 private 的属性赋值
    logger.info("修改属性后对象:\t" + user);
  }
console
属性名:name	属性值:init  	属性类型:class java.lang.String
属性名:age	属性值:0  	属性类型:int
修改属性后对象:	User [name=韦德, age=0]
方法
大家对javabean肯定不会陌生,在用框架操作javabean时,大多都是通过反射调用get,set方法Javabean进行操作,常用的方法如下:
  @Test
  public void methodTest() throws Exception {
    User user = userClass.newInstance();
    // 获取当前类的所有方法
    Method[] methods = userClass.getDeclaredMethods();
    // 获取公有方法(包括父类)
    // Method[] methods = userClass.getMethods();
    // 取消安全性检查,设置后才可以调用private修饰的方法,也可以单独对某个方法进行设置
    Method.setAccessible(methods, true);
    for (Method method : methods) {
      // 获取方法名和返回类型 获取参数类型:getParameterTypes
      logger.info("方法名:" + method.getName() + " \t返回类型:" + method.getReturnType().getName());
    }
    // 获取无参方法
    Method getMethod = userClass.getDeclaredMethod("getName");
    // 取消安全性检查,设置后才可以调用private修饰的方法,也可以批量对所有方法进行设置
    getMethod.setAccessible(true);
    // 调用无参方法
    logger.info("调用getName方法:" + getMethod.invoke(user));
    // 获取有参方法
    Method setMethod = userClass.getDeclaredMethod("setName", String.class);
    // 取消安全性检查,设置后才可以调用private修饰的方法,也可以批量对所有方法进行设置
    setMethod.setAccessible(true);
    // 调用有参方法
    logger.info("调用setName方法:" + setMethod.invoke(user, "韦德"));
    logger.info("通过set方法修改属性后对象:\t" + user);
  }
console
方法名:toString 	返回类型:java.lang.String
方法名:setAge 	返回类型:void
方法名:getAge 	返回类型:int
方法名:getName 	返回类型:java.lang.String
方法名:setName 	返回类型:void
调用getName方法:init
调用setName方法:null
通过set方法修改属性后对象:	User [name=韦德, age=0]
完整的 源码 https://github.com/zhaoguhong/blogsrc
总结
不难看出,Java反射中的构造函数,属性,方法有着诸多相似之处,不仅仅是因为它们有着共同的父类AccessibleObject,基本上所有的api都有相似之处。学习的过程中死记api是最愚蠢的,找方法,理解反射的设计思路。去尝试感悟设计思想,才是王道。
上面只是对反射的常用方法提供了示例,最好的学习方法自然是参照api,自己去实践。纸上得来终觉浅,绝知此事要躬行。通过自己的不断练习,体会,思考,达到融会贯通的目的。
思考
java以面向对象和封装性著称,但反射在java中堪称作弊器,似乎无所不能,给人一种建了一道围墙,下面又留了一道门的感觉,是否破坏了程序的封装性?
笔者认为:循规蹈矩固然好,但过于注重规范反而影响程序的灵活性。Java反射给我们带了灵活性的同时,极大的方便了我们的编程,而且反射堪称各大框架的基础。如此看来,显然利大于弊,你怎么看?
浅谈java发射机制的更多相关文章
- 浅谈java反射机制
		目录 什么是反射 初探 初始化 类 构造函数 属性 方法 总结 思考 什么是反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意 ... 
- 浅谈java编译机制和运行机制
		源文件和字节码的组成方式 源文件: 拓展名后跟java的文件即java的源文件. Java 源码编译由以下三个过程组成: 1.分析和输入到符号表 2.注解处理 3.语义分析和生成class文件 流程图 ... 
- 浅谈 java 反射机制
		一:Java反射概念 Java反射是Java被视为动态(或准动态)语言的一个关键性质.这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其mod ... 
- 浅谈Java反射机制 之 使用类的 属性、方法和构造函数
		前面两篇我们总结了Java反射机制如何获取类的字节码,如何获取构造函数,属性和方法, 这篇我们将进一步验证如何使用我们获取到的属性.方法以及构造函数 1.使用 反射 获取到的 属性 import ja ... 
- 浅谈Java反射机制 之 获取类的字节码文件 Class.forName("全路径名") 、getClass()、class
		另一个篇:获取 类 的 方法 和 属性(包括构造函数) 先贴上Java反射机制的概念: AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它 ... 
- 浅谈Java回调机制
		像许多网上介绍回调机制的文章一样,我这里也以一个现实的例子开头:假设你公司的总经理出差前需要你帮他办件事情,这件事情你需要花些时间去做,这时候总经理肯定不能守着你做完再出差吧,于是就他告诉你他的手机号 ... 
- 浅谈Java参数传递机制
		Java参数传递  才疏学浅,今天才知道Java中方法的参数是可以传递对象引用进去的.  Java的参数传递机制很简单,其实就是值传递.  所谓值传递,也就是我们在给方法传递一个参数的时,传递的 ... 
- 浅谈Java反射机制 之 获取类的 方法 和 属性(包括构造函数)
		上一篇 获取 类 的字节码文件 我们讲到了获取类的字节码文件的三种方法 第三种方法通过getClass("全路径名")获取字节码文件最符合要求 1.获取构造方法 先贴上我们要获取的 ... 
- 浅谈Java的反射机制和作用
		浅谈Java的反射机制和作用 作者:Java大师 欢迎转载,转载请注明出处 很多刚学Java反射的同学可能对反射技术一头雾水,为什么要学习反射,学习反射有什么作用,不用反射,通过new也能创建用户对象 ... 
随机推荐
- Linux - 死锁现象
			一.死锁的概念: 1.死锁的现象描述: 在很多应用中,需要一个进程排他性的访问若干种资源而不是一种.例如,两个进程准备分别将扫描的文档记录到CD上.进程A请求使用扫描仪, 并被授权使用.但进程B首先请 ... 
- 【小瑕疵】在div里插入img后在底部留有缝隙怎么解决
			[本文转载自http://blog.sina.com.cn/s/blog_9fd5b6df01013mld.html] 图片IMG与容器下边界之间有空隙怎么办?这里介绍3中简单的解决方法. 第一,给图 ... 
- CF #228 div1 B. Fox and Minimal path
			题目链接:http://codeforces.com/problemset/problem/388/B 大意是用不超过1000个点构造一张边权为1的无向图,使得点1到点2的最短路的个数为给定值k,其中 ... 
- python基本数据类型——int
			一.int的范围 python2: 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31-1: 在64位系统上,整数的位数为64位,取值范围为-2**63-2**63-1: pyth ... 
- 某次模拟考试day2t3 菊菊的数据结构
			[题目描述] 菊菊是一个码农,他很喜欢码一些高(e)级(xin)数据结构. 有一天,菊菊在打网赛时遇到了 wfj.wfj 觉得他很有前途,可以做下一代码农大神. 于是乎,wfj 给菊菊出了一道题,来检 ... 
- linux性能之iostat
			在使用linux系统的过程中,总是可能需要当前io性能的状态信息是怎么样?这里就就是一下iostat,可以通过iostat来初步查看io的状态信息. 1.常用方式 iostat -xdk 1 10 或 ... 
- 仿淘宝左侧菜单导航栏纯Html + css 写的
			这俩天闲来没事淘宝逛了一圈看到淘宝的左侧导航菜单做的是真心的棒啊,一时兴起,查了点资料抓了几个图片仿淘宝写了个css,时间紧写的不太好,大神勿喷,给小白做个参考 废话不多说先来个效果图 接下来直接上代 ... 
- 蓝桥杯-放麦子-java
			/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ... 
- crontab定时任务不执行的原因
			1.重启crontab若是遇见"You (cloudlogin) are not allowed to use this program (crontab) ... 
- shop_list
			#!/usr/bin/env python # -*- coding: utf-8 -*- #输出商品列表,用户输入序号,显示用户选中的商品 li = ["手机", "电 ... 
