Java注解
-
Java注解( Annotation)注解其实就是代码里的特殊标记,它用于替代配置文件:传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
-
注解可以标记在包、类、属性、方法,方法参数以及局部变量上,且同一个地方可以同时标记多个注解。
内置的注解:
- @Override:检查该方法是否是重载方法。如果发现其父类或者是其引用的接口中并没有该方法时,会报编译错误。
- @Deprecated:标记过时方法,如果使用该方法,会报编译警告
- @SuppressWarnings:指示编译器去忽略注解中声明的警告
以下为作用在其他注解的注解(元注解)
- @Retention:定义了该Annotation被保留的时间长短:
- 某些Annotation仅出现在源代码中,而被编译器丢弃;
- 另一些却被编译在class文件中,注解保留在class文件中,在加载到JVM虚拟机时丢弃,这是默认行为,所以没有用Retention注解的注解,都会采用这种策略
- 而另一些在class被装载时将被读取,注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在class文件中有效(即class保留)
- RUNTIME:在运行时有效(即运行时保留)
-
@Documented:Documented注解的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息。
-
@Target:描述注解的使用范围(即:被修饰的注解可以用在什么地方)。Target注解用来说明那些被它所注解的注解类可修饰的对象范围:注解可以用于修饰 packages、types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数),在定义注解类时使用了@Target 能够更加清晰的知道它能够被用来修饰哪些对象
-
@Inherited:使被它修饰的注解具有继承性(如果某个类使用了被@Inherited 修饰的注解,则其子类将自动具有该注解)。
-
@SafeVarargs:Java7开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
-
@FunctionalInterface:标识一个匿名函数或者函数式接口
-
@Repeatable:标识某注解可以在同一个声明上使用多次。
简单的元注解(修饰自己写的注解)例子:
@Documented
@Target(ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyAnnoation {
}
反射
-
Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
-
Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
被操作对象People:
package zxc;
import zxv.Column;
public class People {
@Column("用户名")//反射注解
private String name;
private int age;
public People(){
}
public People(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
被反射的注解:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
进行反射:
// 类中的成员:方法,属性,构造器
@Test
public void reflect(){
try {
//class[People]---->class(运行时类)---->c[对象]
Class <?> c=Class.forName("zxc.People");//加载到内存中
//通过反射得到默认构造器
Constructor con=c.getConstructor();//得到默认构造器
People p=(People)con.newInstance();//相当于实例化
p.setAge(12);
System.out.println(p.getAge());
//通过反射得到非默认构造器
Constructor con1=c.getConstructor(String.class,int.class);//得到默认构造器
People p1=(People) con1.newInstance("like",12);
System.out.println(p1.getName());
//方法反射
Constructor con2=c.getConstructor();
People p2=(People) con2.newInstance();
Method m= c.getMethod("setName", String.class);//反射得到setName方法
m.invoke(p2,"like");//p2.setName()
Method m1= c.getMethod("getName");//反射得到getName方法
System.out.println(m1.invoke(p2));
//属性反射
Constructor con3=c.getConstructor();
People p3=(People) con3.newInstance();
Field[] fs=c.getDeclaredFields();//显示所有字段 c.getFields()显示非私有字段
Arrays.asList(fs).forEach(f->System.out.println(f.getName()));
//反射字段
Field f=c.getDeclaredField("name");//因为属性:name是私有的,所以此函数没有权限访问私有属性
f.setAccessible(true);//给以访问权限
f.set(p,"like");
System.out.println(f.get(p));
//反射数组
Object o =Array.newInstance(String.class,5);// String []a=new String[5];
Array.set(o,0,"awsl");
Array.set(o,1,"yyds");
Array.set(o,2,"hust");
Array.set(o,3,"comq");
System.out.println(Array.get(o,3));
//反射注解
Class cq=People.class;//和Class c=Class.forName("zxc.People");一个意思
Field fsq[]=cq.getDeclaredFields();
for(Field fq:fsq){
if(fq.isAnnotationPresent(Column.class)){
Column cl=fq.getAnnotation(Column.class);
if(cl.value().equals("用户名"));
System.out.println(cl);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}