Java Basics - generics, reflection, annotation

Posted by warewolfe on Tue, 18 Jan 2022 10:38:49 +0100

1, Generics

Genericity is another widely used feature in Java. Genericity means that the parameter type is not fixed, that is, any data type can be used. It also has another name, that is, parametric type - that is, not only the data itself is a parameter, but also the data type can be specified as a parameter - class Interfaces or methods can be reused by different types of parameters. You just tell the compiler what type to use and leave the rest of the details to it.

1. Generic class

Through generics, you can complete the operation of a group of classes and open the same interface to the outside world

//When instantiating a generic class, you must specify the concrete type of T
public class Generic<T>{ 
    //key the type of this member variable is t, and the type of T is specified externally  
    private T key;

    public Generic(T key) { //The type of generic constructor parameter key is also t, and the type of T is specified externally
        this.key = key;
    }

    public T getKey(){ //The return value type of the generic method getKey is t, and the type of T is specified externally
        return key;
    }
}
//Parameters of different types can be passed in
Generic generic = new Generic("1");
Generic generic1 = new Generic(1);
Generic generic2 = new Generic(1.11);
Generic generic3 = new Generic(false);

2. Generic interface

When a generic argument is not passed in, the generic declaration should be added to the class when declaring the class.

public interface Generator<T> {
    public T next();
}

class FruitGenerator<T> implements Generator<T>{
    @Override
    public T next() {
        return null;
    }
}

When an argument is passed in:

public class FruitGenerator implements Generator<String> {

    private String[] fruits = new String[]{"Apple", "Banana", "Pear"};

    @Override
    public String next() {
        Random rand = new Random();
        return fruits[rand.nextInt(3)];
    }
}

3. Generic method

//Variable parameters
public <T> void printMsg( T... args){
    for(T t : args){
        Log.d("Generic testing","t is " + t);
    }
}
printMsg("111",222,"aaaa","2323.4",55.55);

4. Wildcard

  • ?: Indicates a wildcard. It cannot declare variables, but it is very important in generics. It indicates that it can hold any type, such as list <? > List, which means that any data type can be stored in the list collection (although it can do so).
  • <? Extensions T > is an upper bound wildcard, indicating that only t and subclasses of T are allowed to be called. Therefore, if the incoming type is not t or subclasses of T, an error will be reported during compilation.
  • <? Super T > is a lower bound wildcard, which means that only t and t's parent class are allowed to call. Therefore, if the incoming type is not t or T's parent class, the compilation will report an error.

Exercise 1: the upper bound wildcard has a feature: it can only be obtained and cannot be added. Please understand the meaning of this sentence through the search engine and implement it in code

A: the upper bound only means that when a generic parameter of the operation is the upper bound wildcard <? When referring to extensions T >, you can only operate the methods that return generic parameters (Methods with return value of T), but cannot operate the methods that set generic parameters (modify T).

Exercise 2: the lower bound wildcard has a feature: it can only be added but not obtained. Please understand the meaning of this sentence through the search engine and implement it in code.

A: if the lower bound exists but not retrieved, it means that when a generic parameter is operated as the next wildcard <? When super T > is referenced, you can only set the generic parameter related (modify T) and cannot operate the method that returns the generic parameter related (the method with the return value of T).

package com.company;

public class Task08_01 {
    public static void main(String[] args){
        /*
         * Upper bound <? Extensions T >: you can't save it in, you can only take it out
         * <? extends Fruit>It will invalidate the set() method of putting things on the plate, but the get() method is still valid
         * */
        Plate<? extends Fruit> p1 = new Plate<Apple>(new Apple());
        /*
         * p.set(new Fruit()); report errors
         * p.set(new Fruit());report errors
         */

        //The read things can only be stored in Fruit or its base class
        Fruit newFruit1 = p1.get();
        Object newFruit2 = p1.get();
        //Apple newFruit3 = p.get(); report errors

        /*
        * Lower bound <? Super T >: it does not affect storing in, but fetching out can only be placed in the Object object
        * <? super Fruit>: get()The Object obtained by the method can only be placed in the Object object, and the set() method is normal
        * */
        Plate<? super Fruit> p2 = new Plate<Fruit>(new Fruit());
        //The stored element is normal
        p2.set(new Fruit());
        p2.set(new Apple());
        //The retrieved objects can only be placed in Object objects
        Object newFruit4 = p2.get();
    }
    static class Fruit{

    }

    static class Apple extends Fruit{

    }

    static class Plate<T>{
        private T item;
        public Plate(T t){
            item  = t;
        }
        public void set(T t){
            item = t;
        }
        public T get(){
            return item;
        }
    }


}

Summary:

  • If the content is frequently read out, it is suitable to use the upper bound extensions.
  • It is often inserted in. It is suitable to use the lower bound Super.

2, Reflection

Java has a feature that can obtain all properties, methods, package information and annotations of a class object when the program is running, and can also change the attribute value of the object, call the object method and verify the annotation information. This ability to dynamically obtain information, dynamically change the attribute value and dynamically call the method is reflection. Anti. Reflection is to map the components of a class into objects.

1. Get Class object

  • Get class name by class name class
  • Get from object: object name getClass();
  • Get through the full class name: class Forname (full name of the class). The full name of the class here refers to the object name including the package name, for example: net csdn. java. User is the full name of the user class

2. Get construction method

  • public Constructor[] getConstructors(): get all public constructor methods
  • Public constructor [] getdeclaraedconstructors(): get all construction methods (including private, protected, default and public)
  • public Constructor getConstructor(Class... parameterTypes): get a single "public" constructor
  • public Constructor getDeclaredConstructor(Class... parameterTypes): get a constructor. It can be private, protected, default or public

3. Get member variable

  • Field[] getFields(): get all "public fields"
  • Field [] getdeclaraedfields(): get all fields, including private, protected, default and public
  • public Field getField(String fieldName): get a "public" field
  • Public field getdeclaraedfield (string fieldname): get a field (which can be private)
  • Field -- > public void set (object obj, object value): sets the value of the field

**Exercise: * * use reflection to parse a Class you create and extract all the properties, methods and interfaces in the Class. Requirements: obtain Class objects in three different ways; Modify the attribute value of the resolved Class, and then add a new attribute to the Class; Call Class methods (including private methods, static methods and construction methods) and print the results after execution; Resolve the parent object of this Class, modify the property value of its parent Class and call the method of the parent Class.

package com.company;

import java.awt.datatransfer.FlavorEvent;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Task09_reflex {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //The first way is to get the Class object
        Student student1 = new Student();
        Class stuClass = student1.getClass();

        //The second way is to get the Class object
        Class stuClass2 = Student.class;

        //The third way is to obtain the Class object
        try{
            Class stuClass3 = Class.forName("com.company.Student");
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }

        //Get all the properties of the Student class
        System.out.println("Get all properties:");
        Field[] fieldArray = stuClass.getDeclaredFields();
        for(Field f : fieldArray)
            System.out.println(f);

        //Set values for properties
        System.out.println("Set values for properties:");
        Field f = stuClass.getField("name");
        Object obj = stuClass.getConstructor().newInstance();//Generate Student object
        f.set(obj,"FXW");
        Student stu = (Student)obj;
        System.out.println("Verify name"+stu.name);

        //Call constructor
        System.out.println("Call constructor");
        Constructor con = stuClass.getConstructor(null);
        System.out.println(con);
        Object obj2 = con.newInstance();

        //Call private method
        System.out.println("Call private method");
        Method m = stuClass.getDeclaredMethod("show",int.class);
        System.out.println(m);
        m.setAccessible(true);//Lifting private restrictions
        Object result = m.invoke(obj,20);
        System.out.println(result);
    }
}

class Student{
    public String name;
    protected int age;
    char sex;
    private String number;

    public Student(){
        System.out.println("Common nonparametric construction method");
    }

    public Student(String name,int age){
        System.out.println("Common parameter construction method");
    }

    private String show(int age){
        System.out.println("Private method");
        return "a";
    }
}

3, Annotation

1. Code annotation: acts on the code

  • @Override: check whether this method is an overridden method. If it is found that its parent class or the referenced interface does not have this method, a compilation error will be reported
  • @Deprecated: marks an obsolete method. If this method is used, a compilation warning will be reported
  • @SuppressWarnings: instructs the compiler to ignore warnings declared in annotations

2. Meta annotation: acts on other annotations

  • @Retention: identifies how the annotation is saved, whether it is only in the code, incorporated into the class file, or can be accessed through reflection at run time
  • @Documented: mark whether the annotation is included in the user document;
  • @Target: what kind of Java member should the tag annotation be
  • @Inherited: marks which annotation class the annotation inherits from (the default annotation does not inherit from any subclasses)
  • @SafeVarargs: Java 7 began to support, ignoring any warnings generated by method or constructor calls that use parameters as generic variables
  • @Functional interface: Java 8 began to support, identifying a functional interface
  • @Repeatable: Java 8 began to support, and identification annotations can be used multiple times on the same declaration

Exercise 1: customize an annotation with ElementType as METHOD and RetentionPolicy as RUNTIME. Task requirements: create a class, and the METHOD of the class uses the customized annotation; Judge whether the METHOD has annotations by reflecting and parsing class annotations. If so, print out the contents of the annotations.

Note:

  1. RetentionPolicy.SOURCE: the annotation is only kept in the source file. When the Java file is compiled into a class file, the annotation is abandoned;
  2. RetentionPolicy.CLASS: the annotation is kept in the class file, but it is abandoned when the jvm loads the class file. This is the default life cycle;
  3. RetentionPolicy.RUNTIME: the annotation is not only saved in the class file, but also exists after the jvm loads the class file
package com.company;

import java.lang.annotation.*;
import java.lang.reflect.Method;

public class Task10_01 {
    public static void main(String[] args) throws NoSuchMethodException {
        //Get class
        Class stuClass = Student.class;

        //Acquisition method
        Method method = stuClass.getMethod("show");

        //Get annotation object
        M m = method.getAnnotation(M.class);

        System.out.println(m.value());
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(value = {ElementType.METHOD})
    public @interface M {
        String value() default "This is the default comment content";
    }

    class Student{
        @M
        public void show(){
            System.out.println("a");
        }
    }
}

Exercise 2: customize an annotation with ElementType as FIELD and RetentionPolicy as CLASS. Task requirements: create a CLASS and use custom annotations for a FIELD of the CLASS; Judge whether the method has annotations by reflecting and parsing CLASS annotations. If so, print out the contents of the annotations.

package com.company;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;

public class Task10_02 {
    public static void main(String[] args) throws NoSuchFieldException {
        Class stuClass = Student.class;
        Field f = stuClass.getDeclaredField("name");
        M m = f.getAnnotation(M.class);
        System.out.println(m.value());
    }

    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface M {
        String value() default "This is the default comment content";
    }

    public class Student{
        @M
        public String name;
    }
}


Summary:
@Target(ElementType.TYPE) / / interface, class, enumeration
@Target(ElementType.FIELD) / / constant of field and enumeration

Exercise 3: imitate the above nested annotation. In addition to the annotation of field type, add the annotation of field length and whether it can be empty, and add it to the @ TableColumn annotation

package com.company;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class Task10_03 {
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ColumnLength{
        int value() default 0;
    }

    public @interface ColumnEmptyOrNot{
        @Target(ElementType.FIELD)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface ColumnLength{
            boolean value() default true;
        }
    }

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TableColumn{
        ColumnLength columnlength() default  @ColumnLength;
        ColumnEmptyOrNot columnEmptyOrNot() default @ColumnEmptyOrNot;
    }
}

Exercise 4: Customize nested annotations to describe the position field in the user class.
The first level annotation defines the Department where the position is located
The second level of annotation defines the post name and description.

 //Post name
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PostName {
        String postName() default "";
    }

    //Job description
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PostDescription {
        String postDescription() default "";
    }

    //Department of post
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Department {
        String departmentName() default "";
        PostName postName() default @PostName;
        PostDescription postDescription() default @PostDescription;
    }

    public class Position {
        @Department(postName = @PostName , postDescription = @PostDescription)
        private String postName;
        private String postDescription;
    }

Topics: Java Back-end reflection