JAVA study notes—annotations and reflection

1. Annotation

1.1 Basic concepts of Annotation

what is annotation

  • Annotation is a new technology introduced starting from JDK5.0.
  • The role of Annotation:
    • It is not the program itself, it can explain the program (this is no different from a comment)
    • Can be read by other programs (such as compilers, etc.).
  • Annotation format:
    • Annotations exist in the code as "@annotation name", and you can also add some parameter values, for example: @SuppressWarning(value="unchecked").
  • Where is Annotation used?
    • It can be attached to package, class, method, field, etc., which is equivalent to adding additional auxiliary information to them. We can access these metadata through reflection mechanism programming.
//什么是注解
public class Test01 extends Object {
    
    
    public static void main(String[] args) {
    
    

    }

    //@Override  重写的注解
    @Override
    public String toString() {
    
    
        return super.toString();
    }
}

1.2 Built-in annotations

  • @Override: Defined in java.lang.Override, this annotation applies only to rhetorical methods and indicates that a method declaration intends to override another method declaration in the superclass.
  • @Deprecated: Defined in java.lang.Deprecated, this annotation can be used rhetorically on methods, properties, and classes to indicate that programmers are discouraged from using such an element, usually because it is dangerous or a better alternative exists.
  • @SupperessWarnings: Defined in java.lang.SuppressWarning, used to suppress warning messages during compilation.
    • Different from the first two comments, you need to add a parameter to use it correctly. These parameters have been defined, and we can use them selectively.
    • @SuppressWarnings(“all”)
    • @SuppressWarnings(“unchecked”)
    • @SuppressWarnings(value={“unchecked”,“deprecation”})
    • etc······
//什么是注解
public class Test01 extends Object {
    
    

    //@Override  重写的注解
    @Override
    public String toString() {
    
    
        return super.toString();
    }
    //@Deprecated 不推荐程序员使用,但可以使用,或者存在更好的方式
    @Deprecated
    public static void test(){
    
    
        System.out.println("Deprecated");
    }
    @SuppressWarnings("all")
    public void test02(){
    
    
        List list = new ArrayList<>();
    }
    public static void main(String[] args) {
    
    
        test();
    }
}

1.3 Meta-annotations

  • The role of meta-annotations is to annotate other annotations. Java defines four standard meta-annotation types, which are used to provide descriptions of other annotation types.
  • These types and the classes they support are found in the java.lang.annotation package. (@Target,@Retention,@Documented,@Inherited)
    • @Target: used to describe the scope of application of the annotation (ie: where the described annotation can be used)
    • @Retention: Indicates at what level the annotation information needs to be saved, used to describe the life cycle of the annotation (SOURCE<CLASS<RUNTIME)
    • @Document: Indicates that the annotation will be included in javadoc
    • @Ingerited: Indicates that subclasses can inherit this annotation from the parent class
//测试元注解
@MyAnnotation
public class test02 {
    
    
    public void test(){
    
    

    }
}
//定义一个注解
//Target 表示我们的注解可以用在哪些地方
@Target(value = {
    
    ElementType.METHOD,ElementType.TYPE})
//Retention 表示我们的注解在什么地方还有效
//RUNTIME>CLASS>SOURCES
@Retention(value = RetentionPolicy.RUNTIME)
//Documented 表示是否将我们的注解生成在Javadoc中
@Documented
//Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{
    
    

}

Custom annotations

  • When using @interface custom annotation, the java.lang.annotation.Annotation interface is automatically inherited.
  • analyze:
    • @interface is used to declare an annotation, format: public@interface annotation name {definition content}
    • Each of these methods actually declares a configuration parameter.
    • The name of the method is the name of the parameter.
    • The return value type is the type of the parameter (the return value can only be basic types, Class, String, enum).
    • You can declare the default value of the parameter through default
    • If there is only one parameter member, the parameter is generally named value.
    • Annotation elements must have a value. When we define annotation elements, we often use empty strings and 0 as the default value.
//自定义注解
public class Test03 {
    
    
    //注解可以显示赋值 ,如果没有默认值,我们就必须给注解赋值
    @MyAnnotation2(name = "小蔡",age = 20,schools = {
    
    "清华大学","北京大学"})
    public void test(){
    
    

    }
    @MyAnnotation3(value = "张三")
    public void test2(){
    
    

    }
}
@Target({
    
    ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    
    
    //注解的参数: 参数类型 + 参数名();
    String name() default "";
    int age() default 0;
    int id() default -1;//如果默认值为-1,代表不存在
    String[] schools() default {
    
    "武汉大学","中山大学"};
}

@interface MyAnnotation3{
    
    
    String value();

2. Reflection mechanism

Java.Reflection

2.1 Static VS dynamic language

dynamic language

  • It is a type of language whose structure can be changed at runtime: for example, new functions, objects, and even codes can be introduced, existing functions can be deleted, or other structural changes can be made. In layman's terms, the code can change its structure according to certain conditions at runtime.
  • Main dynamic languages: Objective-C, C#, JavaScript, PHP, python, etc.

static language

  • Corresponding to dynamic languages, languages ​​whose runtime structure is immutable are static languages. Such as Java, C, C++.
  • Java is not a dynamic language, but Java can be called a "quasi-dynamic language". That is, Java has a certain degree of dynamics, and we can use the reflection mechanism to obtain characteristics similar to dynamic languages. The dynamic nature of Java makes programming more flexible!

2.2 Java Reflection

Reflection is the key to Java being regarded as a dynamic language. The reflection mechanism allows the program to obtain the internal information of any class through the Reflection API during execution, and can directly operate the internal properties and methods of any object.

Class c=Class.forName("java.lang.String")

After the class is loaded, a Class type object is generated in the method area of ​​the heap memory (a class has only one Class object). This object contains the complete structural information of the class. We can see the structure of the class through this object. This object is like a mirror, through which we can see the structure of the class, so we vividly call it: reflection

Normal way:

  1. Introduce the name of the required "package class"
  2. instantiated via new
  3. Get the instantiated object

Reflection mode:

  1. instantiate object
  2. getClass() method
  3. Get the full "package class" name

2.3 Research and application of Java reflection mechanism

Functions provided by Java reflection mechanism

  • Determine the class to which any object belongs at runtime
  • Construct objects of any class at runtime
  • Determine the member variables and methods of any class at runtime
  • Get generic information at runtime
  • Call member variables and methods of any object at runtime
  • Process annotations at runtime
  • Generate dynamic proxy
  • ······
Java Reflection Advantages and Disadvantages

advantage:

  • Can realize dynamic creation of objects and compilation, reflecting great flexibility

shortcoming:

  • Impact on performance. Using reflection is basically an interpreted operation where we can tell the JVM what we want to do and it meets our requirements. Such operations are always slower than performing the same operation directly.
Main APIs related to reflection
  • java.lang.Class: represents a class
  • java.lang.reflect.Method: Represents the method of the class
  • java.lang.reflect.Field: represents the member variables of the class
  • java.lang.reflect.Constructor: Represents the constructor of the class
  • ······

2.4 Class

The following method is defined in the Object class, which will be inherited by all subclasses

public final Class getClass()
  • The return value type of the above method is a Class class, which is the source of Java reflection. In fact, the so-called reflection is also easy to understand from the running results of the program, that is: the name of the class can be found through object reflection.

The information that can be obtained after an object looks in the mirror: the attributes, methods and constructors of a certain class, and which interfaces a certain class implements. For each class, the JRE retains an unchanged Class type object. A Class object contains information about a specific structure (class/interface/enum/annotation/primitive type/void/[]).

  • Class itself is also a class
  • Class objects can only be created by the system
  • A loaded class will only have one Class instance in the JVM
  • A Class object corresponds to a .class file loaded into the JVM.
  • Each class instance will remember which Class instance it was generated from
  • Through Class, you can completely get all the loaded structures in a class.
  • The Class class is the root of Reflection. For any class you want to dynamically load and run, you can only obtain the corresponding Class object first.

2.5 Common methods of Class class

method name Function Description
static ClassforName(String name) Returns the Class object of the specified class name
Object newInstance() Call the default constructor and return an instance of the Class object
getName() Returns the name of the entity (class, interface, array class, or void) represented by this Class object
Class getSuperClass() Returns the Class object of the parent class of the current Class object
Class[] getinterfaces() Get the interface of the current Class object
ClassLoader getClassLoader() Returns the class loader for this class
Constructor[] getConstructors() Returns an array containing some Constructor objects
Method getMethod(String name,Class… T) Returns a Method object whose formal parameter type is paramType
Field[] getDeclaredFields() Returns an array of Field objects

2.6 Get an instance of Class class

  1. If the specific class is known, obtain it through the class attribute of the class. This method is the safest and most reliable, and has the highest program performance.
Class clazz = Person.class;
  1. If an instance of a certain class is known, call the getClass() method of the instance to obtain the Class object.
Class clazz=Person.getClass();
  1. The full class name of a class is known, and the class is on the class path. It can be obtained through the static method forName() of the Class class. ClassNotFoundException may be thrown.
Class clazz=Class.forName("demo01.Student");
  1. Built-in basic data types can be directly used with the class name .Type
  2. You can also use ClassLoader, which we will explain later.
//测试Class类的创建方式有哪些
public class Test03 {
    
    
    public static void main(String[] args) throws ClassNotFoundException {
    
    
        Person person = new Student();
        System.out.println("这个人是:"+person.name);

        //方式一:通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());
        //方式二:forname获得
        Class c2 = Class.forName("com.annotation.demo02.Student");
        System.out.println(c2.hashCode());
        //方式三:通过类名.class
        Class c3 = Student.class;
        System.out.println(c3.hashCode());
        //方式四:基本内置类型的包装类都有一个Type属性
        Class c4 = Integer.TYPE;
        System.out.println(c4);
        //获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);
    }
}
class Person{
    
    
    public String name;

    public Person() {
    
    
    }

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

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

class Student extends Person{
    
    
    public Student(){
    
    
        this.name = "学生";
    }
}
class Teacher extends Person{
    
    
    public Teacher(){
    
    
        this.name = "老师";
    }
}

2.7 Which types can have Class objects?

  • class: external class, member (member internal class, static internal class), local internal class, anonymous internal class.
  • interface:interface
  • []:array
  • enum: enumeration
  • annotation:annotation@interface
  • primtive type: basic data type
  • void
//所有类型的Class对象
public class Test04 {
    
    
    public static void main(String[] args) {
    
    
        Class c1 = Object.class; //类
        Class c2 = Comparable.class; //接口
        Class c3 = String[].class; //一维数组
        Class c4 = int[][].class; //二维数组
        Class c5 = Override.class; //注解
        Class c6 = ElementType.class; //枚举
        Class c7 = Integer.class; // 基本数据类型
        Class c8 = void.class; //void
        Class c9 = Class.class; //Class

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);
        //只要元素类型与维度一样,就是同一个Class
        int[] a = new int[10];
        int[] b = new int[100];
        System.out.println(a.getClass().hashCode());//21685669
        System.out.println(b.getClass().hashCode());//21685669
    }
}

2.8 Java memory analysis

Java memory

  1. heap

    • Store new objects and arrays
    • Can be shared by all threads and does not store references to other objects
  2. stack

    • Stores the basic variable type (will contain the specific value of this basic type)
    • A variable that refers to an object (the specific address of this reference in the heap will be stored)
  3. method area

    • Can be shared by all threads
    • Contains all class and static variables

2.9 Understand: Class loading process

When a program actively uses a class, if the class has not been loaded into memory, the system will initialize the class through the following three steps.

Class loading (Load)->Class link (Link)->Class initialization (Initialize)

Class loading: Read the class file into memory and create a java.lang.CLass object for it. This process is done by the class loader

Linking of classes: Merging binary data of classes into the JRE

Initialization of classes: JVM is responsible for initializing classes

2.10 Class loading and understanding of ClassLoader

  • Loading: Load the bytecode content of the class file into memory, convert these static data into the runtime data structure of the method area, and then generate a java.lang.Class object representing this class.
  • Linking: The process of merging the binary code of a Java class into the running state of the JVM.
    • Verification: Ensure that the loaded class information complies with JVM specifications and has no security issues
    • Preparation: The stage of formally allocating memory for class variables (static) and setting the default initial value of the variable. These memories will be allocated in the method area.
    • Analysis: The process of replacing symbolic references (constant names) in the virtual machine's constant memory pool with direct references (addresses).
  • initialization:
    • The process of executing the class constructor () method. The class constructor () method is generated by the compiler automatically collecting the assignment actions of all class variables in the class and merging the statements in the static code block. (The class constructor is used to construct class information. , is not a constructor for constructing objects of this class).
    • When initializing a class, if it is found that its parent class has not been initialized, you need to trigger the initialization of its parent class first.
    • The virtual machine ensures that the () method of a class is correctly locked and synchronized in a multi-threaded environment.
public class Test05 {
    
    
    public static void main(String[] args) {
    
    
        A a = new A();
        System.out.println(A.m);
        /*
        1. 加载到内存,会产生一个类对应的Class对象
        2. 链接,链接结束后m = 0
        3. 初始化
            <clinit>(){
                System.out.println("A类静态代码块初始化");
                m = 300;
                m = 100;
            }
         */
    }
}

class A {
    
    
    static {
    
    
        System.out.println("A类静态代码块初始化");
        m = 300;
    }
    /*
    * m = 300
    * m = 100
    * */

    static int m = 100;
    public A(){
    
    
        System.out.println("A类的无参构造初始化");
    }
}
/*
* 方法区:
* Test05的数据:1. 静态变量 2. 静态方法 3. 常量池 4. 代码
* A类的数据:1. 静态变量 2. 静态方法 3. 常量池 4. 代码
* */
/*
* 堆
* java.lang.Class 对象代表Test05类
* java.lang.Class 对象代表A类
* A a = new A(); 产生一个A类的对象
* */
/*
* 栈
* Main()
* m=0
* */

2.11 When does class initialization occur?

  • Active reference of the class (initialization of the class must occur)
    • When the virtual machine starts, first initialize the class where the main method is located.
    • new an object of a class
    • Call static members (except final constants) and static methods of the class
    • Use the methods of the java.lang.reflect package to make reflective calls to the class
    • When initializing a class, if its parent class has not been initialized, its parent class will be initialized first.
  • Passive reference to the class (no initialization of the class occurs)
    • When a static field is accessed, only the class that actually declared the field will be initialized. For example: when referencing a static variable of a parent class through a subclass, it will not cause the subclass to be initialized.
    • Defining a class reference through an array will not trigger the initialization of this class
    • Reference constants will not trigger initialization of this type (constants are stored in the constant pool of the calling class during the link phase)
//测试类什么时候会初始化
public class Test06 {
    
    
    static {
    
    
        System.out.println("Main类被加载");
    }

    public static void main(String[] args) throws ClassNotFoundException {
    
    
        //1. 主动引用
        Son son = new Son();//Main类被加载 父类被加载 子类被加载
        //反射也会产生主动引用
        Class.forName("com.annotation.demo02.Son");//Main类被加载 父类被加载 子类被加载

        //2. 被动引用
        //不会产生类的引用的方法
        System.out.println(Son.b);//2
        Son[] array = new Son[5];
        System.out.println(Son.M);
    }
}

class Father {
    
    
    static int b = 2;

    static {
    
    
        System.out.println("父类被加载");
    }
}

class Son extends Father {
    
    
    static {
    
    
        System.out.println("子类被加载");
        m = 300;
    }

    static int m = 100;
    static final int M = 1;

2.12 The role of class loader

  • The role of class loading: loads the bytecode content of the class file into memory, converts these static data into runtime data structures in the method area, and then generates a java.lang.Class object representing this class in the heap, as Access entrance to class data in the method area.
  • Class caching: The standard JavaSE class loader can look up classes on request, but once a class is loaded into the class loader, it will remain loaded (cached) for a period of time. However, the JVM garbage collection mechanism can recycle these Class objects.

2.13 The role of class loader

The class loader is used to load classes into memory. The JVM specification defines loaders for the following types of classes.

  • The boot class loader, written in C++, is the class loader that comes with the JVM. It is responsible for the Java platform core library and is used to load the core class library. This loader cannot be obtained directly.
  • Extension class loader: Responsible for loading the jar packages in the jre/lib/ext directory or the jar packages in the directory specified by -D java.ext.dirs into the working library.
  • System class loader: Responsible for loading classes and jar packages in the directory pointed to by java -classpath or -D java.class.path. It is the most commonly used loader.
public class Test07 {
    
    
    public static void main(String[] args) throws ClassNotFoundException {
    
    
        //获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
        //获取系统类加载器的父类加载器-->扩展类加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);
        //获取拓展类加载器的父类加载器-->根加载器(C/C++)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);
        //sun.misc.Launcher$AppClassLoader@18b4aac2
        //sun.misc.Launcher$ExtClassLoader@14ae5a5
        //null

        //测试当前类是哪个加载器加载的
        ClassLoader classLoader = Class.forName("com.annotation.demo02.Test07").getClassLoader();
        System.out.println(classLoader);
        //测试JDK内置的类是谁加载的
        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1);
        //如何获得系统类加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
        //双亲委派机制
        //java.lang.String-->

        ///Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/charsets.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/deploy.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/dnsns.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/jaccess.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/localedata.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/nashorn.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/sunec.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/ext/zipfs.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/javaws.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/jce.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/jfr.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/jfxswt.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/jsse.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/management-agent.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/plugin.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/resources.jar:
        // /Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/rt.jar:
        // /Users/xay/Desktop/编程/JAVA-FullStack/JavaSE/out/production/JavaBasics:/Users/xay/Desktop/编程/JAVA-FullStack/JavaSE/JavaBasics/src/com/yuan/lib/commons-io-2.11.0.jar:
        // /Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar
    }
}

3. Create objects of runtime classes

Java.Reflection

3.1 Get the complete structure of the runtime class

Obtain the complete structure of the runtime class through reflection

Field、Method、Constructor、Superclass、Interface、Annotation

  • All interfaces implemented
  • Inherited parent class
  • All constructors
  • all methods
  • AllFields
  • annotation
  • ···
//获得类的信息
public class Test08 {
    
    
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
    
    
        Class c1 = Class.forName("com.annotation.demo02.User");
        User user = new User();
        Class c2 = user.getClass();
        //获得类的名字
        System.out.println(c2.getName());//获得包名加类名
        System.out.println(c2.getSimpleName());//获得类名

        //获得类的属性
        Field[] fields = c1.getFields();//只能找到public属性
        for (Field field : fields) {
    
    
            System.out.println(field);
        }
        fields = c1.getDeclaredFields();//找到全部的属性
        for (Field field : fields) {
    
    
            System.out.println(field);
        }
        //获得指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);

        //获取类的方法
        Method[] methods = c1.getMethods(); //获得本类及其父类的全部public方法
        for (Method method : methods) {
    
    
            System.out.println("正常的" + method);
        }
        methods = c1.getDeclaredMethods(); //获得本类的所有方法
        for (Method method : methods) {
    
    
            System.out.println("getDeclaredMethods" + method);
        }

        //获得指定的方法
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        //获得指定的构造器
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {
    
    
            System.out.println("#" + constructor);
        }
        Constructor[] declaredConstructors = c1.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
    
    
            System.out.println(declaredConstructor);
        }
        //获得指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println("指定" + declaredConstructor);
    }
}

3.2 Summary

  • In actual operations, the operation code to obtain class information is not often developed.
  • You must be familiar with the function of the java.lang.reflect package and the reflection mechanism.
  • How to get the names, modifiers, etc. of properties, methods, constructors, etc.

3.3 What can you do with the Class object?

  • Create an object of the class: call the newlnstance() method of the Class object
    1. The class must have a parameterless constructor.
    2. The access rights of the constructor of the class need to be sufficient

think? Isn't it possible to create an object without a parameterless constructor? As long as the constructor in the class is explicitly called during operation and the parameters are passed in, the operation can be instantiated.

  • Proceed as follows:
    1. Obtain the constructor of the specified formal parameter type of this class through getDeclaredConstructor(Class...parameterTypes) of the Class class
    2. Pass an object array to the formal parameter in the constructor, which contains the various parameters required in the constructor.
    3. Instantiate objects through Constructor
//动态的创建对象,通过反射
public class Test09 {
    
    
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
    
    
        //获得Class对象
        Class c1 = Class.forName("com.annotation.demo02.User");
        //构造一个对象
        User user = (User) c1.newInstance();//调用了类的无参构造器
        System.out.println(user);//User{name='null', id=0, age=0}

        //通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User xay = (User)constructor.newInstance("xay", 001, 19);
        System.out.println(xay);

        //通过反射调用普通方法
        User user3 = (User) c1.newInstance();
        //通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //invoke:激活的意思
        //(对象,"方法的值")
        setName.invoke(user3,"蔡梦佳");
        System.out.println(user3.getName());
        //通过反射操作属性
        User user4 = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        //不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true)
        name.setAccessible(true);
        name.set(user4,"cmj");
        System.out.println(user4.getName());
    }
}

3.4 Call the specified method

Through reflection, calling methods in the class is completed through the Method class.

  1. Obtain a Method object through the getMethod(String name, Class...parameterTypes) method of the Class class, and set the parameter types required for this method operation.
  2. Then use Object invoke(Object obj,Object[] args) to make the call and pass the parameter information of the obj object to be set to the method.

Object invoke(Object obj,Object… args)

  • Object corresponds to the return value of the original method. If the original method has no return value, null is returned at this time.
  • If the original method is a static method, the formal parameter Object obj can be null.
  • If the original method parameter list is empty, Object[] args is null.
  • If the original method is declared as private, you need to display the setAccessible(true) method of the calling method object before calling this invoke() method, so that the private method can be accessed.

setAccessible

  • Method, Field, and Constructor objects all have setAccessible() methods.
  • The function of setAccessible is to enable and disable the access security check switch.
  • A parameter value of true indicates that the reflected object should cancel Java language access checks when used.
    • Improve reflection efficiency. If reflection must be used in the code and the code needs to be called frequently, please set it to true.
    • Make private members that are otherwise inaccessible also accessible
  • A parameter value of false indicates that the reflected object should implement Java language access checks.

3.5 Performance comparison analysis

//分析性能问题
public class Test10 {
    
    
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
    
    
        test01();
        test02();
        test03();
    }
    //普通方式调用
    public static void test01() {
    
    
        User user = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
    
    
            user.getName();
        }
        long endTime = System.currentTimeMillis();

        System.out.println("普通方式执行10亿次:" + (endTime - startTime) + "ms");
    }
    //反射方式调用
    public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    
    
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
    
    
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();

        System.out.println("反射方式执行10亿次:" + (endTime - startTime) + "ms");
    }
    //反射方式调用 关闭检查
    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    
    
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        getName.setAccessible(true);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
    
    
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();

        System.out.println("关闭检测执行10亿次:" + (endTime - startTime) + "ms");
    }
//普通方式执行10亿次:5ms
//反射方式执行10亿次:3324ms
//关闭检测执行10亿次:1464ms

}

3.6 Reflection operation on generics

  • Java uses the generic erasure mechanism to introduce generics. Generics in Java are only used by the compiler javac to ensure data security and avoid forced type conversion problems. However, once the compilation is completed, all generics Erase all relevant types
  • In order to operate these types through reflection, Java has added ParameterizedType, Generic ArrayType, TypeVariable and WildcardType to represent types that cannot be classified into the Class class but have the same name as the original type.
  • ParameterizedType: represents a parameterized type, such as Collection
  • GenericArrayType: represents an array type whose element type is a parameterized type or type variable
  • TypeVariable: is the common parent interface for various types of variables
  • WildcardType: represents a wildcard type expression
//通过反射获取泛型
public class Test11 {
    
    
    public void test01(Map<String, User> map, List<User> list) {
    
    
        System.out.println("test01");
    }

    public Map<String, User> test02() {
    
    
        System.out.println("test02");
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {
    
    
        Method method = Test11.class.getMethod("test01", Map.class, List.class);
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
    
    
            System.out.println("#" + genericParameterType);
            if(genericParameterType instanceof ParameterizedType){
    
    
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
    
    
                    System.out.println(actualTypeArgument);
                }
            }
        }

        method = Test11.class.getMethod("test02", null);
        Type genericReturnType = method.getGenericReturnType();
        if(genericReturnType instanceof ParameterizedType){
    
    
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
    
    
                System.out.println(actualTypeArgument);
            }
        }

    }
}

3.7 Reflection operation annotations

  • getAnnotations
  • getAnnotation

Exercise: ORM

  • Do you know what an ORM is?

    • Object relationship Mapping—>Object relationship mapping

    • Class and table structure correspondence

    • Correspondence between attributes and fields

    • Object and record correspondence

  • Requirement: Use annotations and reflection to complete the mapping relationship between classes and table structures

//练习反射操作注解
public class Test12 {
    
    
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
    
    
        Class c1 = Class.forName("com.annotation.demo02.Student2");
        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
    
    
            System.out.println(annotation);
        }
        //获得注解的value值
        Tableyuan tableyuan = (Tableyuan)c1.getAnnotation(Tableyuan.class);
        String value = tableyuan.value();
        System.out.println(value);

        //获得类指定的注解
        Field f = c1.getDeclaredField("id");
        Fieldyuan annotation = f.getAnnotation(Fieldyuan.class);
        System.out.println(annotation.colomnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }
}
@Tableyuan("db_student")
class Student2{
    
    
    @Fieldyuan(colomnName = "db_id",type = "int" ,length = 10)
    private int id;
    @Fieldyuan(colomnName = "db_age",type = "int" ,length = 10)
    private int age;
    @Fieldyuan(colomnName = "db_name",type = "varchar" ,length = 3)
    private String name;
    public Student2(){
    
    

    }

    public Student2(int id, int age, String name) {
    
    
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

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

    @Override
    public String toString() {
    
    
        return "Student2{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Tableyuan{
    
    
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldyuan{
    
    
    String colomnName();
    String type();
    int length();
}

Guess you like

Origin blog.csdn.net/weixin_42823298/article/details/128893175