一、反射
- 定义
将类的各个组成部分封装成对象,这就是反射机制
三个步骤:source源代码阶段类加载器——Class类对象阶段创建对象——Runtime运行时阶段
2.获取class对象的方式
⑴class.forName("全类名") :将字节码文件加载进内存,返回class对象
多用于配置文件,将类名定义在配置文件中,读取文件,加载
⑵类名.class :通过类名的属性class获取
多用于参数的传递
⑶对象.getClass() :getClass方法在object类中定义着
多用于对象的获取字节码的方式
*在同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过那种方式获得的class对象都是同一个。
3. 获取功能
⑴获取成员变量们
File[] getFields() : 获取所有public修饰的成员变量
File getField(String name) :获取指定名称的public修饰 的成员变量
File[] getDeclaredFields() : 获取所有的成员变量,不考虑修饰符
File getDeclaredField(String name) :获取指定名称的成员变量,不考虑修饰符
Filed:成员变量操作
暴力反射 d.setAccessible(true)
设置值: void set(Object obj,object value)
获取值:get(Object obj)
⑵ 获取构造方法们
Constructor<?>[] getDeclaredConstructors()
Constructor<T> getDeclaredConstructor(类<?>.... parameterTypes)//(string.class,int.class)
Constructor:构造方法
创建对象 newInstance(object..initargs)//(张三,18)
如果使用空参数构造方法创建对象,操作可以简化:class对象的newInstance方法
⑶获取成员方法们
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name,类<?>... parameterTypes)
Method方法对象
执行方法,object invoke(object obj ,object...args)
获取方法名:String getName
⑷获取类名
String geiName()
4.“框架测试 ”
public class Test {
public static void main(String[] args) throws Exception {
//可以创建任意类的对象,可以执行任意方法
/*
前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法
*/
/* Person p = new Person();
p.eat();*/
/*
Student stu = new Student();
stu.sleep();*/
//1.加载配置文件
//1.1创建Properties对象
Properties pro = new Properties();
//1.2加载配置文件,转换为一个集合
//1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
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=cn.itcast.domain.Student
methodName=sleep
二、注解
1.概念: 说明程序的,给计算机看的,元数据,是对包,类,方法等元素的说明
javadoc
@注解名称
@param 参数
@return 返回值
2.作用分类
@编写文档:通过代码里标注的注解文档【生成doc文档】
@代码分析:通过代码里标注的注解对代码进行分析【使用反射】
@编译检查: 通过代码里标注的注解让编译器能够实现基本的编译检查【override】
3.JDK 预定义注解
@override 检测该注解标注的方法是否是继承父类接口的
@Deprecated 该注解标注的内容,表示已过时
@suppressWarnings 压制警告的
4.自定义注解(javap 反编译)
格式:
元注解
public @interface 注解名称{
属性列表
}
本质:注解是一个接口,该接口默认继承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation
属性:接口中可以定义的成员方法
要求:
1.属性的返回值类型(只有基本数据类型,String,枚举,注解以上类型的数组)
2.在使用的时候必须要赋值,(default 默认赋值,如果只有一个属性需要赋值且名字为VALUE,则赋值可以省略VALUE)
@MyAnno(value=12,per=Person.p1,anno2=@MyAnno2,str={'a','b'})
元注解:用于描述注解的注解
@Target:描述注解能够作用的位置
TYPE:作用于类上
METHOD:可以作用于方法上
FIELD:可以作用于成员变量上
@Retention:描述注解被保留的阶段
SOURCE
CLASS
RUNTIME:RetentionPolicy.Runtime
@Documented:描述注解是否被抽取到api文档中
@inherited:描述注解是否被子类继承
5.在程序中使用(解析)注解:获取注解中定义的属性值
.1获取注解定义的位置的对象(class,method,filed)
.2获取指定的注解
getAnnotation(class)
.3调用注解中抽象方法获取配置的属性值
@Pro(className = "cn.itcast.annotation.Demo1",methodName = "show")
public class ReflectTest {
public static void main(String[] args) throws Exception {
/*
前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法
*/
//1.解析注解
//1.1获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//2.获取上边的注解对象
//其实就是在内存中生成了一个该注解接口的子类实现对象
/*
public class ProImpl implements Pro{
public String className(){
return "cn.itcast.annotation.Demo1";
}
public String methodName(){
return "show";
}
}
*/
Pro an = reflectTestClass.getAnnotation(Pro.class);
//3.调用注解对象中定义的抽象方法,获取返回值
String className = an.className();
String methodName = an.methodName();
System.out.println(className);
System.out.println(methodName);
//3.加载该类进内存
Class cls = Class.forName(className);
//4.创建对象
Object obj = cls.newInstance();
//5.获取方法对象
Method method = cls.getMethod(methodName);
//6.执行方法
method.invoke(obj);
}
}
6.注解小案例
/*简单的测试框架
* 当主方法执行后,会自动自行被检测的的所有方法(加了Check注解的方法),判断方法是否有异常,记录到文件中去。
public class TestCheck{
//1.创建计算器对象
Calculator c=new Calculator();
//2. 获取字节码文件对象
Class cls=c.getClass();
//3.获取所有方法
Method [] methods=cls.getMethods();
int number =0;//出现异常的次数
BufferedWreiter bw=new BufferedWriter(new FileWriter("bug.txt"));
for (Method method: Methods){
//4.判断方法上是否有Check注解
if(method.isAnnotationPresent(check.class)){
//5.有,执行
try{
method.invoke();
}catch(Exception e){
//6.捕获异常
//记录到文件中
number++;
bw,wite(method.getName() +"方法出异常了");
bw.newLine();
bw.write("异常的名称"+e.getCause().getClass().getSimpleName());
bw.newLine();
bw.write("异常的原因"+e.getCause().getMessage());
bw.newLine();
}
}
bw.wrtie(“本次测试一共出现”+number+“异常”);
bw.flush();
bw.close();
}
}