Java Object Oriented Programming Chapter 6 -- Annotation and reflection

Java Object Oriented Programming Chapter 6 -- Annotation and reflection

1. Annotation overview

Java Annotation, also known as Java Annotation, is an Annotation mechanism introduced by JDK5.0

Classes, methods, variables, parameters and packages in the Java language can be labeled. Java annotations can obtain annotation content through reflection. When the compiler generates class files, annotations can be embedded in bytecode. The Java virtual machine can retain the annotation content and obtain the annotation content at run time. Of course, it also supports custom Java tags

It can be simply understood as a label

2. Meta annotation

As the name suggests, meta annotation can be understood as annotation

@Retention (annotation retention period)

  • @Retention(RetentionPolicy.SOURCE). The annotation only exists in the source code and is not included in the class bytecode file

  • @Retention(RetentionPolicy.CLASS), the default retention policy. Annotations exist in the class bytecode file, but cannot be obtained at runtime

  • @Retention(RetentionPolicy.RUNTIME), the annotation will exist in the class bytecode file and can be obtained through reflection at run time

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}

@Target (scope of annotation)

  • @Target(ElementType.TYPE) functions as interface, class, enumeration and annotation
  • @Target(ElementType.FIELD) acts as a constant for attribute fields and enumerations
  • @Target(ElementType.METHOD) action method
  • @Target(ElementType.PARAMETER) action method parameter
  • @Target(ElementType.CONSTRUCTOR) function constructor
  • @Target(ElementType.LOCAL_VARIABLE) acts as a local variable
  • @Target(ElementType.ANNOTATION_TYPE) acts on the annotation (@ Retention annotation uses this attribute)
  • @Target(ElementType.PACKAGE) acts on the package
  • @Target(ElementType.TYPE_PARAMETER) acts on type generics, that is, generic methods, generic classes, and generic interfaces (added in jdk1.8)
  • @Target(ElementType.TYPE_USE) can be used to label any type except class (added in jdk1.8)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
}

@Documented

  • Document means document in English. Its function is to include the elements in the annotation into the Javadoc
@Documented
public @interface MyAnnotation {
}

@Inherited

  • Inherited means inherited in English
  • It does not mean that the annotation itself can be Inherited, but that if a superclass is annotated with an annotation annotated by @ Inherited, if its subclass is not applied with any annotation, the subclass inherits the annotation of the superclass
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Inherited
public @interface MyAnnotation {
}
@MyAnnotation
public class Test {
}

class Test1 extends Test{
}

The annotation MyAnnotation is modified by @ Inherited, and then class Test is annotated by MyAnnotation. Class Test1 inherits Test, so class Test1 also has the annotation MyAnnotation.

@Repeatable

  • Repeatable means repeatable in English. As the name suggests, the annotation modified by this meta annotation can act on an object multiple times at the same time, but each action annotation can represent different meanings
//It's like a bunch of notes
@Retention(RetentionPolicy.RUNTIME)
public @interface Values {
    Value[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {
    String id() default "value";
}
public class Test {
    @Value("hello")
    @Value("world")
    public static void test(String var1, String var2) {
        System.out.println(var1 + " " + var2);
    }

    public static void main(String[] args) {
        Method[] methods = Test.class.getMethods();
        for (Method method : methods){
            if (method.getName().equals("test")) {
                Annotation[] annotations = method.getDeclaredAnnotations();
                System.out.println(annotations.length);
                System.out.println(method.getName() + " = " + Arrays.toString(annotations));
            }
        }
    }
}
  • When defining an attribute in an annotation, its type must be 8 basic data types, plus classes, interfaces, annotations and their arrays

  • The attribute in the annotation can have a default value, which needs to be specified with the default key value

  • If there is only one attribute named value in an annotation, the attribute value can be directly filled in parentheses when applying this annotation

3. Annotation extraction (reflection)

Here we will use the following reflection for the time being, and we will talk about reflection in detail later

@Retention(RetentionPolicy.RUNTIME)
public @interface Values {
    Value[] value();
}

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {
    String id() default "id";
    String name() default "name";
}

@Value(id = "1",name = "zhangsan")
@Value(id = "2",name = "lisi")
public class Test {
    public static void main(String[] args) {
        if (Test.class.isAnnotationPresent(Values.class)){
            Values annotation = Test.class.getAnnotation(Values.class);
            Value[] values = annotation.value();
            for (Value value : values) {
                System.out.println("id="+value.id());
                System.out.println("name="+value.name());
            }
        }
    }
}

id=1
name=zhangsan
id=2
name=lisi

Annotations on attributes and methods can still be used. Similarly, it is still necessary to fake reflection

@Retention(RetentionPolicy.RUNTIME)
public @interface Values {
    Value[] value();
}

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {
    String id() default "id";
    String name() default "name";
}

import java.lang.reflect.Field;
import java.lang.reflect.Method;
@Value(id = "-1",name = "yoya")
@Value(id = "0",name = "ruoye")
public class Test {
    @Value(id = "1",name = "zhangsan")
    public int a;
    @Value(id = "2",name = "lisi")
    public void todo(){

    }

    public static void main(String[] args) {
        boolean hasAnnotation = Test.class.isAnnotationPresent(Values.class);
        if ( hasAnnotation ) {
            Values values = Test.class.getAnnotation(Values.class);
            //Get class annotations
            System.out.println("Class annotation======================");
            System.out.println(values);
        }
        try {
            Field a = Test.class.getDeclaredField("a");
            a.setAccessible(true);
            //Gets the annotation on a member variable
            Value value = a.getAnnotation(Value.class);
            if ( value != null ) {
                System.out.println("Attribute annotation======================");
                System.out.println(value.id());
                System.out.println(value.name());
            }
            Method testMethod = Test.class.getDeclaredMethod("todo");
            if (testMethod!=null) {
                // Get annotation in method
                System.out.println("Method annotation======================");
                Value declaredAnnotation = testMethod.getDeclaredAnnotation(Value.class);
                if ( value != null ){
                    System.out.println(declaredAnnotation.id());
                    System.out.println(declaredAnnotation.name());
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

4. Reflection (the soul of frame design)

4.1 what is reflection

  • Encapsulating the components of a class into other objects is the reflection mechanism

  • You can manipulate these objects while the program is running

  • It can decouple and improve the scalability of the program

  • Too much reflection can affect performance

4.2. Three ways to obtain Class objects

The same bytecode file (*. class) will only be loaded once during a program run, and the class object obtained by either method is the same

4.2.1. Obtain the corresponding Class object through the Class object

This method is not generally used

public class Student {
}

public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        System.out.println(student.getClass());
        System.out.println(student.getClass().getName());
    }
}

class com.ruoye.Student
com.ruoye.Student

4.2.2. Get through the static attribute of class name. Class

Guide package required

public class Student {
}

public class Test {
    public static void main(String[] args) {
        System.out.println(Student.class);
    }
}

class com.ruoye.Student

4.2.3. Get through the static method forName() in Class

public class Student {
}

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<Student> studentClass = (Class<Student>) Class.forName("com.ruoye.Student");
        System.out.println(studentClass.getName());
    }
}

com.ruoye.Student

4.3. Get the constructor of the Class through the Class object

public class Student {
    private int num;
    private String name;

    public Student() {
    }

    private Student(int num) {
        this.num = num;
    }

    public Student(String name) {
        this.name = name;
    }

    private Student(int num, String name) {
        this.num = num;
        this.name = name;
    }
}

public class Test {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<Student> studentClass = Student.class;
        System.out.println("All constructors================");
        Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
        System.out.println("Public constructor=================");
        Constructor<?>[] constructors = studentClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        System.out.println("All constructors that specify parameters==============");
        Constructor<Student> constructor = studentClass.getDeclaredConstructor(int.class);
        System.out.println(constructor);
        System.out.println("Specifies the public constructor for the parameter==============");
        Constructor<Student> constructor1 = studentClass.getConstructor(String.class);
        System.out.println(constructor1);
    }
}

All constructors================
private com.ruoye.Student(int,java.lang.String)
public com.ruoye.Student(java.lang.String)
private com.ruoye.Student(int)
public com.ruoye.Student()
Public constructor=================
public com.ruoye.Student(java.lang.String)
public com.ruoye.Student()
All constructors that specify parameters==============
private com.ruoye.Student(int)
Specifies the public constructor for the parameter==============
public com.ruoye.Student(java.lang.String)

4.4. Create an object through the obtained constructor

public class Student {
    private int num;
    private String name;

    public Student() {
    }

    private Student(int num) {
        this.num = num;
    }

    public Student(String name) {
        this.name = name;
    }

    private Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "num=" + num +
                ", name='" + name + '\'' +
                '}';
    }
}

public class Test {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Student> studentClass = Student.class;
        Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(int.class, String.class);
        //Violent reflex
        declaredConstructor.setAccessible(true);
        Student zhangsan = declaredConstructor.newInstance(1, "zhangsan");
        System.out.println(zhangsan);
    }
}

4.5. Get member variables through Class object

public class Student {
    public boolean flag;
    private int num;
    private String name;

    public Student() {
    }

    private Student(int num) {
        this.num = num;
    }

    public Student(String name) {
        this.name = name;
    }

    private Student(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "num=" + num +
                ", name='" + name + '\'' +
                '}';
    }
}

public class Test {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Student> studentClass = Student.class;
        System.out.println("Get all fields==============");
        Field[] fields = studentClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("Get public field==============");
        Field[] fields1 = studentClass.getFields();
        for (Field field : fields1) {
            System.out.println(field.getName());
        }
        System.out.println("Get specific fields===========");
        Field num = studentClass.getDeclaredField("num");
        System.out.println(num.getName());
        System.out.println("Set values for fields============");
        Student student = studentClass.getDeclaredConstructor(null).newInstance();
        student.setName("ruoye");
        System.out.println(student.toString());
    }
}

4.6. Get the method of this Class through the Class object

public class Student {
    private void sleep(int a){
        System.out.println("sleep");
    }
    public void study(String name){
        System.out.println("study");
    }
}

public class Test {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Student> studentClass = Student.class;
        System.out.println("Get all methods================");
        Method[] declaredMethods = studentClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        System.out.println("Get public method (method containing parent class)================");
        Method[] declaredMethods1 = studentClass.getMethods();
        for (Method declaredMethod : declaredMethods1) {
            System.out.println(declaredMethod);
        }
        System.out.println("Gets the specified public method================");
        Method study = studentClass.getMethod("study", String.class);
        System.out.println(study);
        System.out.println("Gets the specified method================");
        Method sleep = studentClass.getDeclaredMethod("sleep", int.class);
        Student student = studentClass.getDeclaredConstructor(null).newInstance();
        sleep.setAccessible(true);
        System.out.println(sleep);
        //Wake up method
        sleep.invoke(student,1);
    }
}

4.7. Call the specified Method through the Method object

public class Student {
    private void sleep(int a){
        System.out.println("sleep:"+a);
    }
    public void study(String name){
        System.out.println(name+":study");
    }
    public static void run(String name){
        System.out.println(name+":run");
    }
}
public class Test {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Student> studentClass = Student.class;

        Method sleep = studentClass.getDeclaredMethod("sleep", int.class);
        Student student = studentClass.getDeclaredConstructor(null).newInstance();
        sleep.setAccessible(true);
        System.out.println(sleep);
        sleep.invoke(student,1);

        Method run = studentClass.getDeclaredMethod("run", String.class);
        System.out.println(run);
        //If the method is static, the specified obj parameter can be ignored. The parameter can be null
        //If the shape parameter required by the method is 0, the length of the args array provided can be 0 or null
        //Method is static and the class that declares this method has not been initialized
        run.invoke(null,"zhangsan");
    }
}

Tags: Java

Posted on Fri, 03 Sep 2021 18:51:18 -0400 by jahred