首页 / JAVA / Java笔记(14)-反射与注解
Java笔记(14)-反射与注解
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java笔记(14)-反射与注解,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6195字,纯文字阅读大概需要9分钟。
内容图文
![Java笔记(14)-反射与注解](/upload/InfoBanner/zyjiaocheng/741/6fb21d80773348edb9554d783bf577f0.jpg)
- Junit单元测试
1. Junit白盒测试
2. 使用步骤:
a. 定义一个测试类(测试用例)
建议:测试类名:被测试类名+Test -- CaculatorTest
包名:xxx.xxx.xx.test
b. 定义测试方法:可以独立运行
建议:
方法名:test+测试的方法名 -- testAdd()
返回值:void
参数列表:空参
c. 给方法加上注解@Test
d. 导入junit依赖包
3. 判定结果:
不看程序输出,而使用断言Assert操作来处理结果
判定期望是否与程序结果一致
4. 当测试带有IO操作的程序时,时常需要申请资源,释放资源
建议:
定义个init()方法,用于所有测试的资源申请
在init()方法前加注解@Before
定义个close()方法,用于所有测试的资源释放
在close()方法前加注解@After -- 即使测试时抛出异常,close方法仍然会执行
- 反射
1. 反射是框架设计的灵魂
-- 框架:半成品软件。可以在框架的基础上进行软件开发
-- 反射:将类的各个组成部分封装为其他对象。
2. Java程序执行的三个阶段:
1. Source源代码阶段:由源代码 --> class字节码
2. 通过类加载器ClassLoader加载class文件
3. Class类对象阶段:
由class文件 --> Class类对象{
成员变量:Field[] fields
构造方法:Constructor[] cons
成员方法:Method[] methods
}
3. Runtime阶段:创建对象加载到内存中
3. 将成员变量封装为Field对象,将构造方法封装为Constructor对象,将成员方法封装为Method对象,这就指的是反射。
4. 作用:
1. 可以在程序的运行过程中操作这些对象 -- 代码提示
2. 可以解耦,提高程序可扩展性
- 获取Class对象
1. 在第一个阶段时:
Class.forName("全类名<包路径+'.'+类名>");//将字节码文件加载仅内存,返回Class对象
多用于配置文件,将类名定义在配置文件中。读取文件加载类
2. 在第二个阶段:
类名.class;//导入类定义文件后,通过类名的属性class来获取
多用于参数的传递
3. 在第三个阶段:
对象.getClass();//创建对象后,通过Object类中定义的成员方法返回其Class对象
多用于对象的方式获取字节码对象
- 使用Class对象
1. 获取功能:
a. 获取成员变量
1. Field[] getFields() //只能获取所有public修饰的成员变量
2. Field getField(String name) //只能获取指定名称的public修饰的成员变量
3. Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
4. Field getDeclaredField(String name)
b. 获取构造方法们
1. Constructor<?>[] getConstructors()
2. Constructor<T> getConstructor(类<?>... parameterTypes)
3. Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
4. Constructor<?>[] getDeclaredConstructors()
c. 获取成员方法们:
1. Method[] getMethods()
2. Method getMethod(String name, 类<?>... parameterTypes)
3. Method[] getDeclaredMethods()
4. Method getDeclaredMethod(String name, 类<?>... parameterTypes)
d. 获取全类名
1. String getName()
2. String getPackage()
2. Field对象成员方法:
a. 获取成员变量的值
1. Field f = personClass.getFeild("变量名<a>");
2. Person p = new Person();
3. Object value = f.get(p);//获取p对象中的成员变量a的值
b. 设置成员变量值
4. f.set(对象名, 成员变量a要设置的值);//给指定对象的成员变量a设置值
3. 暴力反射
由于getDeclaredField成员方法可以获取私有成员变量
但是,直接对私有成员变量使用get/set方法时,会抛出异常,提示非法权限
因此,需要忽略权限设置,使用成员方法setAccessible忽略
f.setAccessible(true);
对于成员方法和构造方法对象中同样有该成员方法
4. Constructor对象成员方法:
a. 创建对象:
T newInstance(Object ... initargs);//参数传构造对象的参数,如果获取到的是有参构造则传正确参数
例如:
Constructor cons = personClass.getConstructor(String.class, int.class);//获取指定参数列表的构造函数
Object p = cons.newInstance("nameXXX",12);//通过传入参数创建对象
5. Method对象成员方法:
a. 执行方法:
Object invoke(Object obj, Object... args);//使用指定对象obj执行该方法,且方法的参数为参数列表args
//空参方法直接传入obj即可
例如:
Method eat = personClass.getMethod("eat");
Person p = new Person();
eat.invoke(p);//空参的eat方法
Method eat2 = personClass.getMethod("eat", String.class);
eat2.invoke(p,"args");//带参数的eat方法
b. 获取方法名称:
String getName()
例如:
eat.getName();//返回"eat"
- 实现一个小框架
1. 实现步骤:配置文件 --> 反射
a. 将需要创建类型的全类名和需要执行的方法定义在一个配置文件中
b. 在程序中加载读取配置文件
c. 利用反射技术加载类文件进内存
d. 创建类对象
e. 执行方法
2. 例如:
psvm{
//1. 加载配置文件
//1.1 创建Properties对象
Properties pro = new Properties();
//1.2 加载配置文件,转换为集合
//1.2.1 首先获取本文件的类加载器
ClassLoader cld = ReflectTest.class.getClassLoader();
//1.2.2 由本文件的类加载器可以加载该类的目录下的文件,因此由该类加载器来加载配置文件
//加载文件后返回该文件的字节流
InputStream is = cld.getResourceAsStream("pro.properties");
//1.3 加载配置文件
pro.load(is);
//2. 获取配置文件中的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//3. 加载该类进内存
Class cls = Class.forName(className);
//4. 创建对象
Object obj = cls.newInstance();
//5. 获取方法对象
Method method = cls.getMethod(methodName);
//6. 执行方法
method.invoke(obj);
}
配置文件pro.properties
className=xx.xx.Person
methodName=eat
- 注解
1. JDK 1.5+一种代码级别的说明。声明在包,类,字段,方法,局部变量,方法参数等前面,用来说明
2. 作用:
编写文档:通过代码内标识的注解生成文档<API文档> -- 使用javadoc命令
代码分析:通过注解对代码进行分析 -- 使用反射抽取注解
编译检查:例如<@Override>
3. 预定义注解:
@Override:检测被该注解标注的方法是否继承自父类
@Deprecated:该注解标注的内容表示已经过时 -- 用于兼容低版本
@SuppressWarnings:压制警告 -- @SuppressWarnings("all")压制所有警告
4. 自定义注解:
a. 格式:
元注解
public @interface 自定义注解名{
}
b. 本质:
注解本质上是一个接口
pubic interface 注解名 extends Annotation {}
c. 属性:注解中的成员变量和方法
1. 属性的返回值类型:
基本数据类型/String/枚举/注解/以上类型的数组
2. 定义了属性后,在使用时需要给属性赋值
-- 也可以在定义时标注默认值,使用default关键字
-- String name() default "testName";
-- 如果只有一个属性需要复制,且属性名为value,则在使用时可以不标注属性名
public @interface SuppressWarnings{
String[] value();
}
在使用时直接标注@SuppressWarnings("all")
完整为@SuppressWarnings(value = "all")
多个值的使用逗号分隔
d. 元注解:用于描述注解的注解
@Target:描述注解能够作用的位置
ElementType取值:
TYPE:表示可以作用于类上
METHOD:表示可以作用与方法上
FIELD:表示可以作用与成员变量上
@Retention:描述注解被保留的阶段 -- Java代码的三个阶段
RetentionPolicy取值:
SOURCE:表示注解不会保留到class字节码中
CLASS:表示注解会保留到class字节码文件中,不会被JVM读取
RUNTIME:表示注解会保留到class字节码文件中,并被JVM读取
@Documented:描述注解是否被抽取到API文档中
@Inherited:描述该注解是否被子类继承
5. 获取注解属性的值
a. 获取注解定义位置的对象 -- 即Class,Method,Field对象,它们中都有成员方法getAnnotation
b. 通过对象成员方法getAnnotation获取指定注解对象
c. 通过注解对象调用成员方法获取属性值
内容总结
以上是互联网集市为您收集整理的Java笔记(14)-反射与注解全部内容,希望文章能够帮你解决Java笔记(14)-反射与注解所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。