反射(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反射笔记的更多相关文章

  1. java反射笔记(学习尚硅谷java基础教程)

    反射一.概述:Reflection Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性 ...

  2. Java系列笔记(2) - Java RTTI和反射机制

    目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这 ...

  3. 【设计模式】学习笔记17:代理模式之保护代理与Java反射

    本文出自   http://blog.csdn.net/shuangde800 本笔记内容: 1. Java动态代理,反射机制 2. 保护代理 3. 应用保护代理实现的约会系统 ----------- ...

  4. java反射的理解与应用(某大神博客中看到的博文,写的真的太好了,果断转载作为笔记)

    原文地址:http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html#undefined 一.什么是反射机制 简单的来说,反射机制指的是程序 ...

  5. Java开发笔记(七十八)面向对象的后门——反射

    作为一门面向对象的编程语言,Java认为一切皆是对象,每个对象都能归属于某个类,甚至每个类均可提取出一种特殊的类型,即Class类型.早在前面介绍多态的时候,就提到每个类都存在独一无二的基因,通过比较 ...

  6. Java开发笔记(七十九)利用反射技术操作私有属性

    早在介绍多态的时候,曾经提到公鸡实例的性别属性可能被篡改为雌性,不过面向对象的三大特性包含了封装.继承和多态,只要把性别属性设置为private私有级别,也不提供setSex这样的性别修改方法,那么性 ...

  7. Java开发笔记(八十)利用反射技术操作私有方法

    前面介绍了如何利用反射技术读写私有属性,不单是私有属性,就连私有方法也能通过反射技术来调用.为了演示反射的逆天功能,首先给Chicken鸡类增加下列几个私有方法,简单起见弄来了set***/get** ...

  8. JAVA学习笔记—review基本知识[反射与异常]

    JAVA学习笔记—review基本知识[反射与异常] 1.异常: 1.1异常的分类: Java会将所有的异常封装成对象,其根本父类为Throwable. Throwable有两个子类:Error 和E ...

  9. Java注解和反射笔记

    Java注解和反射笔记 1 注解 1.1 定义 Annotation是从JDK1.5开始引入的技术 作用 不是程序本身,可以对程序作出解释 可以被其他程序(编译器等)读取 格式 @注释名,可以添加一些 ...

随机推荐

  1. go builtin包

    Go builtin包提供了go预先声明的函数.变量等的文档.这些函数变量等的实现其实并不是在builtin包里,只是为了方便文档组织. 这些内置的变量.函数.类型无需引入包即可使用. 默认提供的有: ...

  2. 使用字面量,比new更加有效

    参考原文:http://www.cnblogs.com/yxf2011/archive/2012/04/01/2428225.html http://www.cnblogs.com/mushishi/ ...

  3. Spring Cloud Stream消费失败后的处理策略(一):自动重试

    之前写了几篇关于Spring Cloud Stream使用中的常见问题,比如: 如何处理消息重复消费 如何消费自己生产的消息 下面几天就集中来详细聊聊,当消息消费失败之后该如何处理的几种方式.不过不论 ...

  4. Django 系列博客(三)

    Django 系列博客(三) 前言 本篇博客介绍 django 的前后端交互及如何处理 get 请求和 post 请求. get 请求 get请求是单纯的请求一个页面资源,一般不建议进行账号信息的传输 ...

  5. Linux核心命令

    Linux核心命令 strace(查看系统调用的一个过程) 例:strace cat /test.txt netstat perf top pidstat mpstat dstat vmstat sl ...

  6. c++中的new、operator new、placement new

    一.定义 1.new new是c++中的关键字,,其行为总是一致的.它先调用operator new分配内存,然后调用构造函数初始化那段内存. new 操作符的执行过程:1. 调用operator n ...

  7. [PHP]算法-拼接最小字典序的实现

    拼接最小字典序: 给定一个字符串类型的数组strs,请找到一种拼接顺序,使得将所有字符串拼接起来组成的大字符串是所有可能性中字典顺序最小的并放回这个大字符串. 思路: 1.字典序,12345这五个数, ...

  8. sourcetree Authentication failed

    sourcetree 的 git 密码存在 mac 的 钥匙串里面, 需要在钥匙串里删除掉对应信息,再次打开就会让你重新输入密码, 问题就解决了。 参看: https://stackoverflow. ...

  9. Docker 系列六(Docker Swarm 项目).

    一.前言 随着互联网快速发展,以及微服务架构的流行,服务器的压力越来越大.上一篇介绍的 Docker Compose 项目,可以将多个容器捏合在一起,实现容器间的通信,比如 Web 项目对 DB.Ca ...

  10. Python 内置函数笔记

    其中有几个方法没怎么用过, 所以没整理到 Python内置函数 abs(a) 返回a的绝对值.该参数可以是整数或浮点数.如果参数是一个复数,则返回其大小 all(a) 如果元组.列表里面的所有元素都非 ...