JavaSE-22 反射
学习要点
- 反射概念
- 反射的应用
反射概述
1 反射机制
定义
Java反射机制是指在程序在运行状态中,动态获取信息以及动态调用对象方法的功能。
Java反射的动态性质:运行时生成对象实例、运行期间调用方法、运行时更改属性。
Java程序执行过程

反射执行过程

1) Java反射机制是在编译时并不确定哪个类被加载了,而是在程序运行的时候才加载、探知、使用。
2) Java反射机制能够知道类的基本结构,这种对Java类结构的探知能力,称为Java类的“自审”。例如开发环境eclipse或者myeclipse中的代码自动提示功能,就是利用了Java的反射机制,对所创建对象的探知和自审。
3) 通过Java反射,可以实现以下功能:
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的方法和属性。
- 在运行时调用任意一个对象的方法。
2 Java反射常用API
ava反射常用核心类位于java.lang.reflect包,常用类:
1) Class类—可获取类和类的成员信息
2) Field类—可访问类的属性
3) Method类—可调用类的方法
4) Constructor类—可调用类的构造方法
使用反射的基本步骤
1) 导入java.lang.reflect.*
2) 获得需要操作的类的Java.lang.Class对象
3) 调用Class的方法获取Field、Method等对象
4) 使用反射API进行操作 (设置属性﹑调用方法)
反射的应用
1 获取类的信息
Java类加载机制
Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能。
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
获取Class对象
1) 调用对象的getClass( )方法
定义学生信息类
/** 学生信息类 */
public class Student {
private int sid;// 学号
private String sname;// 姓名
private char sgender;// 性别
private int sage;// 年龄
//构造函数(略)
//属性封装(略)
}
定义测试类获得学生信息类的Class对象
Student student=new Student(); Class clazz=student.getClass();
2) 调用类的Class属性(推荐使用:类型安全、性能高)
Class clazz = Student.class;
3) 使用Class类的forName()静态方法
Class clazz = Class.forName("com.etc.demo.Student");// 参数是类全名
从Class对象获取信息
1) 访问Class对象对应类所包含的构造方法
|
方法 |
说明 |
|
Constructor getConstructor(Class[] params) |
返回指定参数的public构造方法 |
|
Constructor[] getConstructors() |
返回所有public构造方法 |
|
Constructor getDeclaredConstructor(Class[] params) |
返回指定参数的构造方法,与访问级别无关 |
|
Constructor[] getDeclaredConstructors() |
返回所有构造方法,与访问级别无关 |
示例代码
Constructor constructors[] =
clazz.getDeclaredConstructors();//返回所有构造方法
Constructor constructors[] =
clazz.getConstructors();//返回所有public构造方法
//返回指定参数的构造方法,与访问修饰符无关
Constructor con = clazz.getDeclaredConstructor
(new Class[]{int.class,String.class,char.class,int.class});
//简要输出构造方法信息
System.out.println(con.toString());
2) 访问Class对象对应类所包含的方法
|
方法 |
说明 |
|
Method getMethod(String name,Class[] params) |
返回方法名为name的指定参数列表的public方法 |
|
Method[] getMethods() |
返回所有public方法 |
|
Method getDeclaredMethod(String name, Class[] params) |
返回方法名为name的指定参数列表的所有方法 |
|
Method[] getDeclaredMethods() |
返回所有方法 |
3) 访问Class对象对应类所包含的属性
|
方法 |
说明 |
|
Field getField(String name) |
返回public指定名称为name的属性 |
|
Field getFields() |
返回全部public属性 |
|
Field getDeclaredField(String name) |
返回指定名称属性 |
|
Field[] getDeclaredFields() |
返回全部属性 |
4) 访问Class对象对应类所包含的注解
|
方法 |
说明 |
|
<A extends Annotation>A getAnnotation (Class<A> annotationClass) |
返回该Class对象所表示类上指定类型的注释,若没有,则返回null |
|
Annotation[] getAnnotations() |
返回所有注释 |
|
Annotation[] getDeclaredAnnotations() |
返回直接存在于此元素上的所有注释 |
5) 访问Class对象对应类的其他信息
|
方法 |
说明 |
|
Class[] getDeclaredClasses() |
返回Class对象对应类的全部内容类 |
|
Class[] getDeclaringClass() |
返回Class对象对应类的全部外部类 |
|
Class[] getInterfaces() |
返回Class对象对应类全部实现的接口 |
|
int getModifiers() |
返回此类或接口的所有修饰符。使用Modifer工具类方法解码返回值获得访问修饰符 |
|
Package getPackage() |
获得此类的包 |
|
String getName() |
返回类的名称 |
|
String getSimpleName() |
返回类的简称 |
|
Class getSuperclass() |
返回基类Class对象 |
示例代码
Class clazz = Student.class;
System.out.println("------类的字段------------");
Field fields[] = clazz.getDeclaredFields();
for (Field field : fields)
System.out.println(field.getName() + " " + field.getType());
System.out.println("-------类的方法-----------");
Method methods[] = clazz.getDeclaredMethods();
for (Method method : methods)
System.out.println(method.getName());
System.out.println("-------类的构造方法-----------");
Constructor constructors[] = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("--------类所在包、完整名称、父类----------");
System.out.println(clazz.getPackage().getName());
System.out.println(clazz.getName());
System.out.println(clazz.getSuperclass());
2 创建对象
通过反射创建对象有两种形式:
- 使用Class对象的newInstance()方法创建对象
- 使用Constructor对象创建对象
使用newInstance()创建对象
要求Class对象对应的类有默认构造方法。
示例代码
Class clazz=Student.class;
Student student=(Student)clazz.newInstance();
student.setSname("张三");
student.setSage(21);
student.sayHello();
使用Constructor对象指定构造方法创建对象
示例代码
Class clazz=Student.class; Constructor constructor= clazz.getConstructor(int.class,String.class,char.class,int.class); Student student=(Student) constructor.newInstance(1001,"张三",'男',22); student.sayHello();
3 访问类的属性
使用Field对象可以获取对象的属性。通过Field对象可以对属性进行取值或赋值操作。主要方法如下:
|
方法 |
说明 |
|
Xxx getXxx(Object obj) |
Xxx对应Java的8个基本数据类型,如int。obj为该属性所在的对象。 |
|
Object get(Object obj) |
获得引用类型属性值。 |
|
void setXxx(Object obj,Xxx val) |
将obj对象该属性设置为val值。 |
|
void set(Object obj,objcet val) |
将obj对象该属性设置为val值。针对引用类型。 |
|
void setAccessible(bool flag) |
对获取到的属性设置访问权限。参数为true,可以对私有属性取值和赋值。 |
示例代码
/** 人类 */
class Person {
private String name;// 姓名
private int age;// 年龄
/** 重写toString()方法 */
public String toString() {
return "my name is" + name + ",age is" + age;
}
}
/** 测试代码 */
Person p = new Person();// 创建Person对象
Class clazz = Person.class;// 获取Person对应的Class对象
// 获取Person类的name属性,使用getDeclaredField()方法获取各种访问级别的属性
Field nameField = clazz.getDeclaredField("name");
// 设置通过反射访问该Field时取消权限检查
nameField.setAccessible(true);
// 使用set方法为p对象指定Field设置值
nameField.set(p, "andy");
//同理设置age属性
Field ageField=clazz.getDeclaredField("age");
ageField.setAccessible(true);
ageField.setInt(p,21);
//输出结果
System.out.println(p.toString());
4 访问类的方法
使用Method对象可以调用对象的方法。在Method类中包含一个invoke()方法,方法的定义如下:
Object invoke(Object obj,Object… args);
obj:执行该方法的对象
args:执行该方法时传入该方法的参数列表
示例代码
/** 计算器类 */
public class Calculator {
/** 加法 */
public int add(int a, int b) {
return a + b;
}
/** 减法 */
private int sub(int a, int b) {
return a - b;
}
}
/** 测试代码 */
// 获取Calculator对应的Class对象
Class clazz = Calculator.class;
// 创建Calculator对象
Calculator calculator = new Calculator();
// add方法调用
Method methodAdd = clazz.getMethod("add", int.class, int.class);
int result1 = (int) methodAdd.invoke(calculator, 10, 12);
System.out.println("10+12=" + result1);
// sub方法的调用
Method methodSub = clazz.getMethod("sub", int.class, int.class);// 报错如何处理?
int result2 = (int) methodSub.invoke(calculator, 13, 4);
System.out.println("13-4=" + result2);
注意:invoke()方法调用对应的方法时,java会检查权限。
解决方案:如果是调用private方法,是用setAccessible()方法设置允许调用。
// sub方法的调用
Method methodSub = clazz.getDeclaredMethod("sub", int.class, int.class);
methodSub.setAccessible(true);
int result2 = (int) methodSub.invoke(calculator, 13, 4);
System.out.println("13-4=" + result2);
5 Array类
在java.lang.reflect包下提供了一个Array类。
Java反射技术除了可以在运行时动态地决定要创建什么类型的对象,访问哪些成员变量,方法,还可以动态地创建各种不同类型,不同维度的数组。
动态创建数组的步骤如下:
1) 创建Class对象,通过class属性、forName(String)方法或者getClass()方法指定数组元素的类型。
2) 调用Array.newInstance(Class, length_of_array)动态创建数组。
操作动态数组常用方法
1) 访问动态数组元素的方法和通常有所不同,它的格式如下所示,注意该方法返回的是一个Object对象
Array.get(arrayObject, index)
2) 为动态数组元素赋值的方法也和通常的不同,它的格式如下所示, 注意最后的一个参数必须是Object类型
Array.set(arrayObject, index, object)
示例代码:
import java.lang.reflect.Array;
public class Test {
public static void main(String[] args) throws Exception {
// 创建一个元素类型为String,长度为10的数组
Object arr = Array.newInstance(String.class, 10);
// 依次为数组中index为7、8的元素赋值
Array.set(arr, 7, "China");
Array.set(arr, 8, "German");
// 依次取出数组中index为7、8的元素的值
Object obj1 = Array.get(arr, 7);
Object obj2 = Array.get(arr, 8);
// 输出元素的值
System.out.println(obj1.toString() + " PK " + obj2.toString());
}
}
上机练习
需求说明
- 使用反射修改和查询Student类的姓名属性(public)和年龄属性(private)。
- 使用反射动态执行Student类输出信息的方法。
JavaSE-22 反射的更多相关文章
- Java匹马行天下之JavaSE核心技术——反射机制
Java反射机制 一.什么是反射? 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及 ...
- 转载:JavaSE之反射
该文章转载自:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html Java反射详解 本篇文章依旧采用小例子来说明,因为我 ...
- day 22 反射,双下方法
反射: 反射:通过字符串去操作对象(类,空间等等)的属性或方法反射的四个方法 hasattr *** getattr *** setattr *** delattr *** # getattr 用法c ...
- JavaWeb-JDBC-Mybatis-Junit-Maven-Lombok
Java与数据库 初识JDBC JDBC是什么? JDBC英文名为:Java Data Base Connectivity(Java数据库连接),官方解释它是Java编程语言和广泛的数据库之间独立于数 ...
- java reflect反思总结
--------------TestBean package lh.demo.bean; public class TestBean { private String userName; priv ...
- 《JavaScript语言精粹》【PDF】下载
<JavaScript语言精粹>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382204 内容简介 javascript曾是&q ...
- Java匹马行天下之新手学习目录
Java匹马行天下之新手学习目录 学习路线 [Java匹马行天下——Java学习路线] [Java匹马行天下——开篇学习计划] 基础篇 [Java匹马行天下之学编程的起点——编程常识知多少] [Jav ...
- WebServer Project-01-反射
简介 上网浏览网页,离不开服务器,客户请求页面,服务器响应页面,响应的内容是根据每个web请求来产生动态内容的,其内部即启动多个线程来产生不同内容.这种请求响应的交互,都是基于HTTP协议的. 当然现 ...
- (精简)Spring框架的IoC(替代工厂类实现方法)和AOP(定义规则,约定大于配置)
Spring的核心框架主要包含两个技术,分别用来处理工厂类,以及事务处理和连接管理的. 两大核心概念 1) IoC:控制反转,在现在的开发中,如果想建立对象并设置属性,是需要先new对象,再通过se ...
- java-反射-注解-json-xml
反射: 框架设计的灵魂 框架:半成品软件.可以再框架的基础上进行软件开发,简化代码 定义:将类的各个组成部分封装为其他对象,这就是反射机制 好处: 可以再程序运行过程中,操作这些对象 可以解耦,提高程 ...
随机推荐
- Java语法基础练习2
---恢复内容开始--- 1.仔细阅读示例:EnumTest.java分析结果 代码: 运行结果: 分析:枚举类型就是一个类,枚举中的常量就是枚举类型中的实例,可把字符串转化为枚举:而且他本身是一个类 ...
- 2.jeesite增删改查
一.准备数据 在数据库中中添加一张表和数据,以mysql为例 SET NAMES utf8; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------- ...
- 打开CAD时出现“acvmtools.arx ARX命令中发生异常
打开CAD时出现“acvmtools.arx ARX命令中发生异常 解决办法1: 试试进入CAD安装的目录,删掉它acvmtools.arx,重新打开cad.(注:acvmtools.arx一 ...
- 使用VS2008,VS2010编译64位的应用程序
要编译生成64位的应用程序,就必须把vs2008,或vs2010的配置管理器设置为x64. 如果你的配置管理器那里没有x64这个选项,那么是你在安装vs时可能没有安装这个组件.你不用卸载vs,只需打开 ...
- poj 3295 Tautology 伪递归
题目链接: http://poj.org/problem?id=3295 题目描述: 给一个字符串,字符串所表示的表达式中p, q, r, s, t表示变量,取值可以为1或0.K, A, N, C, ...
- 51nod 1134最长递增子序列
1134 最长递增子序列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素 ...
- Spring配置文件中未引入dubbo命名空间头部配置而引起的错误案例
问题描述: Spring配置文件中未引入dubbo命名空间的头部配置而引起项目启动时报出如下错误信息: org.springframework.beans.factory.xml.XmlBeanDef ...
- 关于springMVC传参问题
今天写项目,碰到一个以前灭有注意到的问题,一般情况下使用springMVC @Controller注解之后,被此注解标记的方法的参数名只需要跟页面表单的标签的name的值相同即可拿到页面的值,但是如果 ...
- Redis和SpringDataRedis
一.Redis简介 Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,运行在内存中,由ANSI C编写.企业开发通常采用Redis来实现缓存.同类的产品还有memcac ...
- rest_framework基于generics.CreateAPIView创建用户
最近在写新版的devops3.0,被generics.CreateAPIView创建用户密码序列化的问题折磨的欲仙欲死.反复看源码测试,得出下面的流程,这也是做generics.CreateAPIVi ...