Java 反射基础(上)
写在前面:
投稿作者是一位非常爱刨根问底的人,爱钻研技术,和他多次交流过,喜欢他那股不达目的誓不罢休的那股劲。今天他投稿的两篇文章讲的是java反射的基础内容,如果你的技术非常好,也懂,这次可以不用看了,主要推荐给基础的初学者和基础不牢的人看的。
在之前的文章中,有读者反馈我博客的内容有点长,如果要说长,可能是我习惯于思考,写博客的过程中会带着问题去写,解释我为什么这么想,我是怎么解决的,而不是上来直接说解决方案。可是,这样做无疑会增加篇幅,以后,我会在表达清楚的前提下尽可能减少文字描述(但不会省略代码),也算是对自己精简表达能力的锻炼。下面,直接进入正题。
本博文主要记录我学习 Java 反射(reflect)的一点心得,在了解反射之前,您应该先了解 Java 中的 Class 类,如果您不是很了解,可以查看我的另一篇博客《浅谈 Java 的 Class 类》。
我理解的 Java 反射机制
参考了许多博文,总结了以下个人观点,如您有更好的看法还望指导:
Java 反射机制在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称为 java 的反射机制。
反射机制很重要的一点就是“运行时”,其使得我们可以在程序运行时加载、探索以及使用编译期间完全未知的 .class
文件。换句话说,Java 程序可以加载一个运行时才得知名称的 .class
文件,然后获悉其完整构造,并生成其对象实体、或对其 fields(变量)设值、或调用其 methods(方法)。
不知道上面的理论您能否明白,反正刚接触反射时看的我一脸懵比,后来写了几个例子之后:哦~~原来是这个意思!如果您不明白理论没关系,建议您先往下看例子,之后再回来看相信您就能明白了。
实战演练
Step1. 编写测试类
为使得测试结果更加明显,我首先定义了一个 ParentClass
类(默认继承自 Object
类),然后定义一个继承自 ParentClass
类的 SonClass
类,如下所示。可以看到测试类中变量以及方法的访问权限不是很规范,是为了更明显得查看测试结果而故意设置的,实际项目中不提倡这么写。
FatherClass.java
public class FatherClass {
public String mFatherName;
public int mFatherAge;
public void printFatherMsg(){}
}
SonClass.java
public class SonClass extends FatherClass{
private String mSonName;
protected int mSonAge;
public String mSonBirthday;
public void printSonMsg(){
System.out.println("Son Msg - name : "
+ mSonName + "; age : " + mSonAge);
}
private void setSonName(String name){
mSonName = name;
}
private void setSonAge(int age){
mSonAge = age;
}
private int getSonAge(){
return mSonAge;
}
private String getSonName(){
return mSonName;
}
}
Step2. 使用反射获取类的信息
获取类的所有变量
/**
* 通过反射获取类的所有变量
*/
private static void printFields(){
//1.获取并输出类的名称
Class mClass = SonClass.class;
System.out.println("类的名称:" + mClass.getName());
//2.1 获取所有 public 访问权限的变量
// 包括本类声明的和从父类继承的
Field[] fields = mClass.getFields();
//2.2 获取所有本类声明的变量(不问访问权限)
//Field[] fields = mClass.getDeclaredFields();
//3. 遍历变量并输出变量信息
for (Field field :
fields) {
//获取访问权限并输出
int modifiers = field.getModifiers();
System.out.print(Modifier.toString(modifiers) + " ");
//输出变量的类型及变量名
System.out.println(field.getType().getName()
+ " " + field.getName());
}
}
以上代码注释很详细,就不再解释了。需要注意的是 2.1的 getFields()
与 2.2的 getDeclaredFields()
之间的区别(见注释),下面分别看一下两种情况下的输出。看之前强调一下 SonClass
extends FatherClass
extends Object
:
- 调用
getFields()
方法,输出SonClass
类以及其所继承的父类( 包括FatherClass
和Object
) 的public
方法。注:Object
类中没有成员变量,所以没有输出。 类的名称:obj.SonClass public java.lang.String mSonBirthday public java.lang.String mFatherName public int mFatherAge - 调用
getDeclaredFields()
, 输出SonClass
类的所有成员变量,不问访问权限。 类的名称:obj.SonClass private java.lang.String mSonName protected int mSonAge public java.lang.String mSonBirthday
获取类的所有方法信息
/**
* 通过反射获取类的所有方法
*/
private static void printMethods(){
//1.获取并输出类的名称
Class mClass = SonClass.class;
System.out.println("类的名称:" + mClass.getName());
//2.1 获取所有 public 访问权限的方法
//包括自己声明和从父类继承的
Method[] mMethods = mClass.getMethods();
//2.2 获取所有本类的的方法(不问访问权限)
//Method[] mMethods = mClass.getDeclaredMethods();
//3.遍历所有方法
for (Method method :
mMethods) {
//获取并输出方法的访问权限(Modifiers:修饰符)
int modifiers = method.getModifiers();
System.out.print(Modifier.toString(modifiers) + " ");
//获取并输出方法的返回值类型
Class returnType = method.getReturnType();
System.out.print(returnType.getName() + " "
+ method.getName() + "( ");
//获取并输出方法的所有参数
Parameter[] parameters = method.getParameters();
for (Parameter parameter:
parameters) {
System.out.print(parameter.getType().getName()
+ " " + parameter.getName() + ",");
}
//获取并输出方法抛出的异常
Class[] exceptionTypes = method.getExceptionTypes();
if (exceptionTypes.length == 0){
System.out.println(" )");
}
else {
for (Class c : exceptionTypes) {
System.out.println(" ) throws "
+ c.getName());
}
}
}
}
同获取变量信息一样,需要注意2.1与2.2的区别,下面看一下打印输出:
- 调用
getMethods()
方法 获取SonClass
类所有public
访问权限的方法,包括从父类继承的。打印信息中,printSonMsg()
方法来自SonClass
类,printFatherMsg()
来自FatherClass
类,其余方法来自 Object 类。 类的名称:obj.SonClass public void printSonMsg( ) public void printFatherMsg( ) public final void wait( ) throws java.lang.InterruptedException public final void wait( long arg0,int arg1, ) throws java.lang.InterruptedException public final native void wait( long arg0, ) throws java.lang.InterruptedException public boolean equals( java.lang.Object arg0, ) public java.lang.String toString( ) public native int hashCode( ) public final native java.lang.Class getClass( ) public final native void notify( ) public final native void notifyAll( ) - 调用
getDeclaredMethods()
方法 打印信息中,输出的都是SonClass
类的方法,不问访问权限。 类的名称:obj.SonClass private int getSonAge( ) private void setSonAge( int arg0, ) public void printSonMsg( ) private void setSonName( java.lang.String arg0, ) private java.lang.String getSonName( )
结尾
这次的内容主要是代码,文字部分在能表达清楚意思的前提下已经压缩到最少了,希望您看的开心哈!如果文中有任何不妥或错误之处,还请不吝赐教,十分感谢!
本博文演示了如何借助反射获取类的所有变量和方法,当然还有其他许多获取类信息的API(比如得到类的包名、构造函数、接口等),我就不一一列举了,使用方法都差不多。下次将向大家分享如何利用反射在运行时刻修改类成员变量和方法的访问权限,一起期待吧 :)
特别声明:本文经原作者授权转载,未经原作者允许,不得转载其他平台。
- 一个很easy的脚本--php获取服务器端的相关信息
- Kubernetes网络解决方案的比较
- OSX 上初步尝试 asp.net 5
- 一个粗心的Bug,JSON格式不规范导致AJAX错误
- weiapi2.2 HelpPage自动生成接口说明文档和接口测试功能
- C#通过WMI的wind32 的API函数实现msinfo32的本地和远程计算机的系统日志查看功能
- C#通过WMI的wind32 的API函数实现msinfo32的本地和远程计算机的系统摘要信息查看功能
- Envoy架构概览(5):负载均衡
- Envoy架构概览(6):异常检测
- Envoy架构概览(7):断路,全局限速和TLS
- Envoy架构概览(9):访问日志,MongoDB,DynamoDB,Redis
- 【前沿】TensorFlow Pytorch Keras代码实现深度学习大神Hinton NIPS2017 Capsule论文
- Linux 部署ASP.NET SQLite 应用 的坎坷之旅 附demo及源码
- 跨平台:使用OWIN 为WebAPI 宿主
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Navicat 环境测试 innodb 的默认行锁升级表锁
- Ubuntu18.04更换国内源的方法示例
- 详解ubuntu双系统启动时卡死解决办法
- 轻松掌握Git开发(二)本地仓库的基本操作
- 轻松掌握Git开发(三)版本的切换
- 轻松掌握Git开发(四)分支操作
- 一文搞定pandas的透视表
- Spring 日志输出错误字符 -e[0;39m e[2m[
- linux不支持所有命令的解决办法
- linux系列之常用运维命令整理笔录(小结)
- 轻松掌握Git开发(五)远程库的基本操作
- GitHub竟然还有这些骚操作,赶紧学起来
- leetcode之单词规律
- 内存溢出及解决方案
- 3分钟短文:Laravel控制器用法光速入门