反射基础
1.反射定义
所谓反射,其实相当于类照镜子,是一种自省机制;可以使得程序在运行期间动态获取一个类中的成分;在类加载时,任何一个Java类都存在一个java.lang.Class的对象;反射即将类中的成分反射成为对应的类型(属性,方法,构造器,注解等)对象。
2.获取Class对象
//加载一个 指定的类并获取该类的Class对象
//类路径
Class clazz = Class.forName("User");
//类名
clazz = User.class;
//对象
clazz = new User().getClass();
3.获取Class中的属性
//1.通过反射获取类中的成分-属性
//获取由public修饰的属性
Field[] fields = clazz.getFields();
//获取所有的属性,忽略访问修饰符
Field[] field = clazz.getDeclaredFields();
for(Field f:field){
System.out.println(f.getModifiers()+"---"+f.getType()+"---"+f.getName());
//修改属性可见性
// f.setAccessible(true);
}
//获取类中指定的属性名的Field对象
Field f = clazz.getDeclaredField("score");
f.setAccessible(true);
//创建该类型的对象
Object obj = clazz.newInstance();
f.set(obj,158);
double d = f.getDouble(obj);
System.out.println(d);
4.获取Class中的方法
try {
Class clazz = Class.forName("User");
Object obj = clazz.newInstance();
//获取类中的方法
Method[] ms = clazz.getDeclaredMethods();
for (Method method:ms) {
System.out.println(method);
}
//根据方法名和方法中的参数类型,获取一个方法对象
Method m = clazz.getMethod("showInfo", String.class, int.class);
//执行方法
Object returnVal = m.invoke(obj, "aa", 10);
System.out.println(returnVal);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
5.获取Class中的构造器
//加载类(Cat为一个实体类)
Class clazz = Cat.class;
// Object obj = clazz.newInstance();
//获取所有的public构造器
Constructor[] constructors = clazz.getConstructors();
for(Constructor c:constructors){
System.out.println(c);
}
//获取指定的构造器
Constructor c = clazz.getConstructor(int.class);
//执行构造器的初始化方法,创建对象
Object obj = c.newInstance(10);
System.out.println(obj);
6.获取Class中的注解
//Mapper注解
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.TYPE,
ElementType.METHOD,
ElementType.FIELD
})
public @interface Mapper {
}
//Table注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
String value();
String schema();
}
@Mapper
@Table(value = "tb_blog",schema = "test")
public class Blog{
private int bid;
private String title;
private String content;
private String[] tipes;
private Timestamp time;
@Mapper
public void setBid(int bid) {
this.bid = bid;
}
public String[] getTipes() {
return tipes;
}
public void setTipes(String[] tipes) {
this.tipes = tipes;
}
}
public class TestAnnotations {
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
Class<Blog> clz = Blog.class;
//获取类上的注解
Annotation[] annos = clz.getAnnotations();
for(Annotation a:annos){
System.out.println(a);
}
//获取其中一个注解
Table table = clz.getAnnotation(Table.class);
System.out.println(table.schema());
//获取指定的Method对象
Method m = clz.getMethod("setBid", int.class);
//获取方法上指定类型的注解
Mapper mapper = m.getAnnotation(Mapper.class);
//判断方法对象上是否存在指定类型的注解
System.out.println(m.isAnnotationPresent(Mapper.class));
//获取指定名称的属性对象(全局变量)
Field f = clz.getDeclaredField("bid");
//判断属性上存在指定的注释
System.out.println(f.isAnnotationPresent(Mapper.class));
}
}
反射+注解模拟测试框架(Junit)
注解类:
package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author bxwl
* @create 2020-07-27 16:22
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}
测试实体类:
package com.example;
import com.softeem.day43.User;
import com.softeem.day43.reglect2.Blog;
/**
* @author bxwl
* @create 2020-07-27 16:16
*/
public class UserTest {
@Test
public void testInsert(){
User u = null;
System.out.println(u.getUserName());
}
@Test
public void testQuery(){
Blog b = new Blog();
b.setTipes(new String[]{"技术","java","多线程"});
String[] tips = b.getTipes();
System.out.println(tips[3]);
}
@Test
public void TestDivide(){
System.out.println(10/0);
}
@Test
public void TestAdd(){
System.out.println(2+2);
}
}
package com.example;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
/**
* @author bxwl
* @create 2020-07-27 16:26
*/
public class MyJunit {
public static void main(String[] args) {
BufferedWriter bw = null;
//记录方法总数
int methodCount = 0;
//记录错误方法总数
int expCount = 0;
try {
//基于文件的输出缓冲流用于存储生成的错误信息
bw = new BufferedWriter(new FileWriter("D:\\新建文件夹\\java\\test\\log.txt"));
//获取类的Class对象
Class<UserTest> clz = UserTest.class;
//创建目标类型的实例对象
UserTest obj = clz.newInstance();
Method[] methods = clz.getMethods();
//获取测试方法总数
for(Method m:methods){
if(m.isAnnotationPresent(Test.class)) {
methodCount++;
}
}
bw.write("测试方法总数:"+methodCount);
bw.newLine();
bw.write("---------------------");
bw.newLine();
for(Method method:methods){
try {
//如果方法上面包含了Test注解则作为测试方法进行测试
if(method.isAnnotationPresent(Test.class)){
method.invoke(obj);
}
} catch (Exception e) {
//异常方法计数器递增
expCount++;
bw.write(method.getName()+"出现异常!");
bw.newLine();
bw.write("类型:"+e.getCause().getClass());
bw.newLine();
bw.write("原因:"+e.getCause().getMessage());
bw.newLine();
}
}
bw.write("-------------------------------");
bw.newLine();
bw.write("已测试方法数:"+methodCount+",其中异常方法:"+expCount);
bw.flush();
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(bw != null)bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
生成的测试日志:
总结
1.优缺点:
优点:反射提高了Java程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提前硬编码目标类;反射是其它一些常用语言,如C、C++、Fortran 或者Pascal等都不具备的。
缺点:效率低,反射执行所需要的时间长。
2.应用场景
(1)逆向代码 ,如反编译
(2)与注解相结合的框架
(3) 动态生成类框架
(4)单纯的反射机制应用框架