注解
注解 :
1、什么是注解,常见注解有哪些?
1.1 注解和枚举一样是jdk1.5之后的java新特性,它们都是属于J2SE中的内容。
1.2 注解:和枚举一样,是一种特殊的java类,是java中的一种类型(即Type)。
1.3 作用:
可以给程序中的某个成分上添加一些信息,比如在类的方法上添加@Deprecated注解,在类的方法上添加@Override注解
,在类上添加注解【这里的 "@注解名" 都是注解的实例对象,也就是说这些位于成分上的信息是通过对象的形式添加到
这些成分身上的】。这些信息可以作为通知编译器的信息,供编译器使用,也可以作为其他程序在使用某些类时,
根据这些成分身上的注解信息来决定一些动作。比如,编译器本身就是一个java程序,当碰到方法上有@Deprecated注解
对象时,就做出警告,告知使用了过时的方法。
"注解对象位于成分身上"是指注解对象在成分的定义上(注解的生命周期不同,注解在定义上的体现形式也不一样,
当注解是 RentationPolicy.SOURCE 时,注解是体现在源程序中,当注解是 RentationPolicy.CLASS 时,注解是体现在
.class 文件中,当注解是 RentationPolicy.RUNTIME 时,注解体现在内存中的字节码上 。)
1.4 注解是有生命周期的:RetentionPolicy.SOURCE (源文件)、RetentionPolicy.CLASS(Class文件)、
RetentionPolicy.RUNTIME(内存中的字节码),这些是通过元注解@Retention来指定的
注解是有作用目标的:是作用在类上、还是只能是方法上、还是包上、还是成员变量上。这些是通过元注解@Target来指定的
【元注解就是用于加在注解定义上的注解】
1.5 JDK中提供的已经定义好的注解:@Override(用在方法上,表示这个方法是重载方法)、
@SuppressWarning(压制注解,用于通知编译器某些信息) 、
@Deprecated(用在某些成分上,表示该这个方法(等成分)已经过时,不建议使用)
1.6 【快速了解】 注解相当于一种标记,在程序中加了注解就相当于打了标记,没有加注解就相当于没有打标记,
以后,javac编译器、开发工具和其他程序可以通过反射来了解你的类及各种成分上有无标记,有
标记,是何种标记,看你有什么标记就去干相应的事情。标记可以加载包、类、方法、构造函数、字段、
局部变量、方法的参数上。都是在这些成分的定义(声明)上加的注解对象。
【 特殊之处在哪呢?
*1 注解的定义使用的关键字是@interface,和接口有些类似
*2 注解的对象创建位置,可以不在{}内,在程序中成分上即可,对象创建使用 "@注解名" 的方式
*3 注解的属性定义类似于内省眼中的javaBean,注解的属性是通过方法定义的,注解中的方法都是
public abstract 的,所以没有方法体,并且可以用 default 指定默认值 ,没有指定默认值的注解属性
,在创建注解对象时,必须通过 "(属性名称 = 属性值)" 的方式指定,如果一个注解中只有一个属性
是必须要给定属性值的,而且这个属性的名称是value ,那么就可以省略掉 "value = " ,只写"(属性值)"即可。
*4 注解的属性的赋值,是通过 "(属性名称 = 属性值)" 方式。注解属性值的获取是通过 "注解对象.属性名称()"来
完成的,即在程序,先通过反射获得成分身上的注解实例对象,再通过"注解对象.属性名称()" 获取到注解属性
值,并使用注解值
*5 注解属性的类型是通过方法的返回值指定的
*6 注解属性的名称就是方法的名称
*7 当给注解中的数组类型的属性赋值的时候,如果属性值中只有一个元素,即数组中只有一个元素,那么可以省略{}
*8 注解中的属性是用方法表示的,一个方法就表示一个属性,可以设置值,也可以获取值,方法的名称即是属性的名称
,方法的返回值类型即是属性的类型,默认值就是属性的默认值。
】
2、如何自定义注解(或者如何设计注解),如何给注解添加属性?
@Retention(RetentionPolicy.RUNTIME) // 保持到运行时,即内存中,(这里是元注解对象)
@Target(ElementType.METHOD) //省略了"{}" 和 " value = ",Target注解这里的属性是 "ElementType[] value();"(这里是元注解对象)
public @interface MyAnnotation //定义注解名为MyAnnotation的注解
{
//定义 value 属性 ,value的类型是String, 相当于一个javaBean的属性,有一个String的字段
//String value ;
//String setValue(String value){this.value = value}
//String getValue(){return value;}
String value();
//TrafficLamp 这里是一个枚举,使用default关键字指定默认值
TrafficLamp lamp() default TrafficLamp.RED;
//数组属性,没有指定默认值的属性,在创建注解对象的时候,都需要指定属性值
int[] arrayAttr();
}
@MyAnnotation(value = "abc" , lamp = Traffic.GREEN , arrayAttr = {1,2,3})
class AnnotationTest
{
public void static main(String[] args)
{
if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class))
{
MyAnnotation annotation = AnnotationTest.class.getAnnotation(MyAnnotation.class);
if(annotation.value().equals("abc"))
{
....
}
System.out.println(annotation.arryAtrr().length);
}
}
}
3、如何给注解添加注解属性?
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodAnnotation
{
//带默认值的,属性类型是注解的,属性
MyAnnotation myAnnotationAttr() default @MyAnnotation(value = "abc",arrayAttr = {1,2,3});
}
public Person()
{
//方法上应用注解对象@MethodAnnotation
@MethodAnnotation(myAnnotationAtrr = @MyAnnotation(value="xyz",arryAttr = {5,6,7}))
public void show()
{
System.out.println("show method");
}
public static void main() throw Exception
{
//反射获取方法
Method method = Person.class.getMethod("show");
//判断方法上是否有某个类型的注解
if(method.isAnnotationPresent(MethodAnnotation.class))
{
//反射获取方法上的注解对象
MethodAnnotation methodAnnotation = method.getAnnotation(MethodAnnotation.class);
//获取注解对象的注解类型的属性
MyAnnotation myAnnotation = methodAnnotation.myAnnotationAttr();
//获取注解属性的属性
System.out.println(myAnnotation.value());
}
}
}
4、其他示例代码:
package com.heima; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; /*定义应用注解的类Person*/ @MyAnnotation(value = "yes", arrayAttr ={1,2,3}) class Person { private String name; private int age ; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return name+" :: "+age; } } public class Test { /** * @param args */ public static void main(String[] args) { /*利用反射判断Person类上是否存在MyAnnotation注解对象*/ if(Person.class.isAnnotationPresent(MyAnnotation.class)){ /*存在,则利用反射获取Person.class身上的注解对象*/ MyAnnotation annotation = Person.class.getAnnotation(MyAnnotation.class); /*打印生成注解对象annotation的那个类的名称,发现竟然是一个动态代理类com.sun.proxy.$Proxy3生成的对象,即这个对象是一个动态类生成的对象, * 估计是个代理,也有调用处理程序,果然是个代理实例对象,调用处理程序实例对象为sun.reflect.annotation.AnnotationInvocationHandler@17ace8d */ System.out.println("创建 annotation 的类:"+annotation.getClass().getName()); /*根据注解对象annotation的value属性来决定动作*/ if(annotation.value().equals("yes") ) { Person p = new Person(); p.setName("Jack"); p.setAge(20); System.out.println(p); } /*获取注解对象annotation的数组属性,并打印*/ int[] intArray = annotation.arrayAttr(); for(int element : intArray) { System.out.println(element); } /*获取注解对象annotation的调用处理程序实例对象*/ InvocationHandler handler = Proxy.getInvocationHandler(annotation); System.out.println(handler.toString()); System.out.println("------------------测试验证猜想-----------------------"); /*一种创建动态代理对象的较为简单的方式*/ Object proxy = Proxy.newProxyInstance(Test.class.getClassLoader(), HashMap.class.getInterfaces(), new InvocationHandler(){ Map target = new HashMap(); public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("第一种方式创建代理对象,我是proxy2的代理,处理调用-- "+method.getName()+" 开始"); Object retVal = method.invoke(target, args); System.out.println("第一种方式创建代理对象,我是proxy2的代理,处理调用-- "+method.getName()+" 结束"); return retVal; } }); /*打印创建代理实例对象的动态代理类*/ System.out.println("创建 proxy 的动态代理类:"+proxy.getClass().getName()); /*使用动态代理对象,并打印结果*/ ((Map)proxy).put("zhangsan",3); System.out.println(proxy); /*创建代理类实例的另一种较为复杂的方式,先创建动态代理类*/ Class proxy2Class = Proxy.getProxyClass(ArrayList.class.getClassLoader(),ArrayList.class.getInterfaces()); /*利用反射获取动态代理类身上的所有构造方法*/ Constructor[] constructors = proxy2Class.getConstructors(); /*查看这些构造方法*/ for(Constructor constructor : constructors) { System.out.println("构造方法名:"+constructor.getName()); System.out.print("构造方法的参数列表: "); Class[] params = constructor.getParameterTypes(); for(Class param : params) { System.out.print(param.getName()+" "); } } System.out.println(); /*利用反射创建动态代理类proxy2Class的动态代理对象proxy2*/ Collection proxy2 = null; try { /*获取动态代理类的构造方法*/ Constructor constructor = proxy2Class.getConstructor(InvocationHandler.class); /*利用反射创建对象*/ proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){ Object target = new ArrayList(); public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("第二种方式创建代理对象,我是proxy2的代理,处理调用-- "+method.getName()+" 开始"); Object retVal = method.invoke(target, args); System.out.println("第二种方式创建代理对象,我是proxy2的代理,处理调用-- "+method.getName()+" 结束"); return retVal; } }); /*使用代理对象proxy2,并打印结果*/ proxy2.add("Rose"); System.out.println(proxy2); } catch (Exception e) { e.printStackTrace(); } } } }