前几天上REST课,因为涉及到Java的反射机制,之前看过一直没有用过,有些遗忘了,周末找了些资料来重新学习,现在总结一下,加深印象。

什么是反射机制?

参考百度百科对java反射机制的定义:

“JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。”

我们通过一些例子,更好理解反射机制。

Class类

我们知道Java是一门面向对象语言,在Java的世界里,万物皆为对象,比如我们有一个Person类:

public class Person {

}

我们创建一个Person类的实例,Person person = new Person();  那么这个person,就是Person类的实例对象。

那么既然万物都为对象,所以类也是对象。

类是什么的对象呢?类是Class类的对象,表示方式有三种:

//第一种,任何一个类都有一个隐含的静态成员变量class
Class c1 = Person.class; //第二种,已经知道该类的对象,通过getClass()获得
Class c2 = person.getClass(); //第三种,Class类的forName()方法
Class c3 = Class.forName("Person"); //这里,c1,c2,c3都是Class类的实例,我们称c1, c2 ,c3为Person类的类类型
//不难看出,c1 == c2结果是true, c2 == c3结果也是true

通过类的类类型,我们经常会用到的方法就是newInstance()方法,通过该方法可以创建该类的实例:

Person personA = new Person(); //直接new一个实例
Person personB = Person.class.newInstance(); //通过newInstance()方法获得Person的实例 //在学习JAVAEE时候,newInstance()方法我们最常见于获取数据库驱动
Class.forName("com.mysql.jdbc.Driver").newInstance(); //需要注意的是,在使用newInstance()方法的前提是该类必须要有无参构造方法

动态加载类:

编译时刻加载类称为静态加载,运行时刻加载类称为动态加载,使用new方法新建实例即为静态加载类,在编译时候就要加载全部类。这里我们举一个例子:

为了更好的区分编译和运行,我们不适用IDE工具,而使用记事本来实现这个例子:

//我们举女娲造人的例子,创建一个CreatePerson类
public class CreatePerson {
public static void main(String[] args) {
if(args[0].equalsIgnoreCase("man")) { //如果从命令行传入的参数为man 则创建Man的实例并调用say()方法
new Man().say();
}
if(args[0].equalsIgnoreCase("woman")) { //如果从命令行传入的参数为woman 则创建Woman的实例并调用say()方法
new Woman().say();
}
}
} //CreatePerson类用到了2个类,分别是Man和Woman。
//但是我们现在只创建Man类
public class Man {
public void say() {
System.out.println("I am a man !");
}
}

我们在CMD中编译CreatePerson,看看会发生什么:

提示我们找不到Woman这个类。这就是静态加载,在编译时刻需要加载全部类。那么问题来了,如果我要写一个程序,里面有100个功能,这100个功能分别由100个类实现,那么一旦缺少一个类,这整个程序是不是就不能用了。

为了解决这个问题,我们可以使用动态加载。我们把上面这个例子改一下:

//创建一个Person接口
public interface Person {
void say();
} //修改Man类,继承Person接口
public class Man implements Person{
public void say() {
System.out.println("I am a man !");
}
} //修改CreatePerson类,实现动态加载类
public class CreatePerson{
public static void main(String[] args) { try{
//动态加载类
Class c = Class.forName(args[0]);
//通过类的类类型,创建该类实例对象
Person person = (Person)c.newInstance();
person.say(); } catch(Exception e) {
e.printStackTrace();
}
}
}

这个时候,我们再进行编译:

没有报错了,那么我们继续把Man编译,再运行一下:

如果我们在命令行中输入的参数是Woman呢?

抛出ClassNotFoundException异常。因为我们并没有创建Woman类,所以如果以后需要创建Woman类实例,我们只需要新建一个Woman类,并实现Person接口就行了。

通过反射机制,获得类的信息

在Java反射机制的定义中有:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。下面是一个实例:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; public class ClassUtil {
/**
* 获取成员函数的信息
*/
public static void getClassMethodMessage(Object obj) {
Class c = obj.getClass();
//获取类的名称
//System.out.println(c.getName()); /**
*
* Method类,方法对象
*getMethods方法获得所有public的方法,包括继承而来
*getDeclaredMethods是获取该类自己的声明的方法
*/
Method[] ms = c.getMethods();
for(int i = 0; i < ms.length; i++) {
//得到方法的返回值类型的类类型
Class returnType = ms[i].getReturnType();
System.out.print(returnType.getName() + " ");
//得到方法的名称
System.out.print(ms[i].getName() + "(");
//获取参数类型
Class[] paramTypes = ms[i].getParameterTypes();
for(Class class1:paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
} } public static void getFieldMessage(Object obj) {
Class c = obj.getClass(); /**
* 成员变量也是对象
* java.lang.reflect.Field
*
*/
Field[] fs = c.getDeclaredFields();
for(Field field:fs) {
//得到成员变量类型的类类型
Class fieldType = field.getType();
String typeName = fieldType.getName();
//得到成员变量的名称
String fieldName = field.getName();
System.out.println(typeName + " " + fieldName); }
} public static void printConMessage(Object obj) {
Class c = obj.getClass();
/**
* 构造函数也是对象
*
*/
Constructor[] cs = c.getConstructors();
for (Constructor constructor : cs) {
System.out.print(constructor.getName() + "(");
//获取构造函数参数列表------>参数列表的参数类型
Class[] paramType = constructor.getParameterTypes();
for (Class class1 : paramType) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
} } public static void main(String[] args) {
String s = "hello";
getFieldMessage(s);
ClassUtil.printConMessage(s);
getClassMethodMessage(s);
}
}

方法的反射操作

可以通过方法的反射操作实现方法的调用:

import java.lang.reflect.Method;

public class MethodDemo1 {
public static void main(String[] args) {
//要获取print(int, int)
//要获取类的方法就要获取类的信息,获取类的信息就要获取类的类类型
A a1 = new A();
Class c = a1.getClass();
//2,获取方法 名称和参数列表
//getMethod获取的是public的方法
try {
Method m = c.getDeclaredMethod("print", int.class,int.class); //方法的反射操作
//a1.print(10, 20);方法的反射操作,用m来进行方法调用和前者效果一致
Object obj = m.invoke(a1, 10,20);//如果方法有返回值返回值,没有就null } catch (Exception e) { e.printStackTrace();
}
} } class A {
public void print(int a , int b) {
System.out.println(a + b);
} public void print(String a , String b) {
System.out.println(a.toUpperCase() + "," + b.toUpperCase());
}
}

以上就是我对Java反射机制的学习和理解,如果有错误,望指出,以便及时更正!谢谢!

Java反射机制——学习总结的更多相关文章

  1. JAVA反射机制—学习总结

    最近收到很多关于Java反射机制的问题留言,其实Java反射机制技术方面没有太多难点,或许是大家在学习过程中遗漏了细小知识点,导致一些问题无法彻底理解,现在我们简单的总结一下,加深印象.什么是反射机制 ...

  2. Java反射机制学习与研究

    Java反射机制:可以获取正在运行时的Java对象. 1.判断运行时对象对象所属的类. 2.判断运行时对象所具有的成员变量和方法. 3.还可以调用到private方法,改变private变量的值. S ...

  3. Java反射机制学习

    Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”. 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答 ...

  4. JAVA反射机制学习随笔

    JAVA反射机制是用于在运行时动态的获取类的信息或者方法,属性,也可以用来动态的生成类,由于所有类都是CLASS的子类,我们可以用一个CLASS类的实例来实例化各种类 例如: Class<?&g ...

  5. java反射机制学习小结

    之前一直对java的反射机制理解得很模糊,今天因为学习spring,所以花了些时间总算把它理顺了,记录一下 另外,推荐读读这篇文章,写的挺好的http://blog.csdn.net/woshixuy ...

  6. java反射机制学习笔记

    内容引用自:https://www.cnblogs.com/wkrbky/p/6201098.html https://www.cnblogs.com/xumBlog/p/8882489.html,本 ...

  7. Java 反射机制学习资料

    Java反射——引言 Java反射——Class对象 Java反射——构造函数 Java反射——字段 Java反射——方法 Java反射——Getter和Setter Java反射——私有字段和私有方 ...

  8. java反射机制学习代码

    根据 http://www.iteye.com/topic/137944 文档进行学习 代码如下: package reflectTest; import java.lang.reflect.*; i ...

  9. Java反射机制的学习

    Java反射机制是Java语言被视为准动态语言的关键性质.Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息,动态地生成此类,并调 ...

随机推荐

  1. Ambari+HDP+HDF离线安装包下载清单

    Ambari 2.7.3 Repositories OS Format URL RedHat 7 CentOS 7 Oracle Linux 7 Base URL http://public-repo ...

  2. requests + bs4 爬取豌豆荚所有应用的信息

    1.分析豌豆荚的接口的规律 - 获取所有app的接口url 2.往每一个接口发送请求,获取json数据 解析并提取想要的数据 app_data: 1.图标 app_img_url 2.名字 app_n ...

  3. (Go) 1. go环境配置

    第一步: 下载配置环境 转载: https://www.liwenzhou.com/posts/Go/go_menu/ 1.下载地址: https://golang.google.cn/dl/ 2.安 ...

  4. 如何在Linux上创建,列出和删除Docker容器

    本篇文章介绍的内容是关于在Linux机器上创建,列出和删除docker容器,下面我们来看具体的内容. 1.启动Docker容器 使用下面的命令启动新的Docker容器.这将启动一个新的容器,并为你提供 ...

  5. 跟我一起学QT_QT标准对话框_文件对话框

    标准对话框 QT的标准对话框分为以下几种 颜色对话框 文件对话框 字体对话框 输入对话框 消息对话框 进度对话框 错误信息对话框 向导对话框 文件对话框 QT中的文件对话框QFileDialog类提供 ...

  6. .NET Core 3.1之深入源码理解HealthCheck(二)

    写在前面 前文讨论了HealthCheck的理论部分,本文将讨论有关HealthCheck的应用内容. 可以监视内存.磁盘和其他物理服务器资源的使用情况来了解是否处于正常状态. 运行状况检查可以测试应 ...

  7. 从头学pytorch(十四):lenet

    卷积神经网络 在之前的文章里,对28 X 28的图像,我们是通过把它展开为长度为784的一维向量,然后送进全连接层,训练出一个分类模型.这样做主要有两个问题 图像在同一列邻近的像素在这个向量中可能相距 ...

  8. KindEditor.ready 不执行的解决方法

    问题描述 按照官网的要求,一一都设置好了,但就是没法显示富文本编辑器. 1.设置好textarea输入框 <textarea id="myEditor" name=" ...

  9. linux下文件解压缩中文乱码问题的解决

    将带中文文件名的压缩文件上传到服务器,使用unzip解压后,文件名乱码: 临时解决方法: 通过unzip行命令解压,指定字符集unzip -O CP936 xxx.zip (用GBK, GB18030 ...

  10. 除了闹过腥风血雨的fastjson,你还知道哪些Java解析JSON的利器?

    昨天下午 5 点 10 分左右,我解决掉了最后一个 bug,轻舒一口气,准备关机下班.可这个时候,老板朝我走来,脸上挂着神秘的微笑,我就知道他不怀好意.果不其然,他扔给了我一个新的需求,要我在 Jav ...