注解和反射详解

一、注解

  1. 注解(Annotation)的作用:可以被其他程序(比如:编译器)读取。
    @Override 重写注解
    @Deprecated 表示不鼓励使用或者已经废弃,通常是因为它很危险或者存在更好的方法
    @SuppressWarnings 用来抑制编译时的警告信息,传入“all”抑制所有警告

二、元注解

元注解的作用:负责注解其他注解(禁止套娃。。。

@Target 表示我们的注解可以用在哪些地方
@Retention 表示我们的注解在什么地方有效 runtime>class>sources 默认RUNTIME
@Documented 表示是否将我们的注解生成在Javadoc中
@Inherited 表示子类可以继承父类的注解

三、自定义注解

使用 @interface自定义注解,自动继承Annotation接口

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotarion{
    //注解的参数:参数类型 + 参数名 ();
    String value() default "";//参数名为value时,传参时可以省略value = ,不传参时,则为default默认值
}

四、反射

正常方式:引入需要的“包类”名称–>通过new实例化–>取得实例对象

加载类完成后,在堆内存的方法区就产生了一个Class类型对象,这个对象包含了完整的类的结构信息,可以通过这个对象看到类的结构

反射方式:实例化对象–>getClass()方法–>得到完整的“包类”名称

public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //通过反射获取类的class对象
        Class c1 = Class.forName("Reflection.Person");
        System.out.println(c1);

        //一个类在内存中只有一个class对象
        //一个类被加载后,类的整个结构都会被封装在Class对象中
        Class c2 = Class.forName("Reflection.Person");
        Class c3 = Class.forName("Reflection.Person");
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());

    }
}
class Person{
    private String name;
    private int id;

    public Person() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

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

获取Class类的实例

  1. 通过类名获取 Class c = Person.class();
  2. 通过实例对象获取 Class c = person.getClass();
  3. 通过包名 Class c = Class.forName(“Reflection.Person”)
  4. 基本数据类型可以直接用.TYPE Class c = Integer.TYPE

哪些类型可以有Class对象

  1. class 类
  2. interface 接口
  3. [] 数组
  4. enum 枚举
  5. annotation 注解@interface
  6. primitive type 基本数据类型
  7. void

类的加载过程(了解

类的加载(Load)–>类的链接(Link)–>类的初始化(Initialize)
加载:将类的class文件读入内存,并为之创建一个Class对象此过程有类加载器完成
链接:将类的二进制数据合并到JRE中
初始化:JVM负责初始化,当初始化一个类时,若发现其父类没有初始化,则先触发其父类的初始化

什么时候会发生类的初始化?

类的主动引用(一定会发生类的初始化

  1. 当虚拟机启动,先初始化main()方法所在的类
  2. new一个类的对象
  3. 调用类的静态成员(除了final常量)和静态方法
  4. 使用java.lang.reflect包的方法对类进行反射调用
  5. 当初始化一个类,如果其父类没有被初始化,则会初始化他的父类

类的被动引动(不会发生类的初始化

  1. 当访问一个静态域时,只有真正声明这个域的类才会被初始化(子类调用父类的静态变量,不会初始化子类
  2. 通过数组定义类引用,不会触发类的初始化
  3. 引用常量不会触发此类的初始化(常量链接阶段就存入调用类的常量池中了

类加载器

作用:将class文件字节码加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆中生成一个代表这个类的Class对象,作为方法区中类数据的访问入口。

获取类的运行时结构

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

public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c = Class.forName("Reflection.Person");

        //获取类的名字
        String name = c.getName();
        System.out.println(name);//获取包名 + 类名
        System.out.println(c.getSimpleName());//类名

        //获取类的属性
        System.out.println("---");
        Field[] fields = c.getFields();//只能获得public属性
        for (Field field : fields) {
            System.out.println(field);
        }

        Field[] declaredFields = c.getDeclaredFields();//找到全部的属性
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        System.out.println(c.getDeclaredField("name"));//获得指定的属性

        //获得类的方法
        System.out.println("===");
        Method[] methods = c.getMethods();//本类及其父类的全部方法
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("===");
        Method[] declaredMethods = c.getDeclaredMethods();//获得本类的方法
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }

        //获得本类的指定方法
        //参数考虑到重载
        System.out.println(c.getMethod("setName", String.class));

        //获得构造器
        System.out.println("===");
        Constructor[] constructors = c.getConstructors();//获得所有构造器 public
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        System.out.println(c.getDeclaredConstructor(String.class,int.class));//不局限public的方法
    }

}

动态创建对象

调用Class对象的newInstance()方法
1)类必须有一个无参构造器
2)类的构造器的访问权限需要足够

用构造器创建对象
调用方法、修改属性

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

public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class c = Class.forName("Reflection.Person");

        Person person = (Person) c.newInstance();//本质调用了无参构造器
        System.out.println(person);

        //通过构造器创建对象
        System.out.println("===");
        Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
        Person instance = (Person)constructor.newInstance("小王", 170788);
        System.out.println(instance);


        //通过反射调用普通方法
        System.out.println("===");
        Method method = c.getMethod("setName", String.class);
        //invoke 激活的意思
        method.invoke(instance,"大王");//使用invoke方法来传入使用此方法的对象和value
        System.out.println(instance);

        //通过反射操作属性
        System.out.println("===");
        Field name = c.getDeclaredField("name");

        //不能直接访问private的属性,需要关闭程序的安全检测,利用如下方法
        name.setAccessible(true);//true 这样就是可以访问了
        name.set(instance,"小王");
        System.out.println(instance);
        //Methord,Field,Construtor 对象都有setAccessible()开关
    }
}

性能问题

当访问权限为true时,这样会提高反射的效率

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

public class Test04 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        test01();
        test02();
        test03();
    }
    public static void test01(){
        Person p = new Person();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            p.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通方法的运行时间:" + (endTime - startTime) + "ms");
    }

    public static void test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       Class c = Class.forName("Reflection.Person");
        Constructor constructor = c.getConstructor();
        Person instance =(Person) constructor.newInstance();

        Method method = c.getMethod("getName", null);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            method.invoke(instance,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方法的运行时间:" + (endTime - startTime) + "ms");
    }

    public static void test03() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class c = Class.forName("Reflection.Person");
        Constructor constructor = c.getConstructor();
        Person instance =(Person) constructor.newInstance();

        Method method = c.getMethod("getName", null);
        method.setAccessible(true);

        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            method.invoke(instance,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方法关闭安全检测的运行时间:" + (endTime - startTime) + "ms");
    }
}

获取泛型信息

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 Test05 {
    public void test01(Map<String ,Person> map, List<Person> list){
        System.out.println("test01");
    }

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

    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Test05.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);
                }
            }
        }

        System.out.println("===");

        Method method1 = Test05.class.getMethod("test02");
        Type genericReturnType = method1.getGenericReturnType();

        System.out.println(genericReturnType);
        if (genericReturnType instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }

    }
}

反射操作注解(重要

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

public class Test06 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class aClass = Class.forName("Reflection.Student");

        //利用反射访问类的注解
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
       Xiaowang xiaowang = (Xiaowang)aClass.getAnnotation(Xiaowang.class) ;
        System.out.println(xiaowang.value());

        //利用反射访问属性的注解
        System.out.println("===");
        Field field = aClass.getDeclaredField("name");
        FieldWang annotation = field.getAnnotation(FieldWang.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.length());
        System.out.println(annotation.type());
    }
    }


@Xiaowang("db_student")
class  Student{
    @FieldWang(columnName = "db_name",type = "db_String",length = 10)
    private String name;
    @FieldWang(columnName = "db_id",type = "db_int",length = 10)
    private int id;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

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

//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Xiaowang{
    String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldWang{
    String columnName();
    String type();
    int length();
}
原创文章 34 获赞 8 访问量 1182

猜你喜欢

转载自blog.csdn.net/qq_46225886/article/details/105075908