前言

注解就是源代码的元数据,通熟的讲就是代码中的标签。注解就有如下的特点:

  1. 注解是一个附属品,依赖于其余元素(包、类、办法、属性等等)存在。
  2. 注解自身没有作用,在失当的时候由内部程序进行解析才会产生作用。

注解有哪些?

  1. 按起源分

    • JDK 自带注解,例如:@Override, @Deprecated, @SuppressWornings 。
    • 第三方注解。
    • 自定义注解。
  2. 按生命周期划分

    • SOURCE:只存在于源代码中,编译成 class 文件就不存在了。
    • Class:存在于源代码中和 class 文件中。
    • RUNTIME:注解保留到运行时。

什么是元注解?

元注解指的是用于形成注解的注解,包含如下几个:

  1. @Retention:指明 Annotation 的生命周期,传入的值是一个枚举类型,可选值为:

    • RetentionPolicy.SOURCE
    • RetentionPolicy.CLASS
    • RetentionPolicy.RUNTIME
  2. @Target:指明 Annotation 能够润饰程序哪些元素,传入的值为ElemetType[] 类型,值可为:

    • ElementType.CONSTRUCTOR :结构器
    • ElementType.FIELD:属性
    • ElementType.LOCAL_VARIABLE:局部变量
    • ElementType.METHOD:办法
    • ElementType.PACKAGE:包
    • ElementType.PARAMETER:参数
    • ElementType.TYPE:类、接口(包含注解类型和 enum 申明)
  3. @Documented:应用此润饰的注解将会被 javadoc 工具提取成文档,应用此注解,其 @Retention 必须被设置为 RetentionPolicy.RUNTIME 。
  4. @Inherited:具备继承性。

如何自定义注解?

自定义注解须要留神的问题:

  1. 应用 @interface 关键字定义。
  2. 主动继承 java.lang.annotation.Annotation 接口。
  3. 配置参数的类型只能是八大根本类型、String、Class、enum、Annotation 和对应的数组类型。
  4. 配置参数申明的语法格局如下([] 示意可省略):

    类型 变量名() [default 默认值];
  5. 如果只有一个配置参数,其参数名必须为 value。
  6. 如果定义的注解含有配置参数,那在应用注解时,必须指定参数值,指定模式为:“参数名=参数值”。如果只有一个参数,间接写参数值即可,定义中指定了默认值的参数能够不指定值,但没有的肯定要指定值
  7. 没有成员的注解为标记,蕴含成员的称为元数据

自定义注解实例(定义和应用)

参考代码:

(1)Test01.java

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;public class Test01 {    @Info(name = "张三",address="北京")    public void test01(){    }    @One("value")    public void test02(){    }    @Retention(RetentionPolicy.RUNTIME)    @Target({ElementType.TYPE,ElementType.METHOD})    @interface Info {        String name();        String address();        int age()default 18;    }    @Retention(RetentionPolicy.RUNTIME)    @Target({ElementType.TYPE, ElementType.METHOD})    @interface One{        String value();    }}

反射

什么是反射?

反射指的是程序在运行期间借助反射 API 获得任何类的外部信息,并通过这些外部信息去操作对应对象的外部属性和办法。

任何一个类,在第一次应用时,就会被 JVM 加载到堆内存的办法区中。JVM 加载类胜利后,就会在办法区中产生一个对应的 Class 对象(一个类只有一个 Class 对象),这个 Class 对象蕴含被加载类的全副构造信息。

如何获取class对象?

(1)类的 class 属性

每一个类,都有一个 class 动态属性,这个动态属性就是类对应的 Class 对象。

1 Class<Person> cl1 = Person.class; 

(2)Object 对象 的 getClass() 办法

1 Person p1 = new Person();2 Class<Person> cl2 = (Class<Person>) p1.getClass(); 

(3)通过 Class 类的 forName() 办法(最罕用)

1 try {2     Class cl3 = Class.forName("com.llm.hkl.Person");3 } catch (ClassNotFoundException e) {4     e.printStackTrace();5 }

(4)通过 ClassLoader 类(不罕用)

1 ClassLoader cl = Person.class.getClassLoader();2 try {3     Class cl4 = cl.loadClass("com.llm.hkl.Person");4 } catch (ClassNotFoundException e) {5     e.printStackTrace();6 }

如何应用反射?

反射的根本应用包含创建对象,设置属性和调用办法。Class 对象中大多数 get 办法有 Declared 和无 Declared,他们的区别是:

  1. 无 Declared:只能获取到 public 润饰的,包含以后类和所有父类。
  2. 有 Declared:获取到以后类所有的(含有 private),但不包含其父类。

反射实例:

Person类和注解类(筹备):

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Info(name = "张三", habbit = "编程")public class Person {    @Filed("张三")    private String name;    public String habbit;    private int age;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getHabbit() {        return habbit;    }    public void setHabbit(String habbit) {        this.habbit = habbit;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "Person{" +                "name='" + name + '\'' +                ", habbit='" + habbit + '\'' +                ", age=" + age +                '}';    }    private String say(String str) {        String str1 = name + "说:" + str;        System.out.println(str1);        return str1;    }    public void eat(String food) {        System.out.println(name + "吃" + food);    }    public Person() {    }    public Person(String name, String habbit, int age) {        this.name = name;        this.habbit = habbit;        this.age = age;    }    private Person(String name, String habbit) {        this.name = name;        this.habbit = habbit;    }    @Retention(RetentionPolicy.RUNTIME)    @Target({ElementType.METHOD, ElementType.TYPE})    @interface Info {        String name();        String habbit();        int age() default 18;    }    @Retention(RetentionPolicy.RUNTIME)    @Target(ElementType.FIELD)    @interface Filed{        String value();    }}

reflect用法一(获取类的根本信息):

取得类的名字
取得类的属性
取得指定属性的值
取得类的办法
取得指定办法
获取结构器
取得指定的结构器

 Class<?> person = Class.forName("Person");        //取得类的名字        System.out.println("<-----------------------------------取得类的名字-------------------------->");        String name = person.getName();        System.out.println(name);        //取得类的属性        System.out.println("<-------------------------------------取得类的属性--------------------->");            //仅public        System.out.println("<-----------------getFields----------------->");        Field[] fields = person.getFields();        for (Field field : fields) {            System.out.println(field);        }        System.out.println("<-----------------getDeclaredFields----------------->");        Field[] declaredFields = person.getDeclaredFields();        for (Field declaredField : declaredFields) {            System.out.println(declaredField);        }        //取得指定属性的值        System.out.println("<--------------------取得类的指定属性--------------------------------------->");        Field name1 = person.getDeclaredField("name");        System.out.println(name1);        //取得类的办法        System.out.println("<--------------------取得类的办法--------------------------------------->");            //仅public        System.out.println("<-----------------getMethods----------------->");        Method[] methods = person.getMethods();        for (Method method : methods) {            System.out.println(method);        }        System.out.println("<-----------------getDeclaredMethods----------------->");        Method[] declaredMethods = person.getDeclaredMethods();        for (Method declaredMethod : declaredMethods) {            System.out.println(declaredMethod);        }        //取得指定办法        System.out.println("<-------------------------取得类的指定办法--------------------------------------->");        Method say = person.getDeclaredMethod("say",String.class);        System.out.println(say);        //获取结构器        System.out.println("<--------------------------取得类的结构器--------------------------------->");        System.out.println("<-----------------getConstructors----------------->");            //仅public        Constructor<?>[] constructors = person.getConstructors();        for (Constructor<?> constructor : constructors) {            System.out.println(constructor);        }        System.out.println("<-----------------getDeclaredConstructors----------------->");        Constructor<?>[] declaredConstructors = person.getDeclaredConstructors();        for (Constructor<?> declaredConstructor : declaredConstructors) {            System.out.println(declaredConstructor);        }        //取得指定的结构器        System.out.println("<---------------------------取得类指定的结构器------------------------------>");        Constructor<?> declaredConstructor = person.getDeclaredConstructor(String.class, String.class, int.class);        System.out.println(declaredConstructor);

reflect用法二(创立并操作对象):

反射形式创建对象
调用无参结构器创建对象
通过有参结构器
通过公有的结构器
通过反射设置私有属性
通过反射设置公有属性
通过反射调用办法
通过反射调用公有办法

Class<?> person = Class.forName("Person");        //  反射形式创建对象        System.out.println("<-----反射形式创建对象----->");        Person instance01 = (Person) person.newInstance();        System.out.println(instance01);        //  调用无参结构器创建对象        System.out.println("<-----调用无参结构器创建对象----->");        Constructor<?> noneConstructor = person.getDeclaredConstructor();        Person instance02 = (Person) noneConstructor.newInstance();        System.out.println(instance02);        //  调用有参结构器创建对象        System.out.println("<-----调用有参结构器创建对象----->");        Constructor<?> constructor = person.getDeclaredConstructor(String.class, String.class, int.class);        Person instance03 = (Person) constructor.newInstance("张三", "编程", 18);        System.out.println(instance03);        //  调用公有的结构器创建对象        System.out.println("<-----调用公有的结构器创建对象----->");        java.lang.reflect.Constructor<?> privateConstructor = person.getDeclaredConstructor(String.class, String.class);        privateConstructor.setAccessible(true);        Object instance04 = privateConstructor.newInstance("张三", "编程");        System.out.println(instance04);        //  通过反射设置私有属性        System.out.println("<-----通过反射设置私有属性----->");        Field habbit = person.getDeclaredField("habbit");        habbit.set(instance01, "编程");        System.out.println(instance01);        //  通过反射设置公有属性        System.out.println("<-----通过反射设置公有属性----->");        Field name = person.getDeclaredField("name");        name.setAccessible(true);        name.set(instance01, "张三");        System.out.println(instance01);        //  通过反射调用私有办法        System.out.println("<-----通过反射调专用办法----->");        Method eat = person.getDeclaredMethod("eat", String.class);        eat.invoke(instance01,"饭");        //  通过反射调用公有办法        System.out.println("<-----通过反射调用公有办法----->");        Method say = person.getDeclaredMethod("say", String.class);        say.setAccessible(true);        say.invoke(instance01,"呵呵");

reflect用法三(获取泛型信息):

Java采纳泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器 Javac应用的,确保数据的安全性和免去强制类型转换问题,然而,一旦编译实现,所有和泛型无关的类型全副擦除。
为了通过反射操作这些类型,Java新增了 ParameterizedType, GenericArrayTypeType Variable和 WildcardType几种类型来代表不能被归一到class类中的类型然而又和原始类型齐名的类型。

ParameterizedType:示意一种参数化类型比方 Collection< String>

GenericArrayType:示意种元素类型是参数化类型或者类型变量的数组类型

TypeVariable:是各种类型变量的公共父接口

WildcardType:代表种通配符类型表达式

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 Test03 {    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 Exception {        Class<Test03> test03 = Test03.class;        System.out.println("<--------test01---------->");        Method test01 = test03.getDeclaredMethod("test01", Map.class, List.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);                }            }        }        System.out.println("<--------test02---------->");        Method test02 = test03.getDeclaredMethod("test02");        Type genericReturnType = test02.getGenericReturnType();        System.out.println(genericReturnType);        if (genericReturnType instanceof ParameterizedType) {            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();            for (Type actualTypeArgument : actualTypeArguments) {                System.out.println(actualTypeArgument);            }        }    }}

运行后果:

reflect用法四(获取注解信息):

获取类上的注解
获取属性上的注解
获取办法上的注解

        Class<?> person = Class.forName("Person");        System.out.println("<----------获取类上的注解------------->");        //获取类上的注解        Info annotation = person.getAnnotation(Info.class);        System.out.println(annotation.name());        System.out.println(annotation.habbit());        System.out.println(annotation.age());        System.out.println("<----------获取属性上的注解------------->");        //获取属性上的注解        Field name = person.getDeclaredField("name");        Person.Filed file = name.getAnnotation(Person.Filed.class);        String value = file.value();        System.out.println(value);        //获取办法上的注解  略。。。

运行后果:

最初

感激你看到这里,看完有什么的不懂的能够在评论区问我,感觉文章对你有帮忙的话记得给我点个赞,每天都会分享java相干技术文章或行业资讯,欢送大家关注和转发文章!