注解和反射

注解和反射

注解

  • 机器可以识别,和注释不同,注释是给人看的

  • 内置注解

    一共三种@Override,@Deprecated,@SuppressWarnings()

    @SuppressWarnings("")
    public class Test01 extends Thread{
        
        //重写父类方法
        @Override
        public void run() {
            super.run();
        }
        
        //废弃,可以用但不建议
        @Deprecated
        public void say(){
            
        }
        
        //去掉提醒
        @SuppressWarnings("all")
        public void play(){
            int i = 0;
        }
    }
    
  • 元注解

  • 注解其他的注解,解释说明其他注解

    1. Target表示该注解的作用范围
    2. Retention表示该注解的有效的敌方,source表示只在源码生效,一般用runtime,运行时
    3. Documented表示是否将注解记录在javadoc中
    4. Inherited表示注解是否可被继承
    package com.zhm.annotation;
    
    import java.lang.annotation.*;
    
    @MyAnnotation
    public class Test02 {
        @MyAnnotation
        public static void main(String[] args) {
    
        }
    }
    
    //Target表示该注解的作用范围
    @Target(value = {ElementType.TYPE,ElementType.METHOD})
    //Retention表示该注解的有效的敌方,source表示只在源码生效,一般用runtime,运行时
    //Runtime>class>source
    @Retention(value = RetentionPolicy.RUNTIME )
    //Documented表示是否将注解记录在javadoc中
    @Documented
    //Inherited表示注解是否可被继承
    @Inherited
    @interface MyAnnotation{
    }
    
  • 自定义注解

    package com.zhm.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    public class Test03 {
        @MyAnnotation2(name3 = {"牛逼","牛逼在哪"},age3 = 1)
        public static void main(String[] args) {
    
        }
    }
    
    @Target({ElementType.TYPE,ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation2{
        //注解的参数: 参数类型 + 参数名 +()
        //加default可以初始化默认值
        //如果参数只有一个,可以用value命名,调用时可以省略value
        String name() default "zza";
        String[] name2() default "azaz";
        String[] name3();
        int age() default 0;
        int age2() default -1;
        int age3();
    }
    

反射

基本概念

  • JavaScript,Python为动态语言

  • java,c,c++为静态语言

  • 动态和静态语言区别在于运行时,代码可以根据某种条件改变自身结构

  • java通过反射可以称为”准动态语言“

  • image-20241204114021739

  • 一个类在内存中只有一个Class对象

  • 一个类被加载后,类的整个结构都会封装在Class对象中

    package com.zhm.reflection;
    
    public class Test01 {
        public static void main(String[] args) throws ClassNotFoundException {
            Class aClass = Class.forName("com.zhm.reflection.Student");
            System.out.println(aClass);
    
            Class aClass1 = Class.forName("com.zhm.reflection.Student");
            Class aClass2 = Class.forName("com.zhm.reflection.Student");
            Class aClass3 = Class.forName("com.zhm.reflection.Student");
            System.out.println(aClass1.hashCode());
            System.out.println(aClass2.hashCode());
            System.out.println(aClass3.hashCode());
    
        }
    
    }
    
    //实体类
    class Student{
        private int age;
        private String name;
    
        public Student() {
        }
    
        public Student(int age, String name) {
            this.age = age;
            this.name = name;
        }
    
        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 super.toString();
        }
    }
    

获得Class对象方法

  • package com.zhm.reflection;
    
    public class Test02 {
        public static void main(String[] args) throws ClassNotFoundException {
            //三种获得类的Class对象
            //1用一个类的对象.getclass
            Person person = new Teacher();
            Class<? extends Person> c1 = person.getClass();
            System.out.println(c1.hashCode());
    
            //2用Class.forName(类的路径)
            Class<?> c2 = Class.forName("com.zhm.reflection.Teacher");
            System.out.println(c2.hashCode());
    
            //3用类名.class
            Class<Teacher> c3 = Teacher.class;
            System.out.println(c3.hashCode());
    
            //补充4基本类型的包装类内置Type属性
            Class<Integer> c4 = Integer.TYPE;
            System.out.println(c4);
    
            //获得父类类型
            Class<?> c5 = c1.getSuperclass();
            System.out.println(c5);
    
        }
    }
    
    class Person{
        String name;
    
        public Person() {
        }
    
        public Person(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    
    class Teacher extends Person{
        public Teacher() {
            this.name = "teacher";
        }
    }
    
    class Fucker extends Person{
        public Fucker() {
            this.name = "fucker";
        }
    }
    

所有类型的Class对象

package com.zhm.reflection;

import java.lang.annotation.ElementType;

public class Test03 {
    public static void main(String[] args) {
        //所有类型的Class对象
        Class<Object> c1 = Object.class;//类
        Class<String[]> c2 = String[].class;//一维数组
        Class<int[][]> c3 = int[][].class;//二维数组
        Class<Runnable> c4 = Runnable.class;//接口
        Class<Override> c5 = Override.class;//注解
        Class<Void> c6 = void.class;//void
        Class<Integer> c7 = Integer.class;//基本数据类型
        Class<ElementType> c8 = ElementType.class;//enum类型
        Class<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());
        System.out.println(b.getClass().hashCode());

    }
}

类加载内存分析

image-20241204165217108

package com.zhm.reflection;

public class Test04 {
    public static void main(String[] args) {
        /*
        三个阶段
        1.加载,在方法区加载Test04类和A类的数据(静态变量,静态方法,常量池子,代码)
        在堆中创建一个java.lang.Class类对象代表Test04类,一个java.lang.Class类对象代表A类
        Class对象代表类的结构
        2.链接,在栈中分配内存,创建静态对象,初始化(m=0)
        运行main方法
        A a,创建A类对象a,a找到A类Class对象,对a的相关数据修改赋值
        3.初始化,jvm调用
        <clinut>(){
            System.out.println("我是A的静态代码块");
            m = 20;
            m = 10;
        }
        合并static代码,执行,m=10
         */

        A a = new A();
        System.out.println(a.m);
    }
}

class A{
    static {
        System.out.println("我是A的静态代码块");
        m = 20;
    }

    static int m = 10;

    public A() {
        System.out.println("我是A的无参构造");
    }
}

类的初始化的情况

package com.zhm.reflection;

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

    public static void main(String[] args) throws ClassNotFoundException {
        //主动引用
        //1new一个对象,会加载子类,如果父类没被加载,则先父再子
//        Son son = new Son();
        //2通过反射,会加载子类,如果父类没被加载,则先父再子
//        Class<?> c1 = Class.forName("com.zhm.reflection.Son");

        //不会产生类的引用
        //1调用静态方法或者静态变量,只会加载定义静态的类
//        System.out.println(Son.age);
        //2创建对象数组,不会加载类,本质只是开个空间进行命名
//        Son[] sons = new Son[10];
        //3调用常量,也不会加载类,因为常量在链接阶段已经调入常量池中
        System.out.println(Son.M);


    }
}

class Father{
    static int age = 10;
    static {
        System.out.println("父类被加载");
    }
}

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

    static final int M = 19;
}

类加载器

  • 类加载器(装载器)把字节码文件加载到内存,把静态数据放入方法区中

    image-20241206170450016

  • 类加载器jvm规定三个类型

    1. 引导类加载器,最底层,c++编写,jvm自带用来装载核心类库rt.jar,无法直接获取
    2. 扩展类加载器,jre/lib/ext等扩展类的加载器
    3. 系统类(用户类)加载器,用户定义,java.class.path目录,是最常用的

    image-20241206170916815

    package com.zhm.reflection;
    
    public class Test06 {
        public static void main(String[] args) throws ClassNotFoundException {
            //获得系统加载器(用户)
            ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
            System.out.println(systemClassLoader);
    
            //获得系统加载器父类加载器,拓展类加载器
            ClassLoader parent = systemClassLoader.getParent();
            System.out.println(parent);
    
            //获得扩展类加载器父类,根加载器
            ClassLoader parent1 = parent.getParent();
            System.out.println(parent1);
    
            //测试当前类用哪个类加载器加载
            //用户自定义类会用系统加载器
            ClassLoader classLoader = Class.forName("com.zhm.reflection.Test06").getClassLoader();
            System.out.println(classLoader);
    
            //jdk内置(lang包)的类会用根加载器
            ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
            System.out.println(classLoader1);
    
            //获取类加载器可以加载的路径
            //在路径内才能加载
            System.out.println(System.getProperty("java.class.path"));
            /*
            F:\Environment\java\jdk1.8\jre\lib\charsets.jar;
            F:\Environment\java\jdk1.8\jre\lib\deploy.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\cldrdata.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\dnsns.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\jaccess.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\jfxrt.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\localedata.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\nashorn.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\sunec.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\sunmscapi.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;
            F:\Environment\java\jdk1.8\jre\lib\ext\zipfs.jar;
            F:\Environment\java\jdk1.8\jre\lib\javaws.jar;
            F:\Environment\java\jdk1.8\jre\lib\jce.jar;
            F:\Environment\java\jdk1.8\jre\lib\jfr.jar;
            F:\Environment\java\jdk1.8\jre\lib\jfxswt.jar;
            F:\Environment\java\jdk1.8\jre\lib\jsse.jar;
            F:\Environment\java\jdk1.8\jre\lib\management-agent.jar;
            F:\Environment\java\jdk1.8\jre\lib\plugin.jar;
            F:\Environment\java\jdk1.8\jre\lib\resources.jar;
            F:\Environment\java\jdk1.8\jre\lib\rt.jar;
            F:\ava\project\annotation and reflect\out\production\annotation and reflect;
            F:\ava\programs\IntelliJ IDEA 2022.3.1\lib\idea_rt.jar
    
             */
        }
    }
    

    双亲委派机制

    自己定义的类和jdk官方定义的类同名,会向上(父类)一步一步检测有没有相同类,为了安全性,有相同就不会用自己定义的

通过类的Class对象获取类的所有信息

  • 可以获取类的属性,方法,构造器,等等

    package com.zhm.reflection;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class Test07 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
            Class<?> c1 = Class.forName("com.zhm.reflection.Student");
    
            //获得包名+类名
            System.out.println(c1.getName());
            //获得类名
            System.out.println(c1.getSimpleName());
    
            Test01.fgx();
    
            //获得public属性
            Field[] fields = c1.getFields();
            for (Field field : fields) {
                System.out.println(field);
            }
            //获得全部属性,包括私有属性
            fields = c1.getDeclaredFields();
            for (Field field : fields) {
                System.out.println(field);
            }
            //获得指定属性
            System.out.println(c1.getDeclaredField("name"));
    
            Test01.fgx();
    
            //获得全部public方法,包括父类的
            Method[] methods = c1.getMethods();
            for (Method method : methods) {
                System.out.println(method);
            }
            //获得全部方法包括私有,不包括父类
            methods = c1.getDeclaredMethods();
            for (Method method : methods) {
                System.out.println(method);
            }
            //获得指定方法,传入方法名和参数类型的类的Class对象
            System.out.println(c1.getDeclaredMethod("getAge",null));
            System.out.println(c1.getDeclaredMethod("setAge", int.class));
    
            Test01.fgx();
    
            //获得public构造器
            Constructor<?>[] constructors = c1.getConstructors();
            for (Constructor<?> constructor : constructors) {
                System.out.println(constructor);
            }
            //获得全部构造器,包括private
            constructors = c1.getDeclaredConstructors();
            for (Constructor<?> constructor : constructors) {
                System.out.println(constructor);
            }
            //获得指定构造器
            System.out.println(c1.getDeclaredConstructor(int.class, String.class));
            
    
        }
    }
    

通过类的Class对象动态创建对象执行方法

  • 创建对象
    1. c1.newInstance方法,本质无参
    2. 通过c1获取有参构造,newInstance方法传入初始化值
  • 获取方法
    1. 通过c1创建对象,直接调用非private
    2. 通过c1创建对象,再通过c1获取方法,再用invoke方法
  • 获取字段
    1. 通过c1创建对象,直接获取非private
    2. 通过c1创建对象,再通过c1获取字段,再用set方法
  • 如果想要获取private的属性和方法和构造器,需要setAccessible方法设置为true,关闭安全检测开关
package com.zhm.reflection;

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

public class Test08 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class<?> c1 = Class.forName("com.zhm.reflection.Student");

        //通过学生类的Class对象,创建学生类的对象
        //1 本质是调用无参构造
        Student s1 = (Student) c1.newInstance();
        System.out.println(s1);
        //2 通过Class对象获取有参构造,再调用newInstance
        Constructor<?> constructor = c1.getDeclaredConstructor(int.class, String.class);
        Student s2 = (Student) constructor.newInstance(10,"xiaoming");
        System.out.println(s2);

        //通过Class对象获取方法
        Student s3 = (Student) c1.newInstance();
        Method setAge = c1.getDeclaredMethod("setAge", int.class);
        setAge.invoke(s3,101);
        System.out.println(s3.getAge());

        //通过Class对象获取,修改数据
        Student s4 = (Student) c1.newInstance();
        Field name = c1.getDeclaredField("name");

        name.setAccessible(true);
        name.set(s4,"xiaohong");
        System.out.println(name.get(s4));
        System.out.println(s4.getName());
    }
}

反射和普通方法效率对照

package com.zhm.reflection;

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

public class Test09 {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        test01();
        test02();
        test03();
    }

    public static void test01(){
        long startTime = System.currentTimeMillis();
        Student student = new Student();
        for (int i = 0; i < 10_0000_0000; i++) {
            student.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通执行10亿次需要"+(endTime-startTime)+"ms");
    }

    public static void test02() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        long startTime = System.currentTimeMillis();
        Student student = new Student();
        Class<Student> c1 = Student.class;
        Method getName = c1.getDeclaredMethod("getName", null);
        for (int i = 0; i < 10_0000_0000; i++) {
            getName.invoke(student,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射执行10亿次需要"+(endTime-startTime)+"ms");
    }

    public static void test03() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        long startTime = System.currentTimeMillis();
        Student student = new Student();
        Class<Student> c1 = Student.class;
        Method getName = c1.getDeclaredMethod("getName", null);
        getName.setAccessible(true);
        for (int i = 0; i < 10_0000_0000; i++) {
            System.out.println(getName.invoke(student, null));
        }
        long endTime = System.currentTimeMillis();
        System.out.println("关闭安全检查的反射执行10亿次需要"+(endTime-startTime)+"ms");
    }
}

通过反射获得泛型

  • getGenericParameterTypes 获得泛型传入参数类型
  • ParameterizedType 参数化类型(Collection
  • getActualTypeArgument 获得实际类型参数
  • getGenericReturnType 获得泛型返回类型
package com.zhm.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 Test10 {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<Test10> c1 = Test10.class;
        Method method = c1.getDeclaredMethod("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 = c1.getDeclaredMethod("test02");
        Type genericParameterType = method.getGenericReturnType();
        System.out.println(genericParameterType);
        if (genericParameterType instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }


    }

    public void test01(Map<String,Student> map, List<Student> list){
        System.out.println("test01");
        return;
    }

    public List<Student> test02(){
        System.out.println("test02");
        return null;
    }

}

反射注解结合,通过反射获取注解信息

package com.zhm.reflection;

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

public class Test11 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> c1 = Class.forName("com.zhm.reflection.Student2");
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        Tablezhu annotation = (Tablezhu) c1.getAnnotation(Tablezhu.class);
        String value = annotation.value();
        System.out.println(value);

        Field name = c1.getDeclaredField("name");
        Annotation[] annotation1 = name.getAnnotations();
        for (Annotation annotation2 : annotation1) {
            System.out.println(annotation2);
        }
        Fieldzhu annotation2 = (Fieldzhu) name.getAnnotation(Fieldzhu.class);
        System.out.println(annotation2.cloumnName());
        System.out.println(annotation2.length());
        System.out.println(annotation2.type());


    }
}

//定义实体类
@Tablezhu("db_Student")
class Student2{
    @Fieldzhu(length = 10,cloumnName = "db_age",type = "int")
    private int age;
    @Fieldzhu(length = 10,cloumnName = "db_id",type = "int")
    private int id;
    @Fieldzhu(length = 3,cloumnName = "db_name",type = "String")
    private String name;

    public Student2() {
    }

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

    public int getAge() {
        return age;
    }

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

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

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

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

posted @ 2025-04-22 22:08  学习java的白菜  阅读(7)  评论(0)    收藏  举报