反射和注解
反射是Java被视为动态语言的关键,反射机制允许程序在执行期借助Reflection API取得任何类的信息;
一个类在内存中只有一个class对象
一个类被加载后,类的整个结构都会被封装在class对象中。
对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个结构的有关信息。
- Class 本身也是一个类
- Class 对象只能由系统建立对象
- 一个加载的类在JVM中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.classs文件
- 每个类的实例都会记得自己是由哪个Class实例是由哪个Class实例所生成的
- 通过Class可以完成地得到一个类中的所有被加载的结构
获取Class类的实例
通过类的class属性获取,该方法最为安全可靠,程序性能最高
- Class class = Person.class;
已知某个类的实例,调用该实例的getClass方法获取Class对象
- Class class =person.getClass();
已知一个类的全类名,且该类在类的路径下,可通过Class类的静态方法forName获取,可能抛出ClassNotFoundException
- Class class =Class.forName(“com.mysql.jdbc.Driver”)
反射动态执行过程
//获得Class对象
Class c1 = Class.forName("com.user");
//构造一个对象
User user = (User) c1.newInstance();
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstrutor(String.class,int.class,int.class);
User user =(User) constructor.newInstance("ysh",1,18);
//通过反射调用普通方法 getDeclared获取全部的包括私有方法
//第一个是方法名,第二个是方法参数
Method setName = c1.getDeclaredMethod("setname",String.class);
//激活执行方法,第一个参数是执行对象,第二个是方法参数
setName.invoke(user,"ysh");
//通过反射操作属性
Field name = c1.getDeclaredField("name");
//不能操作私有属性,我们需要关闭程序的安全检查
name.setAccessible(true);
name.set(user,"ysh");
junit加入断言
Assert.assertEquals(40,result);//第一个参数是预测结果,第二个是实际结果
jdk内置注解
- Override :限定重写父类方法,该注解只能用于方法
- Deprecated :用于表示所修饰的元素(类,方法,构造器,属性等)已过时,通常是因为所修饰的结构危险或存在更好的选择
- SuppressWarnings :抑制编译器警告
自定义注解
public @interface MyAnnotation{
//这个value看上去是无参数方法,实际是理解是一个成员变量,成员变量的类型和成员变量的名字
//无参数方法的类型:基本数据类型,string ,枚举,注解类型,也可以是以上类型的数组
//如果只有一个成员变量叫value
String[] values();
String value() default "abc"; //给默认初始值
}
注解的使用:
- 使用注解的话,如果你定义了配置参数,使用时必须给赋值操作
- 如果只有一个参数,并且这个参数的名字为value的话,那么value=可以省略不写
- 如果你给配置参数设置默认的值了,那么使用的时候无需传值
- 一个注解的内部是可以不定义配置参数的 内部没有定义配置参数的注解可以叫做标记,内部定义配置参数的注解叫做元数据
//@MyAnnotation(value={"abc","def","ysh"})
@MyAnnotation({"abc","def","ysh"})
public class Perple{
}
元注解
用于修饰注解的注解
@Retention:用于修饰注解的生命周期
-
RetertionPolity.SOUTCE:反编译字节码文件,发现字节码文件中没有这个注解,只在源文件有效
-
RetertionPolity.CLASS :生命周期扩大到字节码文件 不写这个注解默认是字节码文件
-
RetertionPolity.RUNTIME :在运行中有效,要有反射必须要运行时有效
@Target( )
@Target(里面放枚举类型)
@Retention(RetertionPolity.SOUTCE )
public @interface MyAnnotation{
}
public enum ElementType {
TYPE, // 类、接口、枚举类
FIELD, // 成员变量(包括:枚举常量)
METHOD, // 成员方法
PARAMETER, // 方法参数
CONSTRUCTOR, // 构造方法
LOCAL_VARIABLE, // 局部变量
ANNOTATION_TYPE, // 注解类
PACKAGE, // 可用于修饰:包
TYPE_PARAMETER, // 类型参数,JDK 1.8 新增
TYPE_USE // 使用类型的任何地方,JDK 1.8 新增
}
@Documented注解 就是这个注解可以生成api文档
@Inherited注解 子类会继承父类的注解