云笔记项目-Java反射知识学习
在云笔记项目中,补充了部分反射的知识,反射这一部分基础知识非常重要,前面学习的框架Spring和MyBatis读取xml配置文件创建对象,以及JDBC加载驱动等都用了反射,但只知道有这个东西,具体不知道怎么用,大概的原理是怎么样的,现在简单的记录下
什么是反射
反射(Reflection)是Java提供的动态执行机制,可以动态加载类,动态创建对象,动态获取类信息,比如接口信息,方法信息,属性信息,构造信息等,是JDK1.4开始出现的功能。并可以通过获取到的信息动态创建对象,动态调用方法等。如果想更好的感受反射,可以从静态执行方式和动态执行方式两种去对比。
a.静态执行:Java代码通过编译以后就确定的执行次序,称为静态执行次序。比如新建一个对象Foo foo=new Foo(),然后调用对象的方法foo.test()执行,这就是静态执行,代码在编译期就知道具体的对象是什么,对象要执行的方法是什么。
b.动态执行:在运行期间才确定要创建哪个类,执行类的哪个方法。也就是编译期无法得知具体的类信息,也无法得到类中的方法信息,等具体加载类执行时才能知道。Java反射API,可以实现动态执行加载类和执行方法的功能。
反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。
为了更好理解反射,先准备两个写好的类,后面做用素材测试使用:
Foo类:
package Test; public class Foo {
//加几个属性,演示通过反射得到所有的属性
public String name;
public int age;
private int salary; //加一个构造器,演示通过反射获得构造器
// public Foo(String name) {
// super();
// this.name = name;
// } //加几个方法,演示通过反射动态调用方法
private String getPrice() {
return "100";
} public String hello() {
return "hello reflect";
}
}
Too类:
package Test; public class Too {
public String name;
public int age;
private int salary; public String Hello() {
System.out.println("Hello Too");
return "Success";
}
}
反射功能
a.动态加载类,主要有三种方法:
(1)使用Class类的forName()静态方法
作用是将类名对应的类加载到方法区,如果类名错误就抛出异常。
forName()工作原理:写好一个类,比如Foo.java类,通过编译后会生成Foo.class字节码文件,当执行Class cls=Class.forName("Foo")后,Class.forName()这个方法会首先读取Foo.class字节码文件,将其加载到方法区中。Class.forName()执行完后的返回值就是一个具体的Class类型对象,储存在堆中,其通向方法区。而cls是一个指向具体对象的引用,会储存在栈中。通过cls,可以获取Foo类的一切信息,属性和方法等。当forName()方法中的类名更改后,其加载新的类对应的字节码文件到方法区,从而实现了类的动态加载。
package Test; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner; public class Demo { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
//动态加载类
Scanner scan=new Scanner(System.in);
//得到用户输入的类名
System.out.println("请输入类名:");
String className=scan.nextLine();
//动态加载类
Class cls=Class.forName(className);
System.out.println("---------------类信息---------------");
System.out.println(cls);//输出class 包名.类名
System.out.println(cls.getName());//输出包名.类名
}
}
控制台输入Test.Foo后,输出结果如下,getName()获得的是Java内部使用的真正名称,包含包名和类名,其他还有getSimpleName()和getPackage()方法等,分别代表返回不包含包名和只包含包名的信息:
(2)直接获取某一个对象的class
Class<Date> cls = Date.class;
获取Class对象如果提前知道了类名,不一定需要实例对象,可以使用<类名>.class获取Class对象。
(3)调用某个对象的getClass()方法
StringBuilder str = new StringBuilder("123");
Class<?> cls = str.getClass();
所有类的根父类Object有一个方法 public final native Class<?> getClass() ,可以获取对象的Class对象。Class是一个泛型类,使用getClass()方法时并不知道返回的具体类是什么类型,因此返回Class<?>。问号"?"代表类型的实参,不是类型形参,其代表所有类型的父类,是一种实际的参数。
b.动态创建对象,主要有两种方法
(1)可以使用cls.newInstance()方法创建对象,相当如使用无参构造器创建了对象。
Object obj=cls.newInstance()
特点:动态创建对象;可以创建任何对象;cls对应的类必须有无参数构造器,如果没有将抛出异常,(一般符合javabean规范的类都有无参数构造器)
(2)使用cls.getConstructor()方法得到Constructor对象,然后使用Constructor.getInstance()方法获取对象,这个构造器可以传入参数,是跟第一种主要的区别。
在上述main方法中加上如下代码获取对象,注释的部分是通过带参数的构造器创建对象:
//动态创建对象
//1 使用cls.newInstance()来获取对象,使用无参数构造器
Object obj=cls.newInstance();
System.out.println("---------------对象信息---------------");
System.out.println(obj);
//2 使用cons.newInstance()获取对象,使用特定的构造器
// Constructor cons=cls.getConstructor(String.class);
// Object obj=cons.newInstance("clyang");
// System.out.println(obj);
同样控制台使用Test.Foo类进行测试,输出结果为:
c.反射可以查找类中的方法
可以返回类中声明的全部方法信息,eclipse开发工具中,当得到一个对象后,可以通过输入点,就可以列出对象里所有的方法,其实也是用的反射机制。如Foo foo=new Foo(),当输入foo.时,"foo."后面会列出一堆方法和属性信息,其实就是在点了后,java获得了foo,然后获取到了类名,通过java反射得到这个类下的方法和属性,然后将其输出到界面,列出来展示给开发人员。
(1)getDeclaredMethods()
在上述main方法中加上如下代码获取所有声明的方法,使用getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法:
//动态检查类中声明的方法信息
Method[] method=cls.getDeclaredMethods();//返回所有private,public,protected等修饰的方法
System.out.println("---------------方法信息---------------");
for(Method m:method) {
System.out.println(m);//输出方法信息
}
同样使用Test.Foo类进行测试,控制台输出结果为:
(2)getMethods()
方法返回某个类的所有公用(public)方法,包括其继承类的公用方法.
(3)getMethod(String name,Class<?>... parameterTypes)
方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
d.动态执行方法
(1) 需要在动态创建对象后再动态执行方法
Object obj=cls.newInstance();//动态创建对象
(2)找到对象对应的类型方法信息,方法信息在类上查找
method m=cls.getDeclaredMethod(name);//找到对象对应类cls中的方法信息
(3)接下来就可以调用方法了
m.invoke(obj);//字面意思是,m方法调用了obj,个人猜测是m方法唤醒了obj,然后底层调用了obj.m()方法。
//动态调用方法
System.out.println("请输入方法名");
String methodName=scan.nextLine();
Method m=cls.getDeclaredMethod(methodName);
//如果想让private方法也能被调用,需要加上
System.out.println("---------------动态执行方法---------------");
m.setAccessible(true);
Object o=m.invoke(obj);
System.out.println(o);
同样使用Test.Foo类进行测试,测试执行hello方法,控制台输出结果为:
e.反射也可以查找类中的属性
(1)getDeclaredFields()
可以返回类所有已声明的成员变量,但不能得到其父类的成员变量,Field[] field=cls.getDeclaredField()。
//返回类的所有成员变量
Field[] fields=cls.getDeclaredFields();
System.out.println("---------------属性信息---------------");
for(Field f:fields) {
System.out.println(f);
}
同样使用Test.Foo类进行测试,控制台输出结果可以看出私有的成员变量也可以得到:
(2)getField
访问共有的成员变量。
f.反射可以获取类中的构造器
可以获取类中所有声明的构造器,Constructor[] constructor=cls.getDeclaredConstructors();
//返回类中声明的构造器
Constructor[] constructor=cls.getDeclaredConstructors();
System.out.println("---------------构造器信息---------------");
for(Constructor c:constructor) {
System.out.println(c);
}
同样控制台使用Test.Foo类进行测试,输出结果为:
发现输出的是默认构造器方法,因为在Foo类中,没有写构造器,因此创建对象时默认调用了无参数构造器。
g.反射的用途
(1)Eclipse快捷菜单使用了反射,利用反射发现类的属性和方法
(2)Spring利用了反射:动态加载类,动态创建bean,动态注入属性,包括私有属性注入,动态解析注解
(3)Mybatis利用了反射,查询时候,动态将查询结果利用反射注入到bean并返回
(4)Junit使用了反射
(5)注解的解析使用了反射
(6)Servlet调用使用了反射
总结
反射内容非常复杂,现在只是学习如何基本的使用,具体底层的实现,invoke方法的原理,还需要后续学习补充。
参考博文:https://www.cnblogs.com/coprince/p/8603492.html
参考书籍:《Java编程的逻辑》
云笔记项目-Java反射知识学习的更多相关文章
- JAVA反射机制—学习总结
最近收到很多关于Java反射机制的问题留言,其实Java反射机制技术方面没有太多难点,或许是大家在学习过程中遗漏了细小知识点,导致一些问题无法彻底理解,现在我们简单的总结一下,加深印象.什么是反射机制 ...
- Java底层知识学习:Bytecode and JMM
最近在跟着耗子哥的程序员练级指南学习Java底层知识,结合<深入理解Java虚拟机>这本书在看,写笔记,看资料,成长中…… 目前看完了第二章JMM和各内存区OOM的情况 一篇图文并茂介绍字 ...
- java反射知识相关的文章
整理的反射相关的文章: (1).通俗理解反射(知乎):学习java应该如何理解反射? (2).关于反射比较深入的博文地址:深入解析Java反射(1) - 基础 贴出我反射调用代码:(craw,dept ...
- Java反射机制——学习总结
前几天上REST课,因为涉及到Java的反射机制,之前看过一直没有用过,有些遗忘了,周末找了些资料来重新学习,现在总结一下,加深印象. 什么是反射机制? 参考百度百科对java反射机制的定义: “JA ...
- Java基础知识学习(九)
GUI开发 先前用Java编写GUI程序,是使用抽象窗口工具包AWT(Abstract Window Toolkit).现在多用Swing.Swing可以看作是AWT的改良版,而不是代替AWT,是对A ...
- Java反射机制学习与研究
Java反射机制:可以获取正在运行时的Java对象. 1.判断运行时对象对象所属的类. 2.判断运行时对象所具有的成员变量和方法. 3.还可以调用到private方法,改变private变量的值. S ...
- Java 反射机制学习资料
Java反射——引言 Java反射——Class对象 Java反射——构造函数 Java反射——字段 Java反射——方法 Java反射——Getter和Setter Java反射——私有字段和私有方 ...
- java反射知识
java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称 ...
- Java反射机制学习
Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”. 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答 ...
随机推荐
- 学习笔记TF023:下载、缓存、属性字典、惰性属性、覆盖数据流图、资源
确保目录结构存在.每次创建文件,确保父目录已经存在.确保指定路径全部或部分目录已经存在.创建沿指定路径上不存在目录. 下载函数,如果文件名未指定,从URL解析.下载文件,返回本地文件系统文件名.如果文 ...
- [c#]_ELVE_Message多功能用法
1. 当要显示如图3个按钮时,并要获得单击不同按钮的进行不同的相应时,可以在MessageBoxButtons后面添加一个.(应该英文的点,此处为了醒目,用中文代替)可以看到提示框下方需要几个按 ...
- python, ImageFont
ImageFont模块定义了相同名称的类,即ImageFont类.这个类的实例存储bitmap字体,用于ImageDraw类的text()方法. PIL可以配置是否支持TrueType和OpenTyp ...
- scoping作用域,anonymous function匿名函数,built-in functions内置函数
作用域练习1 def test1(): print('in the test1') def test(): print('in the test') return test1 res = test() ...
- Python装饰器的调用过程
在Python学习的过程中,装饰器是比较难理解的一个应用.本人也在学习期间也遇到很多坑,现将装饰器的基本调用过程总结一下. 首先,装饰器用到了“闭包”,而“闭包”是学习装饰器的基础,所以在讲装饰器之前 ...
- [UE4]Text Box
Text Box:文本输入控件. 一.新建一个名为testTextBox的UserWidget,添加一个名为“EditableTextBox_0”的TextBox到默认容器Canvas Panel 二 ...
- [java,2017-05-04] 合并word文档
import java.io.File; import com.aspose.words.Document; import com.aspose.words.ImportFormatMode; pub ...
- web socket client
<!DOCTYPE HTML> <html> <head> <title>My WebSocket</title> </head> ...
- spring 生命周期最详解
转载. https://blog.csdn.net/qq_23473123/article/details/76610052 目的 在大三开始学习spring时,老师就说spring bean周期非常 ...
- Linux环境变量设置/etc/profile、/etc/bashrc、~/.profile、~/.bashrc区别
登入系统读取步骤: 当登入系统时候获得一个shell进程时,其读取环境设定档有三步 : 1.首先读入的是全局环境变量设定档/etc/profile,然后根据其内容读取额外的设定的文档,如 /etc/p ...