Preface
1. Annotations are also called metadata
2. The advent of annotations simplifies some duplicate development and often works with aop
3. Annotations without arguments are called label annotations
4. Cleaner, more readable code for easy expansion
5. and compile-time type checking
1. Meta-Notes
Meta Annotation is responsible for annotating other annotations, usually our custom annotations
annotation | Role description |
---|---|
@Target | The position of annotation function; ElementType parameters include: 1 type: class, enumeration, interface; 2 METHOD; 3 FIELD; 4 CONSTRUCTOR; 3 PACKAGE; 3 PARAMETER: parameter |
@Retention | Saved annotation level, RetentionPolicy: SOURCE, CLASS, RUNTIME |
@Inherited | Allows subclasses to inherit annotations from the parent class, which can obtain annotation object information from the parent class |
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @interface InheritedAnnotation { String value() default "==inherited information=="; } @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("Used@Inherited Notes, you can get the parent class" + Arrays.asList(AChild.class.getAnnotations())); System.out.println("Used@Inherited Annotation, you can get the parent annotation object information:" + AChild.class.getAnnotation(InheritedAnnotation.class).value()); BSuper childObj = new BChild(); System.out.println("Common annotations, you can get the parent class" + Arrays.asList(BChild.class.getAnnotations())); } }
Run result:
Used@Inherited Notes, you can get the parent class[@demo.InheritedAnnotation(value=inherited information)] Used@Inherited Annotation, you can get the parent annotation object information:==inherited information== Common annotations, you can get the parent class[]
2. Note Elements
1. Annotation element type
1,All Basic Types(byte/short/int/long/float/double/boolean/char) 2,String 3,Class 4,Enum 5,Annotation(Annotation type to achieve nesting of annotations) 6,Arrays of all types above No packaging type allowed
Custom Notes:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface AnnotationElementDemo { //Basic Type Element int intElement(); //class type Class<?> classElement() default Void.class; //String type String strElement() default ""; //Array type long[] longElement(); //Enumeration Type ElementType elementRef(); //Annotation type, inline annotation, inheritance annotation effect InnerAnnotation innerAnnotaion() default @InnerAnnotation; //Wrapper type error: Invalid type'Integer'for annotation member // Integer integer(); } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface InnerAnnotation{ }
2. Default Value Limit
(1) Actually Java annotations are not related to common modifiers (public, static, void, etc.). Example: @Test test annotations can be freely annotated on any modifier method
public class Testable { public static void execute() { System.out.println("Executing.."); } @Test //Annotations are used in public decorated methods public void testExecute2() { execute(); } @Test//Annotations are used in default modification methods void testExecute() { execute(); } @Test//Annotations are used on private ly modified methods private void testExecute1() { execute(); } @Test//Annotations are used in static modification methods static void testExecute3() { execute(); } } ///:~
(2) The element must either set a default value or be provided when used. The default value cannot be null. If you want to bypass this limit, you can set an empty string or a negative number.
(3) Shortcut, comment elements have a value attribute, the only assignment element is that you can set a value directly in parentheses without using the element name = value.
3. Notes do not support inheritance
Annotations are defined much like interfaces, except that extend inheritance cannot be used (it can be resolved using embedded annotation elements) and that annotations can set default values.
@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; //Embedded annotation elements } ///:~ @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()) {//Traverse through the current class object All objects contain 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 :
4. Notes and Reflections
package, Class, construct, method, filed all implement the AnnotatedElement interface, so you can get annotation information through reflection.
AnnotatedElement has the following methods:
Return value | Method Name | Explain |
---|---|---|
< T extends Annotation> | getAnnotation(Class< T > annotationClass) | If there are annotation objects of the specified type for the element, those annotations are returned, otherwise null is returned. |
Annotation[] | getAnnotations() | Returns all annotation objects that exist on this element, including inherited from the parent |
boolean | isAnnotationPresent(Class<? extends Annotation> annotationClass) | Returns true if an annotation of the specified type exists on this element, false otherwise. |
Annotation[] | getDeclaredAnnotations() | Returns all comments that exist directly on this element, note that, excluding comments from the parent class, the caller is free to modify the returned array; this has no effect on the array returned by other callers, or returns an array of length 0 |
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @interface InheritedAnnotation1 { String value() default "==inherited information=="; } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface OneAnnotation1 { } @InheritedAnnotation1 class Super { private int superPrivate; public int superPublic; public Super() { } //private private int superPrivate(){ return 0; } //Public public int superPublic(){ return 0; } } @OneAnnotation1 class Child extends Super{ private int childPrivate; public int childPublic; public Child() { } //private private int childPrivate(){ return 0; } //Public 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("Reflection calls private method execution return value:"+method.invoke(o,null)); System.out.println("==================Obtain Child Member Information======================="); System.out.println("child Is it annotated OneAnnotation1: " + childClazz.isAnnotationPresent(OneAnnotation1.class)); System.out.println("child All notes(Include parent class): " + Arrays.asList(childClazz.getAnnotations())); System.out.println("child All of their own notes:" + Arrays.asList(childClazz.getDeclaredAnnotations())); System.out.println("child Get the annotation object for the parent class to:" + childClazz.getAnnotation(InheritedAnnotation1.class)); System.out.println("child Get it by itself method(Contain private): " + Arrays.asList(childClazz.getDeclaredMethods())); System.out.println("child Get private method objects:" + childClazz.getDeclaredMethod("childPrivate", null)); System.out.println("==================adopt Child Get parent class member information======================="); System.out.println("child Get the parent public method:" + Arrays.asList(childClazz.getMethods())); System.out.println("child Is it annotated InheritedAnnotation1: " + childClazz.isAnnotationPresent(InheritedAnnotation1.class)); } }
Run result:
Reflection calls private method execution return value:0 ==================Obtain Child Member Information======================= child Is it annotated OneAnnotation1: true child All notes(Include parent class): [@demo.InheritedAnnotation1(value===inherited information==), @demo.OneAnnotation1()] child All of their own notes:[@demo.OneAnnotation1()] child Get the annotation object for the parent class to:@demo.InheritedAnnotation1(value===inherited information==) child Get it by itself method(Contain private): [private int demo.Child.childPrivate(), public int demo.Child.childPublic()] child Get private method objects: private int demo.Child.childPrivate() ==================adopt Child Get parent class member information======================= child Get the parent public method:[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 Is it annotated InheritedAnnotation1: true