Java反射机制
2021/7/10 9:08:31
本文主要是介绍Java反射机制,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
反射
第一部分 Junit单元测试
1.1、测试分类
- 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
- 白盒测试:需要写代码。关注程序具体的执行流程。
1.2、Junit使用:白盒测试
-
步骤:
-
定义一个测试类(测试用例)
-
建议:
a. 测试类名:被测试的类名Test CalculatorTest
b. 包名:xxx.xxx.xx.test cn.itcast.test
-
-
定义测试方法:可独立运行
-
建议:
a. 方法名:test测试的方法名 testAdd()
b. 返回值:void
c. 参数列表:空参
-
-
给方法加 @Test
-
导入 junit 依赖环境
-
-
判定结果:
-
红色:失败
-
绿色:成功
-
一般我们会使用断言操作来处理结果:
Assert.assertEquals(期望的结果,运算的结果)
-
第二部分 反射(重点!)
2.1、Java代码在计算机中经历的三个阶段:
2.2、反射与框架
- 框架:半成品软件;可在框架的基础上进行软件开发,极大地简化代码。
- 反射:将类的各个组成部分封装为其它对象;是框架设计的灵魂。
- 反射的好处:
- 可以在程序运行过程中,操作这些对象。
- 解耦合,提高程序的可扩展性!
2.3、获取Class类对象的方式
-
java.lang.Class
extends java.lang.Object -
Class Class
:Class类的实例表示正在运行的Java应用程序中的类和接口。 -
枚举是一种类,注解是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该
Class
对象。基本的 Java 类型(boolean
、byte
、char
、short
、int
、long
、float
和double
)和关键字void
也表示为Class
对象。 -
Class
没有公共构造方法。Class
对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass
方法自动构造的。 -
类型参数:
T
- 由此Class
对象建模的类的类型。例如,
String.class
的类型是Class<String>
。如果将被建模的类未知,则使用Class<?>
。
-
1. Class.forName("全类名"): 将字节码文件加载进内存,返回Class对象 <"全类名"即是:包名.类名> 多用于配置文件,将类名定义在配置文件中,读取文件,加载类。 2. 类名.class:通过类名的属性class获取 多用于参数的传递 3. 对象.getClass():getClass()方法在Object类中定义着,返回此Object运行时类。 多用于对象获取字节码的方式 注意: 同一个字节码文件(*.class)在一次程序运行过程中只会被加载一次,不论通过哪种方式获取的Class对象都是同一个。
public class ReflectDemo1{ public static void main(String[] args) throws ClassNotFoundException { //1. Class.forName("全类名") 全类名:包名.类名。 Class cls1 = Class.forName("day13.reflection.demo1.Person"); System.out.println(cls1); //2. 类名.class Class<Person> cls2 = Person.class; System.out.println(cls2); //3. 对象.getClass() Person p = new Person(); Class<? extends Person> cls3 = p.getClass(); System.out.println(cls3); //相同字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的Class对象都是同一个! System.out.println(cls1 == cls2); //true System.out.println(cls1 == cls3); //true } }
2.4 Class常用方法:
-
获取功能:
①获取成员变量:
Field[] getFields(); 获取所有public修饰的成员变量 (所有public) Field getField(String name); 获取指定名称的public修饰的成员变量 (单个) Field[] getDeclaredFields(); 获取所有的成员变量,不考虑修饰符 (所有) Field getDeclaredField(String name); 获取指定名称的成员变量 (单个)
import java.lang.reflect.Field; public class ReflectDemo2 { public static void main(String[] args) throws Exception { //获取Class对象 Class cls = Person.class; //1.Field[] getFields(); 获取所有public修饰的成员变量 Field[] fields = cls.getFields(); for(Field f : fields){ System.out.println(f); } System.out.println("-----------------------"); /* Field getField(String name); 获取指定名称的public修饰的成员变量 操作:<Field类中的两个方法:> ①设置值:void set(Object obj,Object value) ②获取值:Object get(Object obj) ③忽略访问权限修饰符的安全检查: setAccessible(true); 暴力反射-->解决访问私有属性时抛出的IllegalAccessException异常! 访问私有属性/方法时,均可使用暴力反射! */ Field a = cls.getField("a"); Person p = new Person(); //获取成员变量a的值 Object value = a.get(p); System.out.println(value); //设置a的值 a.set(p,"Basketball"); System.out.println(p); System.out.println("========================="); //Field[] getDeclaredFields(); 获取所有的成员变量,不考虑修饰符 Field[] declaredFields = cls.getDeclaredFields(); for(Field f : declaredFields){ System.out.println(f); } //Field getDeclaredField(String name); 获取指定名称的成员变量 Field d = cls.getDeclaredField("d"); //忽略访问权限修饰符的安全检查 d.setAccessible(true); //暴力反射-->解决访问私有属性时出现的IllegalAccessException! //获取私有成员变量d的值 System.out.println(d.get(p)); } }
②获取构造方法:
Constructor<?>[] getConstructors(); Constructor<T> getConstructor(Class<?>... parameterTypes); Constructor<?>[] getDeclaredConstructors(); Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes); java.lang.reflect.Constructor类: public T newInstance(Object... initargs); 用于创建有参对象 java.lang.Class类: public T newInstance(); 创建由此类对象表示的类的新实例(用于无参构造的创建) public ClassLoader getClassLoader(); 返回该类的类加载器
import java.lang.reflect.Constructor; public class ReflectDemo3 { public static void main(String[] args) throws Exception { //获取Class类对象 Class cls = Person.class; //Constructor<T> getConstructor(Class<?>... parameterTypes); Constructor constructor = cls.getConstructor(String.class,int.class); //创建对象 Object obj = constructor.newInstance("杜兰特",35); //System.out.println(obj.getClass()); //Object类中的getClass():返回此Object的运行时类。 System.out.println(obj); System.out.println("-----------------------------"); //创建对象:无参 Constructor constructor1 = cls.getConstructor(); Object obj1 = constructor1.newInstance(); System.out.println(obj1); //Class类中的 public T newInstance(); 创建由此类对象表示的类的新实例 Object o = cls.newInstance(); System.out.println(o); } }
③获取成员方法:
Method[] getMethods(); Method getMethod(String name,Class<?>... parameterTypes); Method[] getDeclaredMethods(); Method getDeclareMethod(String name,Class<?>... parameterTypes); java.lang.reflect.Method类: public Object invoke(Object obj,Object... args); 对带有指定参数的指定对象调用由此Method对象表示的底层方法(执行方法) public String getName(); 以 String 形式返回此 Method 对象表示的方法名称。
import java.lang.reflect.Method; public class ReflectDemo4 { public static void main(String[] args) throws Exception { //获取Class类对象 Class cls = Class.forName("day13.reflection.demo1.Person"); Method eat_method = cls.getMethod("eat"); System.out.println(eat_method); Person p = new Person(); //执行方法 eat_method.invoke(p); Method eat = cls.getMethod("eat", String.class); //执行方法 eat.invoke(p,"土豆"); System.out.println("==============================="); //获取所有public修饰的方法 Method[] methods = cls.getMethods(); for (Method method : methods) { System.out.println(method); String name = method.getName(); //获取方法名称 getName(); System.out.println(name); //method.setAccessible(true); //暴力反射 } //获取类名:String getName() String className = cls.getName(); System.out.println(className); } }
④获取类名
public String getName(); 获取类名
2.5、练习:配置文件+反射
Class类: public ClassLoader getClassLoader();返回该类的类加载器 ClassLoader抽象类: public InputStream getResourceAsStream(String name);返回用于读取指定资源的输入流 Properties集合类: java.util.Properties extends java.util.Hashtable<K,V> implements Map<K,V> public void load(InputStream inStream);从输入字节流读取属性列表(键值对) public String getProperty(String key);用指定的键在此属性列表中搜索属性
import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties; /* 需求: 写一个“框架”,不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法。 实现: 1.配置文件 2.反射 步骤: 1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中 2.在程序中加载读取配置文件 3.使用反射技术来加载类文件进内存 4.创建对象 5.执行方法 */ public class ReflectTest { /* 前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法。 */ public static void main(String[] args) throws Exception { //1.创建Properties对象 Properties pro = new Properties(); //2.通过类加载器获取配置文件 ClassLoader cl = ReflectTest.class.getClassLoader(); //配置文件要放在src路径下面!否则出现NullPointException InputStream is = cl.getResourceAsStream("pro.properties"); //3.加载配置文件 pro.load(is); //4.获取配置文件中定义的数据 String className = pro.getProperty("className"); String methodName = pro.getProperty("methodName"); //5.加载该类进内存 Class cls = Class.forName(className); //6.创建对象 Object o = cls.newInstance(); //7.执行方法 Method method = cls.getMethod(methodName); method.invoke(o); } }
第三部分 注解
3.1、注解与注释?
- 注解:说明程序,给计算机看的。
- 注释:用文字描述程序,给程序员看的。
3.2、定义与描述
注解(Annotation):也叫元数据。一种代码级别的说明,JDK1.5及以后版本引入的新特性,与类、接口、枚举同属一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明、注释。
概念描述:
- JDK1.5之后的新特性
- 说明程序的
- 使用注解:@注解名称
java.lang.annotation.Interface Annotation: 所有 annotation 类型都要扩展的公共接口。
3.3、作用分类
①编写文档:通过代码里标识的注解生成文档【生成doc文档】
②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
③编译检查:通过代码库标识的注解让编译器能够实现基本的编译检查【Override】
3.4、JDK内置注解
- @Override:检测被该注解标注的方法是否继承自父类/接口
- @Deprecated:该注解标注的内容,表示已过时
- @SuppressWarnings:压制警告!
3.5、自定义注解?
这篇关于Java反射机制的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26消息中间件源码剖析教程
- 2024-11-26JAVA语音识别项目资料的收集与应用
- 2024-11-26Java语音识别项目资料:入门级教程与实战指南
- 2024-11-26SpringAI:Java 开发的智能新利器
- 2024-11-26Java云原生资料:新手入门教程与实战指南
- 2024-11-26JAVA云原生资料入门教程
- 2024-11-26Mybatis官方生成器资料详解与应用教程
- 2024-11-26Mybatis一级缓存资料详解与实战教程
- 2024-11-26Mybatis一级缓存资料详解:新手快速入门
- 2024-11-26SpringBoot3+JDK17搭建后端资料详尽教程