Java 注解和反射 学习笔记(2021.10.19)

注解和反射

一、什么是注解

注解(Annotation)作用:可以被其他驱动读取;对代码做出解释(这一点和注释没有区别)

注解结构:以@开头

注解在哪里使用:方法、类、字段、包等地方使用

例子:如

public class Demo01 extends Object {
    public static void main(String[] args) {
        
    }

    @Override
    public String toString() {
        return super.toString();
    }
}

二、内置注解

  • @Deprecated:不推荐使用,可能有危险或者更好的选择
  • @SuppressWornings:镇压警告,把警告变成正常

三、元注解

元注解负责注解其他注解,有四个:

  • @Target:用于描述注解的使用范围(即:别描述的注解可以用在什么地方
  • @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期
    • (SOURCE<CLASS<RUNTIME)
  • @Documented:是否这个注解在生成文档上生成
  • @Inherited:表示这个注解是否能被继承

Demo:

@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Inherited
@interface MyAnnotation{

}

四、自定义注解

package com.xiaowei9s.annotation;

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

public class Demo03 {
    @MyAnnotation1(name = "xiaowei",id = 15)
    public void test(){}

    @MyAnnotation2()
    public void test1(){}
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation1{
    String name();
    int age() default 18;//有默认值的情况下在使用注解的时候可以不必要输入值
    int id();
    String[] hobby() default {"打乒乓球","打篮球"};
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    String name() default "";
    int age() default 18;//有默认值的情况下在使用注解的时候可以不必要输入值
    int id() default -1;
    String[] hobby() default {"打乒乓球","打篮球"};
}

五、反射概述

动态语言:JavaScript,动态语言可以在运行的时候可以改变自身结构的。

静态语言:C/C++,Java(准动态,利用反射机制,却有些不安全)

image

优点:

实现动态创建对象和编译,灵活性强

缺点:

对性能有影响,因为是解释操作

六、获得反射对象

package com.xiaowei9s.reflection;

//什么叫反射
public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("com.xiaowei9s.reflection.User");
        Class c2 = Class.forName("com.xiaowei9s.reflection.User");
        Class c3 = Class.forName("com.xiaowei9s.reflection.User");
        Class c4 = Class.forName("com.xiaowei9s.reflection.User");

        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());

    }
}

class User{
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    String name;
    int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

七、得到Class类的几种方式

image

image

获取Class实例:

package com.xiaowei9s.reflection;

//如何获得Class类的实例
public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException {
        Student stu = new Student();
        //方式一,变量名.getClass()
        Class c1 = stu.getClass();
        System.out.println(c1.hashCode());

        //方式二,类名.class
        Class c2 = Student.class;
        System.out.println(c2.hashCode());

        //方式三,forName()
        Class c3 = Class.forName("com.xiaowei9s.reflection.Student");
        System.out.println(c3.hashCode());

        //方式四,只有包装类有,TYPE
        Class c4 = Integer.TYPE;
        System.out.println(c4.hashCode()+" "+c4);

        //获取类的结构
        System.out.println(c1.getName());
        System.out.println(c1.getDeclaredFields());
        System.out.println(c1.getSuperclass());

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

八、所有类型的Class对象

  • 接口
  • 数组
  • 枚举
  • 注解
  • 基本数据类型
  • void
package com.xiaowei9s.reflection;

import java.lang.annotation.ElementType;

public class Demo03 {
    public static void main(String[] args) {
        Class c1 = String.class;
        Class c2 = Runnable.class;
        Class c3 = Override.class;
        Class c4 = String[].class;
        Class c5 = String[][].class;
        Class c6 = ElementType.class;
        Class c7 = void.class;
        Class c8 = Class.class;
        Class c9 = int.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);

        //只要类型一致,就是同一个hashCode,获得同一个Class类
        int[] ints = new int[100];
        int[] ints1 = new int[10];
        System.out.println(ints.getClass().hashCode());
        System.out.println(ints1.getClass().hashCode());
    }
}

九、类加载内存分析

类加载器理解:

image

package com.xiaowei9s.reflection;

public class Demo04 {
    public static void main(String[] args) {
        System.out.println("main方法");
        A a = new A();
        System.out.println(a.m);//m = 100
        /*
            1. 在静态方法区内存中加载Demo04类的静态变量方法等。。
            2. 在静态方法区内存中加载A类的静态方法区中的变量。
            3. 在堆中分别建立Demo04、A类的Class对象。
            4. 初始化:
                <clinit>(){//合并静态代码
                    System.out.println("静态代码");
                    m = 300;
                    m = 100;
                }
            5. 执行main方法

        */

    }
}
class A{

    static {
        System.out.println("静态代码");
        m = 300;
    }

    static int m = 100;

    public A(){
        System.out.println("构造代码");
    }

}

十、分析类初始化

image

package com.xiaowei9s.reflection;

import java.sql.SQLOutput;

public class Demo05 {
    static {
        System.out.println("Main被加载");
    }

    public static void main(String[] args) throws ClassNotFoundException {
        //主动引用
        //Son son = new Son();

        //反射加载类
        //Class.forName("com.xiaowei9s.reflection.Son");

        //数组使用
        Son[] sons = new Son[10];

        //访问常量
        System.out.println(Son.M);

        //访问静态变量
        System.out.println(Son.i);
    }
}

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

}
class Father{
    static int i = 10;
    static {
        System.out.println("父类被加载");
        i = 20;
    }
    static final int M = 5;

}

十一、类加载器

image

package com.xiaowei9s.reflection;

public class Demo06 {
    public static void main(String[] args) {
        //获取系统类的加载器
        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);

        //测试当前类是哪个加载器加载的
        ClassLoader classLoader = Demo06.class.getClassLoader();
        System.out.println(classLoader);

        //测试JDK内置类是哪个类加载的
        ClassLoader classLoader1 = Object.class.getClassLoader();
        System.out.println(classLoader1);

        //如何获得系统类加载器可加载的路径
        System.out.println(System.getProperty("java.class.path"));
    }
}

十二、获取类的运行结构

image

package com.xiaowei9s.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Demo07 {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
        Class c1 = User.class;

        //获得类的属性
        Field[] declaredFields = c1.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        declaredFields = c1.getFields();//只有public,方法和构造方法同理
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        Field name = c1.getDeclaredField("name");//获得指定的字段
        System.out.println(name);

        //获得类的方法
        Method[] declaredMethods = c1.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        Method setName = c1.getDeclaredMethod("setName", String.class);
        System.out.println(setName);//获得指定方法

        //获得类构造器
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        //获得指定构造器方法同上
    }
}

十三、动态创建对象执行方法

package com.xiaowei9s.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo08 {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class c1 = User.class;

        //通过反射创建对象
        //User u = (User) c1.newInstance();//如果没有空构造器则不能使用这个方法构造对象
        //System.out.println(u);

        //通过获取构造器创建对象
        Constructor constructor = c1.getConstructor(String.class, int.class);
        User u = (User) constructor.newInstance("xiaowei", 18);
        System.out.println(u);

        //通过反射获取方法
        Method getName = c1.getDeclaredMethod("getName");
        System.out.println(getName.invoke(u));//invoke是激活的意思

        //通过反射来操纵属性
        Field name = c1.getDeclaredField("name");
        name.setAccessible(true);
        name.set(u,"xiaowei9s");//私有无法直接操纵
        System.out.println(getName.invoke(u));
    }
}

十四、性能对比分析

package com.xiaowei9s.reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;

public class Demo09 {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        test01();
        test02();
        test03();
    }
    //普通方法
    private static void test03() {
        User user = new User("1", 1);
        long stime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long etime = System.currentTimeMillis();
        System.out.println("普通方法访问10亿次用时"+(etime-stime)+"ms");
    }
    //反射方法
    private static void test02() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        User user = new User("1", 1);
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName");
        long stime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user);
        }
        long etime = System.currentTimeMillis();
        System.out.println("反射方法访问10亿次用时"+(etime-stime)+"ms");
    }
    //关闭检测
    private static void test01() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        User user = new User("1", 1);
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName");
        getName.setAccessible(true);
        long stime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user);
        }
        long etime = System.currentTimeMillis();
        System.out.println("关闭检测访问10亿次用时"+(etime-stime)+"ms");
    }
}

十五、获取泛型信息

package com.xiaowei9s.reflection;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class Demo10 {
    public Map<String,User> test01(Map<String,User> map){
        return null;
    }
    public Map<String,User> test02(List<String> list,Map<String,User> map){
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {
        Class<Demo10> c1 = Demo10.class;
        //获取方法内参数的泛型
        Method test01 = c1.getDeclaredMethod("test01", Map.class);
        Type[] genericParameterTypes = test01.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 test02 = c1.getDeclaredMethod("test02", List.class, Map.class);
        Type genericParameterTypes1 = test02.getGenericReturnType();
        if (genericParameterTypes1 instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericParameterTypes1).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }





    }
}

十六、获取注解信息

package com.xiaowei9s.reflection;

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

public class Demo11 {
    public static void main(String[] args) throws NoSuchFieldException {
        Class c1 = Student1.class;
        TableWei annotation = (TableWei) c1.getAnnotation(TableWei.class);
        System.out.println(annotation.value());

        Field name = c1.getDeclaredField("name");
        Annotation[] annotations =name.getAnnotations();
        for (Annotation fieldWei : annotations) {
            FieldWei f = (FieldWei) fieldWei;
            System.out.println(f.colName());
            System.out.println(f.length());
            System.out.println(f.type());
        }

    }
}

@TableWei("db_stu")
class Student1{
    @FieldWei(colName = "id",type = "int",length = 10)
    private int id;
    @FieldWei(colName = "age",type = "int",length = 3)
    private int age;
    @FieldWei(colName = "name",type = "String",length = 10)
    private String 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;
    }

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

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

@Target(value = ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableWei{
    String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldWei{
    String colName();
    String type();
    int length();
}

知识来源:kuangstudy.com

posted @ 2021-10-19 22:40  小阴辨  阅读(48)  评论(0)    收藏  举报