注解
什么是注解
- JDK 1.5开始引入
- 不是程序本身,可以对程序作出解释,被其他程序读取
- @注释名,可以添加参数值,如@SuppressWarnings(value=“unchecked”)
- 可以附加在pakage、class、method、field上,相当于给他们添加了额外的辅助信息,我们可以通过反射机制实现对这些元数据的访问
内置注解
- @Override:方法重写
- @Deprecated:方法/属性/类,不推荐程序员使用
- @SuppressWarnings:抑制编译时的警告信息
元注解
元注解的作用是负责注解其他注解,Java定义了4个标准的元注解类型
- **@Target:**描述注解的使用范围,方法/属性/类/包…
- **@Retention:**表示需要在说明级别保存该注释循序,用于描述注解的生命周期 SOURCE-CLASS-RUNTIME
- @Document:说明该注解将被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
自定义注解
使用**@interface**自定义注解时,自动继承了java.lang.annotation.Annotation接口
@hana(name = "hana", id = 1024)
public class Test01 {
@hana(id = 228)
private String name;
}
@Target(value = {ElementType.TYPE,ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface hana{
// 注解的参数:参数类型+参数名();
String name() default "";
int age() default -1; // 如果默认为-1,表示不存在
int id();
String[] schools() default {"清华", "北大"};
}
反射
静态 VS 动态语言
- 动态语言是一类在运行时代码可以根据某些条件改变自身结构的语言,如新的函数、新的对象、引进代码、删除已有函数等
- 静态语言是一类运行时结构不可变的语言,如Java、C、C++等
Java可以利用反射机制获得类似动态语言的特性
反射概念
加载完类之后,在堆内存中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息。反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
运行时类的完整结构
通过反射获取运行时类的完整结构
- 实现的全部接口
- 所继承的父类
- 全部的构造器
- 全部的方法
- getMethods():获得本类及其父类的所有public方法
- getDeclaredMethos():获得本类的所有方法
- 全部的属性
- 注解
- …
Class类实例获取方法
- 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class clazz = Person.class;
- 已知某个类的实例,调用该实例的getClass() 方法获取Class对象
Class clazz = person.getClass();
- 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class clazz = Class.forName("com.demo.Person");
- 内置基本数据类型可以直接用其包装类类名.Type
Class clazz = Integer.Type;
- 利用ClassLoader
哪些类型有Class对象
- class:外部类、成员类、局部内部类、匿名内部类
- interface:接口
- []:数组
- enum:枚举
- annotation:注解@interface
- 基本数据类型
- void
有了Class对象,能做什么
- **创建类的对象:**调用Class对象的newInstance()方法
- 类必须有一个无参数的构造器
- 类的构造器的访问权限需要足够
PS:可以通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的形参类型的构造器-》然后向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数-》通过Constructor实例化对象
- **调用指定的方法:通过Class类的getMethod(String name, Class …parameterTypes)方法取得一个Method对象,并设置次方法操作时所需的参数类型-》然后使用Object invoke(Object obj, Object[] args)**进行调用,并向方法中传递要设置的obj对象的参数信息。
- Object对应原方法的返回值,若无返回值,此时返回null
- 若原方法为静态方法,此时形参Object obj可为null
- 若原方法参数列表为空,则Object[] args为null
- 若原方法声明为private,则需要在调用此invoke()方法前,显示调用方法对象的setAccessible(true)方法,将可访问private的方法
setAccessible
- Method、Field和Constructor对象都有setAccessible()方法
- setAccessible作用是启动和禁止访问安全检查的开关
- 参数值为true表示反射的对象在使用时应该取消Java语言访问检查
- 提高反射的效率,如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true
- 使得原本无法访问的私有成员也可以访问
- 参数值为false表示反射的对象在使用时应该实施Java语言访问检查