java反射笔记
反射(reflect)
1. Class对象
1.1 什么是Class对象
当JVM加载某个class文件的时候,会自动创建一个唯一的Class对象(注意:由同一个类加载器加载的class文件),这个Class对象包含了整个class类的信息(例如:类的名称、访问修饰符、字段、字段描述、方法等等一切信息)。当使用new关键字创建这个类的实例时,jvm都会使用这个Class对象来创建类的实例。
1.1 获取Class对象方式
| 方式 | 说明 |
|---|---|
| Test.class | 通过类名.class直接获取 |
| t1.getClass() | 通过对象的getClass()方法获取 |
| Class.forName("...") | 使用Class类的forName静态方法获取,参数给的是完整类名(包名+类名) |
2. 反射
2.1 什么是反射
所谓的反射,是在程序运行时动态获得任何一个Class对象的成员信息(类信息、字段、构造方法、成员方法等),并且能在运行时依据某个Class对象创建当前类的实例。
2.2 Class常用API
| 方法 | 说明 |
|---|---|
| newInstance() | 创建类实例 |
| getName() | 获取类的完整类名 |
| getSimpleName() | 获取类的简单类名 |
| getPackage() | 获取类对应的包信息 |
| getSuperclass() | 获取父类的Class对象 |
| getInterfaces() | 获取实现的所有接口 |
| getClassLoader() | 获取当前类的类加载器 |
| getConstructor(..) | 获取公共且明确参数类型的构造方法 |
| getDeclaredConstructor(..) | 获取受保护且明确参数类型的构造方法 |
| getConstructors() | 获取所有公共的构造方法 |
| getDeclaredConstructors() | 获取所有(包括受保护)的构造方法 |
| getField(..) | 根据字段名称获取某一个公共的字段 |
| getDeclaredField(..) | 根据字段名称获取当前类某一个的字段(包括受保护的) |
| getFields() | 获取所有公共的字段,包括继承自父类的公共字段 |
| getDeclaredFields | 获取当前类所有字段,包括受保护的(不包括继承父类的字段) |
| getMethod(..) | 根据方法名以及参数类型获取一个公共的方法 |
| getDeclaredMethod(..) | 根据方法名以及参数类型获取当前类的一个受保护的方法 |
| getMethods() | 获取所有公共的方法(包括继承自父类的公共方法) |
| getDeclaredMethods() | 获取当前类的所有方法,包括受保护的(不包括继承父类的方法) |
| isAnnotation() | 此Class是否是一个注解 |
| isAnnotationPresent(..) | 当前Class时是否定义了某个注解 |
| getAnnotation(..) | 获取当前类上定义的某个注解 |
| getAnnotations() | 获取当前类上定义的所有注解 |
| isEnum() | 此Class是否是一个枚举 |
| isArray() | 此Class是否是一个数组类型 |
| isInterface() | 此Class是否是一个接口 |
| ... | 其他API请参照官方文档 |
public class TestClass {
public static void main(String[] args) throws Exception{
Class<?> clazz = Class.forName("edu.nf.reflect.Users");
//通过Class对象来创建实例,当前类必须提供一个公开并且无参的构造方法
Users user = (Users) clazz.newInstance();
//获取类的完整类名
System.out.println(clazz.getName());
//获取类的简单类名
System.out.println(clazz.getSimpleName());
//获取类所在的包名
System.out.println(clazz.getPackage().getName());
//获取当前类的父类的Class
System.out.println(clazz.getSuperclass());
//获取当前类实现的所有接口
System.out.println(clazz.getInterfaces());
//获取加载这个类的类加载器
System.out.println(clazz.getClassLoader());
//获取公共并且参数类型为String的构造方法
clazz.getConstructor(String.class);
//获取私有并且参数为int类型的构造方法
clazz.getDeclaredConstructor(Integer.TYPE);
//获取所有公共的构造方法
Constructor[] consArray1 = clazz.getConstructors();
//获取所有构造方法,包括公共和是有的
Constructor[] consArray2 = clazz.getDeclaredConstructors();
//获取某一个公共的字段,参数指定字段的名字
Field f1 = clazz.getField("address");
System.out.println(f1.getName());
//获取某一个受保护的字段
Field f2 = clazz.getDeclaredField("tel");
System.out.println(f2.getName());
System.out.println("-----------------------");
//获取所有公共的字段,包括继承自父类的公共字段
Field[] fieldArray1 = clazz.getFields();
for (Field field : fieldArray1) {
System.out.println(field.getName());
}
System.out.println("-----------------------");
//获取所有字段,包括受保护的(不包括继承父类的字段)
Field[] fieldArray2 = clazz.getDeclaredFields();
for (Field field : fieldArray2) {
System.out.println(field.getName());
}
System.out.println("-----------------------");
//获取某一个公共的方法(第一个参数指定方法名,第二个参数指定方法参数的类型,这是一个可变参数,有多少个参数就要指定多少个类型)
Method m1 = clazz.getMethod("say", String.class);
System.out.println(m1.getName());
//获取某一个受保护的方法
Method m2 = clazz.getDeclaredMethod("call");
System.out.println(m2.getName());
System.out.println("-----------------------");
//获取所有公共的方法(包括继承自父类的公共方法)
Method[] methodArray1 = clazz.getMethods();
for (Method method : methodArray1) {
System.out.println(method.getName());
}
System.out.println("-----------------------");
//获取本类的所有方法,包括受保护的(不包括父类的方法)
Method[] methodArray2 = clazz.getDeclaredMethods();
for (Method method : methodArray2) {
System.out.println(method.getName());
}
}
}
2.3 Class对象中的成员
| 成员 | 说明 |
|---|---|
| Constructor | 用于描述类的构造方法 |
| Field | 用于描述类的字段 |
| Method | 用于描述类的方法 |
| Parameter | 用于描述方法或构造方法的参数信息 |
2.3.1 Constructor常用API
| API | 说明 |
|---|---|
| getName() | 获取当前构造方法的名称 |
| getParameterCount() | 获取构造方法的参数个数 |
| getDeclaringClass() | 获取声明此构造方法的Class类 |
| setAccessible(..) | 设置访问开关 |
| newInstance(..) | 使用当前的Constructor构建实例 |
| ... | 其他API请参照官方文档 |
public class TestCons {
public static void main(String[] args) throws Exception{
//加载Users的class信息,并构建Class对象
Class<?> clazz = Class.forName("edu.nf.reflect.Users");
//通过class对象访问构造方法信息,
// 根据构造方法的参数类型获取某一个公共的构造方法
Constructor cons1 = clazz.getConstructor(int.class);
// 访问受保护的构造方法
Constructor cons2 = clazz.getDeclaredConstructor(int.class);
//构造方法的名称
System.out.println(cons1.getName());
//获取构造方法的参数个数
System.out.println(cons1.getParameterCount());
//获取定义这个构造方法的Class类
System.out.println(cons1.getDeclaringClass());
//通过构造方法来创建类的实例
//由于构这个造方法是私有的,因此必须强制打开访问开关
cons1.setAccessible(true);
//然后通过newInstance方法来创建类的实例,并传入构造方法所需的参数
Users user = (Users)cons1.newInstance(21);
//获取所有的构造方法(包括私有和公有的)
Constructor[] cons = clazz.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println("参数个数: "+con.getParameterCount());
}
}
}
2.3.2 Field常用API
| API | 说明 |
|---|---|
| getType() | 获取当前字段类型 |
| getName() | 获取当前字段名称 |
| get(..) | 获取当前字段的值 |
| set(..) | 给当前字段赋值 |
| setAccessible(..) | 设置访问开关 |
| ... | 其他API请参照官方文档 |
public class TestField {
public static void main(String[] args) throws Exception{
Class<?> clazz = Class.forName("edu.nf.reflect.Users");
//创建类的实例
Object instance = clazz.newInstance();
//获取一个受保护的字段
Field f = clazz.getDeclaredField("tel");
//打开访问开关
f.setAccessible(true);
//给字段赋值(第一个参数指定当前类的实例,第二个参数是具体的值)
f.set(instance, "123456");
//取值(get方法的参数也是指定当前类的实例)
System.out.println(f.get(instance));
//获取字段的类型
System.out.println(f.getType());
//获取字段的名称
System.out.println(f.getName());
}
}
2.3.3 Method常用API
| API | 说明 |
|---|---|
| getName() | 获取当前方法名称 |
| getReturnType() | 获取当前方法的返回值 |
| getParameterCount() | 获取当前方法参数的个数 |
| getParameters() | 获取当前方法的参数对象 |
| getParameterTypes() | 获取当前方法的所有参数类型 |
| setAccessible(..) | 设置访问开关 |
| invoke(..) | 回调当前的method |
| ... | 其他API请参照官方文档 |
public class TestMethod {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("edu.nf.reflect.Users");
//构建当前类的实例
Object instance = clazz.newInstance();
//获取受保护的call方法
Method method = clazz.getDeclaredMethod("call", String.class);
//获取方法的名称
System.out.println(method.getName());
//获取方法的返回值类型
System.out.println(method.getReturnType());
//获取方法参数的个数
System.out.println(method.getParameterCount());
//获取方法的所有参数对象
System.out.println(method.getParameters());
//获取方法中所有参数的类型
Class<?>[] paramsType = method.getParameterTypes();
for (Class<?> aClass : paramsType) {
System.out.println(aClass);
}
//调用当前方法(第一个参数是当前类的实例,第二个参数开始是方法所需的参数)
//invoke方法返回的是当前调用的方法的返回值
//这个方法是受保护的,因此需要先打开访问开关
method.setAccessible(true);
Object returnValue = method.invoke(instance, "12345678");
System.out.println(returnValue);
}
}
2.3.4 Parameter常用API
| API | 说明 |
|---|---|
| getType() | 获取参数类型 |
| getName() | 获取参数的名称(说明:JDK8默认编译的时候是不会将参数名信息保存在字节码中,如果想要获取参数名,那么在编译时就需要加上编译参数 ,如:javac -parameters Users.java) |
| ... | 其他API请参照官方文档 |
public class TestParameter {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("edu.nf.reflect.Users");
//先获取指定的受保护的方法
Method callMethod = clazz.getDeclaredMethod("call", String.class);
//获取该方法的参数信息
Parameter[] params = callMethod.getParameters();
for (Parameter param : params) {
//获取参数的类型
System.out.println(param.getType());
//获取参数的名称(在JDK8之前是没有办法获取参数名的,必须通过第三方字节码工具来获取)
//JDK8默认编译的时候是不会讲参数名信息保存在字节码中
//如果想要获取参数名,那么在编译时就需要加上编译参数
//如:javac -parameters Users.java
System.out.println(param.getName());
}
}
}
java反射笔记的更多相关文章
- java反射笔记(学习尚硅谷java基础教程)
反射一.概述:Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性 ...
- Java系列笔记(2) - Java RTTI和反射机制
目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这 ...
- 【设计模式】学习笔记17:代理模式之保护代理与Java反射
本文出自 http://blog.csdn.net/shuangde800 本笔记内容: 1. Java动态代理,反射机制 2. 保护代理 3. 应用保护代理实现的约会系统 ----------- ...
- java反射的理解与应用(某大神博客中看到的博文,写的真的太好了,果断转载作为笔记)
原文地址:http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html#undefined 一.什么是反射机制 简单的来说,反射机制指的是程序 ...
- Java开发笔记(七十八)面向对象的后门——反射
作为一门面向对象的编程语言,Java认为一切皆是对象,每个对象都能归属于某个类,甚至每个类均可提取出一种特殊的类型,即Class类型.早在前面介绍多态的时候,就提到每个类都存在独一无二的基因,通过比较 ...
- Java开发笔记(七十九)利用反射技术操作私有属性
早在介绍多态的时候,曾经提到公鸡实例的性别属性可能被篡改为雌性,不过面向对象的三大特性包含了封装.继承和多态,只要把性别属性设置为private私有级别,也不提供setSex这样的性别修改方法,那么性 ...
- Java开发笔记(八十)利用反射技术操作私有方法
前面介绍了如何利用反射技术读写私有属性,不单是私有属性,就连私有方法也能通过反射技术来调用.为了演示反射的逆天功能,首先给Chicken鸡类增加下列几个私有方法,简单起见弄来了set***/get** ...
- JAVA学习笔记—review基本知识[反射与异常]
JAVA学习笔记—review基本知识[反射与异常] 1.异常: 1.1异常的分类: Java会将所有的异常封装成对象,其根本父类为Throwable. Throwable有两个子类:Error 和E ...
- Java注解和反射笔记
Java注解和反射笔记 1 注解 1.1 定义 Annotation是从JDK1.5开始引入的技术 作用 不是程序本身,可以对程序作出解释 可以被其他程序(编译器等)读取 格式 @注释名,可以添加一些 ...
随机推荐
- Chapter 4 Invitations——6
The snow washed away for good after that one dangerously icy day. 在危险的冰天雪地之后,这场雪洗走了很多. Mike was disa ...
- JavaScript和Ajax部分(2)
11. DOM如何操作文档的标准节点? 1) 查看节点:使用getElementById(),getElementByName(),getElementByTagName可以查看HTML文档中的任何元 ...
- ES6躬行记(10)——正则表达式
在ES5中,如果使用构造函数RegExp()初始化RegExp对象(即正则表达式),并且它的第一个参数是正则表达式时,那么不允许再传入标志字符串(即第二个参数).而ES6更改了这项限制,如果传入了第二 ...
- 使用Python进行并发编程
让计算机程序并发的运行是一个经常被讨论的话题,今天我想讨论一下Python下的各种并发方式. 并发方式 线程(Thread) 多线程几乎是每一个程序猿在使用每一种语言时都会首先想到用于解决并发的工具( ...
- Go基础系列:import导包和初始化阶段
import导入包 搜索路径 import用于导入包: import ( "fmt" "net/http" "mypkg" ) 编译器会根据 ...
- Go基础系列:惰性数值生成器
惰性数值生成器是指在需要的时候才生成下一个数值,不需要的时候就卡在那.这和python的列表推导表达式类似.惰性生成器的好处是不会一次性将全部结果返回或放进内存,而是每次只返回一个,这样不会在某一时刻 ...
- QT 完美实现圆形按钮
QT 版本:5.6.0 官方的按钮有些普通,如果我们想要换成自己喜欢的按钮而却无从下手,那么请继续往下阅读(皮一下). 首先,可以在网络上搜索一下自己喜欢的按钮图形(或者可以自行绘制),我以下面的图形 ...
- 第一次:lesson eighty seven。
原文: A car crash. A:Is my car ready yet? B:I don't know sir,what's the number of your car? A:It's LFZ ...
- [angularjs] angularjs系列笔记(四)控制器
Scope作用域 Scope作用域是应用在HTML视图和Js控制器之间的纽带 Scope是一个对象,有可用的属性和方法 根作用域 所有的应用都有一个$rootScope,它可以作用在ng-app指令包 ...
- 【Spring】使用Spring和AMQP发送接收消息(下)
上篇讲了使用RabbitMQ发送消息,本篇则来讲接收消息.在传统JMS中有两种从队列获取信息的方式,使用JmsTemplate的同步方式以及使用消息驱动pojo的异步方式.Spring AMQP也提供 ...