二十章:注解


前言

1、注解也称为元数据
2、注解的出现简化一些重复的开发,经常配合aop使用
3、没有元数的注解,叫标记注解
4、注解更加干净整洁,易读代码,方便扩展
5、以及编译时类型检查


一、元注解

元注解专职负责注解其他注解,一般就是我们的自定义注解

注解作用描述
@Target注解作用的位置;ElementType参数包括:①type:类、枚举、接口 ;②METHOD;③FIELD;④CONSTRUCTOR;⑤PACKAGE;⑥PARAMETER:参数
@Retention保存的注解级别,RetentionPolicy:SOURCE、CLASS、RUNTIME
@Inherited允许子类继承父类的注解,子类可以获取到父类的注解对象信息
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface InheritedAnnotation {
    String value() default "==inherited信息==";
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
 @interface OneAnnotation {
}

@InheritedAnnotation
class ASuper{}
class AChild extends ASuper{

}

@OneAnnotation
class BSuper{}
class BChild extends BSuper{

}

public class InheritedDemo {
    public static void main(String[] args) {
        ASuper inheritedObj = new AChild();
        System.out.println("使用了@Inherited注解,可以获取到父类" + 
        			Arrays.asList(AChild.class.getAnnotations()));
        System.out.println("使用了@Inherited注解,可以获取到父类注解对象信息:" + 
        			AChild.class.getAnnotation(InheritedAnnotation.class).value());
        BSuper childObj = new BChild();
        System.out.println("普通注解,可以获取到父类" +
        		 Arrays.asList(BChild.class.getAnnotations()));
    }
}

运行结果:

使用了@Inherited注解,可以获取到父类[@demo.InheritedAnnotation(value=inherited信息)]
使用了@Inherited注解,可以获取到父类注解对象信息:==inherited信息==
普通注解,可以获取到父类[]

二、注解元素

1.注解元素类型

1、所有的基本类型(byte/short/int/long/float/double/boolean/char)
2、String
3、Class
4、Enum
5、Annotation(注解类型,可以实现注解嵌套)
6、以上所有类型的数组

不允许任何包装类型

自定义注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationElementDemo {
    //基础类型元素
    int intElement();
    //class类型
    Class<?> classElement() default Void.class;
    //String类型
    String strElement() default "";
    //数组类型
    long[] longElement();
    //枚举类型
    ElementType elementRef();
    //注解类型,内嵌注解,达到继承注解效果
    InnerAnnotation innerAnnotaion() default @InnerAnnotation;
    //包装类型报错:Invalid type 'Integer' for annotation member 
//    Integer integer();  
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface InnerAnnotation{
}

2.默认值限制

①实际上Java注解与普通修饰符(public、static、void等)无关,例:@Test测试注解可以随意注解在任何修饰的方法上

public class Testable {
    public static void execute() {
        System.out.println("Executing..");
    }    
    @Test //注解使用在public修饰的方法上
    public void testExecute2() {
        execute();
    }
    @Test//注解使用在default修饰的方法上
    void testExecute() {
        execute();
    }
    @Test//注解使用在private修饰的方法上
    private void testExecute1() {
        execute();
    }
    @Test//注解使用在static修饰的方法上
    static void testExecute3() {
        execute();
    }
} ///:~

②元素要么设置默认值,不然在使用时提供,默认值不能为null,如果想绕开这个限制可以设置空串或者负数。
③快捷方式,注解元素中有value属性,唯一赋值赋值元素是,设置值可以不用元素名=值,直接在括号中放入值。

三、注解不支持继承

注解虽然定义的时候很类似接口,区别在于不能使用extend继承(可以使用内嵌注解元素解决),还有注解可以设置默认值。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
  boolean primaryKey() default false;
  boolean allowNull() default true;
  boolean unique() default false;
} ///:~

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
  String name() default "";
  Constraints constraints() default @Constraints; //内嵌注解元素
} ///:~

@Target(ElementType.TYPE) // Applies to classes only
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
  public String name() default "";
} ///:~
public class TableCreator {
  public static void main(String[] args) throws Exception {
    Class<?> cl = Class.forName(className);
      DBTable dbTable = cl.getAnnotation(DBTable.class);
      if(dbTable == null) {
        System.out.println("No DBTable annotations in class " + className);
        continue;
      }
      String tableName = dbTable.name();
      // If the name is empty, use the Class name:
      if(tableName.length() < 1)
        tableName = cl.getName().toUpperCase();
      List<String> columnDefs = new ArrayList<String>();
      for(Field field : cl.getDeclaredFields()) {//遍历当前class对象所有对象包含private
        String columnName = null;
        Annotation[] anns = field.getDeclaredAnnotations();
        if(anns.length < 1)
          continue; // Not a db table column
        if(anns[0] instanceof SQLInteger) {
          SQLInteger sInt = (SQLInteger) anns[0];
          // Use field name if name not specified
          if(sInt.name().length() < 1)
            columnName = field.getName().toUpperCase();
          else
            columnName = sInt.name();
          columnDefs.add(columnName + " INT" + getConstraints(sInt.constraints()));
        }
        if(anns[0] instanceof SQLString) {
          SQLString sString = (SQLString) anns[0];
          // Use field name if name not specified.
          if(sString.name().length() < 1)
            columnName = field.getName().toUpperCase();
          else
            columnName = sString.name();
          columnDefs.add(columnName + " VARCHAR(" + sString.value() + ")" +  getConstraints(sString.constraints()));
        }
        StringBuilder createCommand = new StringBuilder("CREATE TABLE " + tableName + "(");
        for(String columnDef : columnDefs)
          createCommand.append("\n    " + columnDef + ",");
        // Remove trailing comma
        String tableCreate = createCommand.substring(0, createCommand.length() - 1) + ");";
        System.out.println("Table Creation SQL for "+className + " is :\n" + tableCreate);
      }
  }
  private static String getConstraints(Constraints con) {
    String constraints = "";
    if(!con.allowNull())
      constraints += " NOT NULL";
    if(con.primaryKey())
      constraints += " PRIMARY KEY";
    if(con.unique())
      constraints += " UNIQUE";
    return constraints;
  }
} /* Output:
Table Creation SQL for annotations.database.Member is :
CREATE TABLE MEMBER(
    FIRSTNAME VARCHAR(30));
Table Creation SQL for annotations.database.Member is :

四、注解与反射

package、Class、construct、method、filed都实现了AnnotatedElement接口,所以可以通过反射获取注解信息。
AnnotatedElement有如下方法:

返回值方法名称说明
< T extends Annotation>getAnnotation(Class< T > annotationClass)该元素如果存在指定类型的注解对象,则返回这些注解,否则返回 null。
Annotation[]getAnnotations()返回此元素上存在的所有注解对象,包括从父类继承的
booleanisAnnotationPresent(Class<? extends Annotation> annotationClass)如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
Annotation[]getDeclaredAnnotations()返回直接存在于此元素上的所有注解,注意,不包括父类的注解,调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响,没有则返回长度为0的数组
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface InheritedAnnotation1 {
    String value() default "==inherited信息==";
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface OneAnnotation1 {
}

@InheritedAnnotation1
class Super {
    private int superPrivate;
    public int superPublic;

    public Super() { }
    //私有
    private int superPrivate(){ return 0; }
    //公有
    public int superPublic(){ return 0; }

}

@OneAnnotation1
class Child extends Super{
    private int childPrivate;
    public int childPublic;

    public Child() { }
    //私有
    private int childPrivate(){ return 0; }
    //公有
    public int childPublic(){ return 0; }

}
public class AnnotationElementTest {
    public static void main(String[] args) throws Exception {
        Class<?> childClazz = Class.forName("demo.Child");
        Method method = childClazz.getDeclaredMethod("childPrivate", null);
        method.setAccessible(true);
        Object o = childClazz.newInstance();
        System.out.println("反射调用私有方法执行返回值:"+method.invoke(o,null));
        System.out.println("==================获取Child成员信息=======================");
        System.out.println("child是否被注解OneAnnotation1:" + childClazz.isAnnotationPresent(OneAnnotation1.class));
        System.out.println("child的所有注解(包含父类):" + Arrays.asList(childClazz.getAnnotations()));
        System.out.println("child的本身所有注解:" + Arrays.asList(childClazz.getDeclaredAnnotations()));
        System.out.println("child获取父类的注解对象到:" + childClazz.getAnnotation(InheritedAnnotation1.class));
        System.out.println("child获取到本身所以method(包含private):" + Arrays.asList(childClazz.getDeclaredMethods()));
        System.out.println("child获取私有方法对象:" + childClazz.getDeclaredMethod("childPrivate", null));
        System.out.println("==================通过Child获取到父类成员信息=======================");
        System.out.println("child获取到父类公共方法:" + Arrays.asList(childClazz.getMethods()));
        System.out.println("child是否被注解InheritedAnnotation1:" + childClazz.isAnnotationPresent(InheritedAnnotation1.class));
    }
}

运行结果:

反射调用私有方法执行返回值:0
==================获取Child成员信息=======================
child是否被注解OneAnnotation1:true
child的所有注解(包含父类)[@demo.InheritedAnnotation1(value===inherited信息==), @demo.OneAnnotation1()]
child的本身所有注解:[@demo.OneAnnotation1()]
child获取父类的注解对象到:@demo.InheritedAnnotation1(value===inherited信息==)
child获取到本身所以method(包含private)[private int demo.Child.childPrivate(), public int demo.Child.childPublic()]
child获取私有方法对象:private int demo.Child.childPrivate()
==================通过Child获取到父类成员信息=======================
child获取到父类公共方法:[public int demo.Child.childPublic(), public int demo.Super.superPublic(), public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()]
child是否被注解InheritedAnnotation1:true

总结

深入理解Java注解类型(@Annotation)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值