注解目前还是非常流行的,我们常用的Sprinng就是利用注解。 添加注解可以代码简洁,阅读方便 ,使用方便。
注释名称 | 解释 |
---|---|
@Target | 表示该注解可以用于什么地方,可能的ElementType参数有:CONSTRUCTOR:构造器的声明FIELD:域声明(包括enum实例)LOCAL_VARIABLE:局部变量声明METHOD:方法声明PACKAGE:包声明PARAMETER:参数声明TYPE:类、接口(包括注解类型)或enum声明 |
@Retention | 表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:SOURCE:注解将被编译器丢弃CLASS:注解在class文件中可用,但会被VM丢弃RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。 |
@Document | 将注解包含在Javadoc中 |
@Inherited | 允许子类继承父类中的注解 |
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//@Inherited 允许子类继承父类中的注解
//@Documented 将注解包含在Javadoc中
//@Retention 注解在什么级别保存注解,在反射机制中可以用到
//@Target 创建的注解可以 用在什么地方(方法、类 等)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotation {
}
新建类 Atest.Class来使用注释
@MyAnnotation
public class Atest {
private int number;
private String name;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString(){
return Atest.class.toString();
}
Atest(){}
}
新建Btest.Class来测试注释,利用反射
public class Btest {
public static void main(String[] args) throws {
Atest atest = new Atest();
Class<?> clazz = atest.getClass();
//判断类是否有注释
if(clazz.isAnnotationPresent(MyAnnotation.class)) {
System.out.println("有注解");
System.out.println(clazz.newInstance().toString());
}
}
显示结果:
有注解
class test.Atest
若果对于注释的元注释,@Retention(RetentionPolicy.RUNTIME)改成@Retention(RetentionPolicy.SOURCE),则JVM识别不到注释,一般使用运行时状态。
综上,注释有什么用处,可以在JVM运行时进行一系列操作,反射一起使用,获取被注释的类进行相关的处理。在Spring中的注释都是这样使用。可以使得一些我们自己完成的工作让框架完成
Java的反射机制中重要的部分就是获取Class对象,对于Class对象描述了类的信息信息,可以通过获取Class队形获取类的成员,方法,注解等
获取Class对象的三种方法:
那么,获取到的class类可以干什么?
可以获取对应的类的构造方法,一般方法,和成员
Constructor constructors = clazz.getConstructor(null);//拿到构造函数
Field[] fields = clazz.getDeclaredFields();//拿到它定义的所有字段
Method[] methods = clazz.getDeclaredMethods();//拿到它定义的所有方法
还有很多的方法:
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
JAVA反射机制是在运行状态中,**对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;**这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
反射机制可以打破类的访问权限的限制,可以运行private方法和访问修改private的属性。
执行私有方法和访问私有属性的时候需要加上一句method.setAccessible(true);打破访问权限的限制
新建一个Ctest的类,里面与私有方法和私有属性
public class Ctest {
private int code;
private String name;
Ctest(int code,String name) {
this.code = code;
this.name = name;
}
private String printCtest(){
return "hello"+name + code;
}
}
在类Btest里面进行访问:
public class Btest {
public static void main(String[] args){
Atest atest = new Atest();
Class<?> clazz = atest.getClass();
Field[] fields = clazz.getDeclaredFields();
//判断类是否有注释
if(clazz.isAnnotationPresent(MyAnnotation.class)) {
System.out.println("有注解");
System.out.println(clazz.newInstance().toString());
}
Ctest c = new Ctest(1,"htx");
Class<?> cclazz = Ctest.class;//获取class对象
Field[] files = cclazz.getDeclaredFields();//获取所有权限的方法属性
Method[] methods = cclazz.getDeclaredMethods();//获取所有权限的方法
for(Method method : methods){
System.out.println("方法" + method.getName());
}
for(Field file: files){
System.out.println("属性" + file);
}
try {
//修改属性
Field field = cclazz.getDeclaredField("name");
field.setAccessible(true);
System.out.println("修改前的属性值是:" + field.get(c).toString());
field.set(c,"world");
System.out.println("修改后的属性值是:" + field.get(c).toString());
//执行方法
Method method = cclazz.getDeclaredMethod("printCtest");
method.setAccessible(true);
Object temp = method.invoke(c);
System.out.println("执行方法" + temp.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果为:
方法printCtest
属性private int test.Ctest.code
属性private java.lang.String test.Ctest.name
修改前的属性值是:htx
修改后的属性值是:world
执行方法helloworld1