• 【JAVA入门】JUnit单元测试、类加载器、反射、注解


    目录

    Junit单元测试

    一、测试分类

    二、Junit概述

    三、Junit的使用

    类加载器

    一、类加载器概述

    二、类的加载时机

    三、类的加载器

    反射(Reflection)

    一、反射(Reflection)机制概述

    静态语言

    利用反射机制提供的功能

    反射相关的主要API

    二、Class类及获取Class

    三、 反射获取构造方法

    四、反射获取空参构造方法并运行

    五、 反射带参构造方法并运行

    六、反射创建对象的快捷方式

    七、 反射获取私有构造方法并运行

    八、反射获取成员方法

    九、反射调用get_set方法

    十、反射获取私有方法并运行

    十一、 反射案例分析

    十二、反射案例代码实现

    十三、 反射案例代码实现优化

    注解

    一、 注解的介绍

    二、 自定义注解

    三、自定义注解基本使用

    四、 自定义注解使用的注意事项

    五、 元注解@Target介绍

    六、元注解@Retention介绍

    七、注解解析获取到类上的注解

    八、注解解析获取到方法上的注解


    Junit单元测试

    一、测试分类

    黑盒测试:不需要写代码,输入值看程序是否能够输出期望的值。

    白盒测试:需要写代码,关注程序具体的执行流程。

    二、Junit概述

    Junit是java编程语言的单元测试工具。Junit是一个非常重要的测试工具

    • Junit是一个开放源代码的测试工具。

    • 提供注解来识别测试方法:@Test、@Before、@After

    • Junit测试可以让代码编写更快,并提高质量

    • Junit简洁,花费时间较少

    • Junit在一个条中显示进度,如果运行良好是绿色,反之为红色

    三、Junit的使用

    1. 步骤:
    2. 1.模块名称上右键/new/directory/输入名称lib确定
    3. 2.把junit的jar包复制到文件夹lib中
    4. 3.文件夹lib上右键/Add as Library/在对话框中输入以下内容后/ok
    5. Name: 输入lib
    6. Level:输入Module Library
    7. Add to module: 输入当前模块名
    8. ============================================================
    9. //只能用在非静态无返回值无参数的方法上
    10. /* 运行:
    11.        方法上右键运行,运行的是含有@Test注解的方法
    12.        类上右键运行,运行的是类当中含有@Test注解的所有方法
    13.        绿条: 正常运行
    14.        红条: 出现问题,异常了
    15.  常用注解
    16.        - @Test,用于修饰需要执行的测试方法
    17.        - @Before,修饰的方法会在测试方法之前被自动执行
    18.        - @After,修饰的方法会在测试方法执行之后自动被执行
    19. */
    20. import org.junit.Test;
    21. public class DemoJunit {
    22.    @Test
    23.    public void method(){
    24.        System.out.println("method...");
    25.   }
    26.    @Test
    27.    public void fun(){
    28.        System.out.println("fun...");
    29.   }
    30.    @Test
    31.    public void show(){
    32.        System.out.println("show...");
    33.   }
    34.    @Before
    35.   public void before(){
    36.       System.out.println("before...");
    37.   }
    38.   @After
    39.   public void after(){
    40.       System.out.println("after...");
    41.   }
    42. }
    43. =========================================================
    44. 运行结果:
    45. before...
    46. method...
    47. after...
    48. before...
    49. fun...
    50. after...
    51. before...
    52. show...
    53. after...

    类加载器

    一、类加载器概述

    类加载器:负责将.class文件(存储的物理文件)加载到内存中

    二、类的加载时机

    1. public class DemoClass {
    2.    public static void main(String[] args) {
    3.        // 1. 创建类的实例。
    4.         DemoClassFather father = new DemoClassFather();
    5.        // 2. 类的静态变量,或者为静态变量赋值。
    6.        System.out.println(DemoClassFather.str);
    7.        // 3. 类的静态方法。
    8.        DemoClassFather.method();
    9.        // 4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。
    10.        // 5. 初始化某个类的子类。
    11.        new Son();
    12.        // 6. 直接使用java.exe命令来运行某个主类。
    13.   }
    14. }
    15. ======================================================================
    16. //父类
    17. public class DemoClassFather {
    18.    //静态变量
    19.    static String str ="haha";
    20.    //静态代码块
    21.    static {
    22.        System.out.println("DemoClassFather被加载。。。");
    23.   }
    24.    //静态方法
    25.    public static void method(){
    26.        System.out.println("method.....");
    27.   }
    28. }
    29. class Son extends DemoClassFather{
    30. static {
    31.    System.out.println("Son被加载。。。。");
    32. }
    33. }

    三、类的加载器

    1.    类加载器:
    2.        1.作用:
    3.            负责把.class文件加载到内存的方法区中.
    4.            将class文件(硬盘)加载到内存生成Class对象。
    5.        2.组成:
    6.            (1)BootstrapClassLoader 根类加载器
    7.                也被称为引导类加载器,负责Java核心类的加载
    8.                引导类加载器BootstrapClassLoader:
    9.                    用C++编写的,是JVM自带的类加载器,
    10.                    负责Java平台核心库,用来加载核心类库。该加载器无法直接获取
    11.                比如System,String等。
    12.            (2)ExtClassLoader 扩展类加载器
    13.                负责JRE的扩展目录中jar包的加载
    14.                在JDK中JRE的lib目录下ext目录
    15.            (3)AppClassLoader 系统类加载器/应用类加载器
    16.                Java语言编写的类加载器,负责加载我们定义的类和第三方jar包中的类。
    17.        3.获取类加载器
    18.            java.lang.Class类
    19.            成员方法:
    20.                 public ClassLoader getClassLoader(): 返回该类的类加载器。
    21.            java.lang.ClassLoader类
    22.            成员方法:
    23.                 public ClassLoader getParent(): 返回委托的父类加载器。
    24.         4.类加载器加载机制:
    25.            双亲委派机制: 谁用谁加载
    26.            比如:
    27.                public Person {
    28.                    String s = name;
    29.                    DNSNameService
    30.                    ...
    31.                }
    32.                java Person
    33.                Person类是由AppClassLoader加载
    34.                Person类内部使用String,原则上来讲,应该由AppClassLoader加载
    35.                但是,先找父加载器ExtClassLoader,不负责
    36.                ExtClassLoader找父加载器BootstrapClassLoader,负责
    37.                Person类内部使用DNSNameService,原则上来讲,应该由AppClassLoader加载
    38.                但是,先找父加载器ExtClassLoader,负责
    39.                不管怎样? .class文件只能被加载一次
    40.    注意:
    41.        BootstrapClassLoader 根类/引导类/核心类加载器 String,System
    42.        ExtClassLoader 扩展类加载器 DNSNameService
    43.        AppClassLoader 系统类加载器/应用类加载器
    44.        它们之间不存在继承关系,最终的父类 java.lang.ClassLoader
    45. ================================================================================
    46. public class Demo03ClassLoader {
    47.    @Test
    48.    public void boot(){
    49.        //String 由BootstrapClassLoader加载,C++实现,不让我们获取
    50.        ClassLoader c = String.class.getClassLoader();
    51.        System.out.println(c);//null
    52.   }
    53.    @Test
    54.    public void ext() {
    55.        //由扩展类加载器加载:获取扩展类的class对象
    56.        ClassLoader c = DNSNameService.class.getClassLoader();
    57.        System.out.println(c);//sun.misc.Launcher$ExtClassLoader@452b3a41
    58.   }
    59.    @Test
    60.    public void app(){
    61.        //由App类加载器加载
    62.        ClassLoader c = Demo03ClassLoader.class.getClassLoader();
    63.        System.out.println(c);//sun.misc.Launcher$AppClassLoader@18b4aac2
    64.   }
    65.    @Test
    66.    public void app2() {
    67.        //由App类加载器加载:
    68.        ClassLoader c = Demo03ClassLoader.class.getClassLoader();
    69.        System.out.println(c);//sun.misc.Launcher$AppClassLoader@18b4aac2
    70.        ClassLoader p = c.getParent();//委托父加载器
    71.        System.out.println(p);//sun.misc.Launcher$ExtClassLoader@452b3a41
    72.        ClassLoader pp = p.getParent();
    73.        System.out.println(pp);//null
    74.   }
    75. }

     

    反射(Reflection)

    注意: 1.当第一次使用类的信息时,该类的.class文件,会被加载到内存中的方法区中 2.jvm同时为加载到内存方法区的.class文件,创建一个Class类型的对象,该对象被保存在堆内存中 相当于堆内存中的Class类型的对象,指向了方法区的.class文件 3.一个类的.class文件,只能被加载一次,所以对应的Class类型的对象,只有一个 4.任意类型(基本类型/引用类型)都有对应的Class类型的对象 什么叫做反射呢?   通过获取Class类型的对象,从而操作对应的.class文件   说白了: 通过Class类型的对象获取.class文件中的成员变量/成员方法/构造方法并执行
    

    一、反射(Reflection)机制概述

    被视为动态语言的关键,反射机制允许程序在执行期间借助Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

    加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构。

    是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。

    静态语言

    与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++

    Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。Java的动态性让编程的时候更加灵活!

    利用反射机制提供的功能

    在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时获取泛型信息 在运行时调用任意一个对象的成员变量和方法 在运行时处理注解 生成动态代理

    反射相关的主要API

    java.lang.Class:代表一个类 java.lang.reflect.Method:代表类的方法 java.lang.reflect.Field:代表类的成员变量 java.lang.reflect.Constructor:代表类的构造器

    二、Class类及获取Class

    1. import org.junit.Test;
    2. import java.lang.annotation.ElementType;
    3. import java.lang.reflect.Constructor;
    4. import java.lang.reflect.Field;
    5. import java.lang.reflect.Method;
    6. /*
    7.    获取Class对象的方式
    8.        方式一:
    9.        java.lang.Object类,成员方法:
    10.            public Class getClass(): 获取Class类型的对象
    11.        方式二:
    12.            任意类型(基本/引用),隐藏的class属性,获取该类对应的Class对象
    13.        方式三:
    14.            java.lang.Class类,静态方法:
    15.            public static Class forName(String className)
    16.                返回与带有给定字符串名的类或接口相关联的 Class 对象。
    17.                参数:
    18.                   String className: 类/接口 的全名称(包名+类/接口名)
    19.       建议使用方式三:
    20.            参数是String,可以写在配置文件中
    21.        Class类的成员方法:
    22.            public String getSimpleName(): 获得简单类名,只是类名,没有包
    23.            public String getName(): 获取完整类名,包含包名+类名
    24. */
    25. public class ReflectionTest {
    26.    @Test
    27.    public void test3() throws ClassNotFoundException {
    28.        //方式一:
    29.        Class c1 = Person.class;
    30.        System.out.println(c1);
    31.        //方式二:通过运行时类的对象,调用getClass()
    32.        Person p1 = new Person();
    33.        Class c2 = p1.getClass();
    34.        System.out.println(c2);
    35.        //方式三:调用Class的静态方法:forName(String classPath)
    36.        Class c3 = Class.forName("www.gh110.com");
    37. //       c3 = Class.forName("www.123.com");
    38.        System.out.println(c3);
    39.        System.out.println(c1 == c2);
    40.        System.out.println(c1 == c3);
    41.        //方式四:使用类的加载器:ClassLoader (了解)
    42.        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
    43.        Class c4 = classLoader.loadClass("www.gh110.com");
    44.        System.out.println(c4);
    45.        System.out.println(c1 == c4);
    46.   }
    47. }

    三、 反射获取构造方法

    1.    反射获取构造方法
    2.    步骤:
    3.        1.获取Class类型的对象(推荐使用: Class.forName)
    4.        2.java.lang.Class类,成员方法: 作用获取构造方法对象的
    5.             public Constructor[] getConstructors():
    6.                获取所有的public修饰的所有构造方法
    7.              每个构造方法,被封装成了一个Constructor对象,存储到数组中,并返回数组
    8.              
    9.             public Constructor[] getDeclaredConstructors():
    10.                获取所有的构造方法(包含public,默认,protected,private修饰的)
    11.              每个构造方法,被封装成了一个Constructor对象,存储到数组中,并返回数组
    12.             public Constructor getConstructor(Class... parameterTypes)
    13.                根据参数类型获取构造方法对象,只能获得public修饰的构造方法。
    14.                如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。
    15.                参数是可变参数,调用此方法时,可以不写参数,获取的空参构造
    16.                            可以写参数,给定的参数必须是Class对象
    17.                                比如:
    18.                                    参数 String name,int age
    19.                                    调用此方法: String.class,int.class
    20.            public Constructor getDeclaredConstructor(Class... parameterTypes)
    21.                根据参数类型获取构造方法对象,可以获得private修饰的构造方法。
    22.        3.练习:
    23.       获取public修饰的所有构造方法对象
    24.            获取所有构造方法对象(包含private修饰的)
    25.            获取public修饰的空参构造方法对象
    26.            获取public修饰的第一个参数是String类型,第二个参数是int类型的构造方法对象
    27.            获取public修饰的参数是int类型的构造方法对象
    28. =========================================================================================
    29. public class Demo04GetConstructor {
    30.    public static void main(String[] args) throws Exception {
    31.        //1.获取Class类型的对象(推荐使用: Class.forName)
    32.        Class clazz = Class.forName("domain.User");
    33.        //获取所有的public修饰的所有构造方法
    34.        Constructor[] cons = clazz.getConstructors();
    35.        //增强for遍历
    36.        for (Constructor con : cons) {
    37.            System.out.println(con);
    38.       }
    39.        System.out.println("----------------");
    40.        //获取public修饰的空参构造方法对象
    41.        Constructor con1 = clazz.getConstructor();
    42.        System.out.println(con1);
    43.        //获取public修饰的第一个参数是String类型,第二个参数是int类型的构造方法对象
    44.        Constructor con2 = clazz.getConstructor(String.class, int.class);
    45.        System.out.println(con2);
    46.        //获取public修饰的参数是int类型的构造方法对象
    47.        //报异常: NoSuchMethodException,没有这个方法异常,因为方法是private修饰
    48.        //Constructor con3 = clazz.getConstructor(int.class);
    49.        //System.out.println(con3);
    50.        //获取private修饰的参数是int类型的构造方法对象
    51.        Constructor con4 = clazz.getDeclaredConstructor(int.class);
    52.        System.out.println(con4);
    53.   }
    54. }

    四、反射获取空参构造方法并运行

    1.    反射获取空参构造方法并运行
    2.    步骤:
    3.        1.获取Class类型的对象(推荐使用: Class.forName)
    4.        2.Class对象调用getConstructor方法,获取空参构造方法对象
    5.        3.执行空参构造方法对象,从而创建一个具体的对象
    6.            java.lang.reflect.Constructor类,成员方法:
    7.                public Object newInstance(Object... params):
    8.                    根据方法参数传递的具体数据,调用指定的构造方法,从而创建一个具体的对象
    9.                    参数:
    10.                        Object... params: 可变参数
    11.                            传递数组,参数列表,不传参都可以
    12.                    作用:
    13.                        创建对象时,成员变量需要具体的数据
    14.        举例(空参构造):
    15.            不使用反射
    16.                User user = new User();
    17.            使用反射:
    18.                获取到了空参构造方法对象
    19.                Constructor con = ...;//空参构造方法被封装到了Constructor对象con中
    20.                //newInstance方法内部会把Constructor对象con中封装的空参构造执行一次,
    21.                //从而创建一个具体的对象出来
    22.                Object obj = con.newInstance();
    23.        举例(满参构造):------此处很重要,帮助大家理解------
    24.            不使用反射
    25.                User user = new User("zhangsan",18);
    26.            使用反射:
    27.                获取到了满参构造方法对象
    28.                Constructor con = ...;//满参构造方法被封装到了Constructor对象con中
    29.                //newInstance方法内部会把Constructor对象con中封装的满参构造执行一次,
    30.                //并且newInstance方法会把自己接收到的参数,交给Constructor对象con中封装的满参构造
    31.                //从而创建一个带数据的具体的对象出来
    32.                Object obj = con.newInstance("zhangsan",18);
    33. =========================================================================================
    34. public class Demo05NewInstance {
    35.    public static void main(String[] args) throws Exception {
    36.        //1.获取Class类型的对象(推荐使用: Class.forName)
    37.        Class clazz = Class.forName("domain.User");
    38.        //2.Class对象调用getConstructor方法,获取空参构造方法对象
    39.        Constructor con = clazz.getConstructor();
    40.        //3.执行空参构造方法对象,从而创建一个具体的对象
    41.        User user = (User)con.newInstance();
    42.        System.out.println(user);
    43.   }
    44. }

    五、 反射带参构造方法并运行

    1.    反射带参构造方法并运行
    2.    步骤:
    3.        1.获取Class类型的对象(推荐: Class.forName(...))
    4.        2.Class类型的对象调用getConstructor方法,获取指定的构造方法对象
    5.        3.构造方法对象调用newInstance方法,创建一个具体的对象
    6.        4.打印对象
    7. ========================================================================
    8. public class Demo06NewInstance {
    9.    public static void main(String[] args) throws Exception {
    10.        //1.获取Class类型的对象(推荐: Class.forName(...))
    11.        Class clazz = Class.forName("domain.User");
    12.        //2.Class类型的对象调用getConstructor方法,获取指定的构造方法对象
    13.        //获取public修饰,指定参数类型的构造方法对象
    14.        Constructor con = clazz.getConstructor(String.class, int.class);
    15.        //3.构造方法对象调用newInstance方法,创建一个具体的对象
    16.        User user = (User) con.newInstance("张三",18);
    17.        //4.打印对象
    18.        System.out.println(user);
    19.   }
    20. }
     

    六、反射创建对象的快捷方式

    1.    反射创建对象的快捷方式
    2.    步骤:
    3.        1.获取Class类型的对象(推荐: Class.forName(...))
    4.        2.Class对象调用newInstance方法,创建一个具体的对象
    5.            java.lang.Class类,成员方法:
    6.            public T newInstance()
    7.                创建此 Class 对象所表示的类的一个新实例。
    8.                底层原理:
    9.                    (1)获取空参构造方法对象
    10.                    (2)空参构造方法对象调用newInstance方法
    11.        3.打印对象
    12. =======================================================================
    13. public class Demo07NewInstance {
    14.    public static void main(String[] args) throws Exception {
    15.        //1.获取Class类型的对象(推荐: Class.forName(...))
    16.        Class clazz = Class.forName("domain.User");
    17.        //2.Class对象调用newInstance方法,创建一个具体的对象
    18.        User user = (User)clazz.newInstance();
    19.        //3.打印对象
    20.        System.out.println(user);
    21.   }
    22. }

    七、 反射获取私有构造方法并运行

    1.    反射获取私有构造方法并运行       暴力反射
    2.    步骤:
    3.        1.获取Class类型的对象(推荐使用: Class.forName)
    4.        2.Class对象调用getDeclaredConstructor方法,获取指定参数私有构造方法对象
    5.        3.指定参数私有构造方法对象调用setAccessible方法,取消 Java 语言访问检查
    6.        4.指定参数私有构造方法对象调用newInstance方法,创建一个具体的对象
    7.        5.打印对象
    8.    注意:
    9.        java.lang.reflect.AccessibleObject类,成员方法:
    10.        public void setAccessible(boolean flag):
    11.            将此对象的 accessible 标志设置为指示的布尔值。
    12.            参数:
    13.                boolean flag
    14.                true: 取消 Java 语言访问检查       private 失效
    15.                false: 实施 Java 语言访问检查       private 有效
    16.        AccessibleObject类,子类:
    17.            Constructor,Field,Method类,都可以调用setAccessible方法
    18.            从而进行暴力反射
    19. ====================================================================================
    20. public class Demo08NewInstance {
    21.    public static void main(String[] args) throws Exception {
    22.        //1.获取Class类型的对象(推荐使用: Class.forName)
    23.        Class clazz = Class.forName("domain.User");
    24.        //2.Class对象调用getDeclaredConstructor方法,获取指定参数私有构造方法对象
    25.        Constructor con = clazz.getDeclaredConstructor(int.class);
    26.        //3.指定参数私有构造方法对象调用setAccessible方法,取消 Java 语言访问检查
    27.        con.setAccessible(true);
    28.        //4.指定参数私有构造方法对象调用newInstance方法,创建一个具体的对象
    29.        User user = (User) con.newInstance(28);
    30.        //5.打印对象
    31.        System.out.println(user);
    32.   }
    33. }

    八、反射获取成员方法

    1. /*
    2.    Javabean类的介绍
    3.        1.所有成员变量必须private修饰
    4.        2.必须提供对应的get和set方法
    5.        3.必须提供空参构造(满参构造是可选的)
    6. */
    7. public class User {
    8.    private String name;
    9.    private int age;
    10.    private char[] my2CharArray(String str) {
    11.        return str.toCharArray();
    12.   }
    13.    public int getSum(int a, int b) {
    14.        return a + b;
    15.   }
    16.    @Override
    17.    public String toString() {
    18.        return "User{" +
    19.                "name='" + name + '\'' +
    20.                ", age=" + age +
    21.                '}';
    22.   }
    23.    //空参构造
    24.    public User() {
    25.   }
    26.    //满参
    27.    public User(String name, int age) {
    28.        this.name = name;
    29.        this.age = age;
    30.   }
    31.    //只给name赋值
    32.    public User(String name) {
    33.        this.name = name;
    34.   }
    35.    //只给age赋值
    36.    private User(int age) {
    37.        this.age = age;
    38.   }
    39.    public String getName() {
    40.        return name;
    41.   }
    42.    public void setName(String name) {
    43.        this.name = name;
    44.   }
    45.    public int getAge() {
    46.        return age;
    47.   }
    48.    public void setAge(int age) {
    49.        this.age = age;
    50.   }
    51. }
    52. /*
    53.    反射获取成员方法
    54.    步骤:
    55.        1.获取Class类型的对象(推荐使用: Class.forName)
    56.        2.java.lang.Class类,成员方法: 作用获取成员方法对象的
    57.            public Method[] getMethods()
    58.                获取所有的public修饰的成员方法,包括父类中。
    59.                每个成员方法被封装成为一个Method对象,存储到数组中,并返回
    60.             public Method getMethod(String methodName, Class... params)
    61.            根据方法名和参数类型获得一个方法对象,只能是获取public修饰的
    62.            参数:
    63.                String methodName: 方法的名字
    64.                    Class... params: 方法参数类型对应的Class对象
    65.                        可变参数: 传递数组,参数列表,不传参
    66.            Method getDeclaredMethod(String name, Class... params)
    67.                根据方法名和参数类型获得一个方法对象,可以获取private修饰的
    68.        3.练习:
    69.       获取任意修饰符的所有成员方法
    70.            获取public修饰符的所有成员方法
    71.            获取public修饰的名称为toString的没有参数的方法
    72.            获取public修饰的名称为setName的参数为String类型的方法
    73.            获取public修饰的名称为getSum的参数为两个int类型的方法
    74.            获取public修饰的名称为my2CharArray的参数为String类型的方法
    75. */
    76. public class Demo01GetMethod {
    77.    public static void main(String[] args) throws Exception {
    78.        //1.获取Class类型的对象(推荐使用: Class.forName)
    79.        Class clazz = Class.forName("domain.User");
    80.        //2.获取所有public修饰包含父类的成员方法对象组成的数组
    81.        Method[] ms = clazz.getMethods();
    82.        //增强for遍历
    83.        for (Method m : ms) {
    84.            System.out.println(m);
    85.       }
    86.        System.out.println("----------------");
    87.        //获取public修饰的名称为toString的没有参数的方法
    88.        Method m1 = clazz.getMethod("toString");
    89.        System.out.println(m1);
    90.        //获取public修饰的名称为setName的参数为String类型的方法
    91.        Method m2 = clazz.getMethod("setName", String.class);
    92.        System.out.println(m2);
    93.        //获取public修饰的名称为getSum的参数为两个int类型的方法
    94.        Method m3 = clazz.getMethod("getSum", int.class, int.class);
    95.        System.out.println(m3);
    96.        //获取public修饰的名称为my2CharArray的参数为String类型的方法
    97.        //该方法private修饰,无法获取报出异常
    98.        //Method m4 = clazz.getMethod("my2CharArray", String.class);
    99.        //System.out.println(m4);
    100.        //获取private修饰的名称为my2CharArray的参数为String类型的方法
    101.        Method m5 = clazz.getDeclaredMethod("my2CharArray", String.class);
    102.        System.out.println(m5);
    103.   }
    104. }

    九、反射调用get_set方法

    1.    反射调用get_set方法
    2.    步骤:
    3.        1.获取Class类型的对象(推荐使用: Class.forName)
    4.        2.Class类型的对象调用newInstance方法,创建具体的对象
    5.        3.Class类型的对象调用getMethod方法,获取get和set方法对应的Method对象
    6.        4.get和set方法对应的Method对象调用invoke方法,执行对应的功能
    7.            java.lang.reflect.Method类,成员方法:
    8.            public Object invoke(Object obj, Object... args)
    9.                对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
    10.                参数:
    11.                    Object obj: 成员方法的调用必须由对象支持
    12.                    Object... args: 执行成员方法时,需要的具体的参数
    13.                返回值类型:
    14.                    java.lang.Object类型: 成员方法执行后的返回值类型(被提升为Object类型)
    15.                    如果方法的返回值类型是void: 返回null
    16.        不使用反射:
    17.            User user = new User();
    18.            user.setName("张三");
    19.        使用反射:
    20.            已经获取到了setName方法对应的Method对象
    21.            已经把setName方法封装到Method对象setNameMethod中
    22.            Method setNameMethod = clazz.getMethod(...);
    23.            User user = new User();//通过反射创建也可以
    24.            //invoke方法内部使用invoke方法接收到的参数User对象user
    25.            //调用它内部封装的成员方法setName,同时调用该成员方法setName的时候传递参数"张三"
    26.            setNameMethod.invoke(user,"张三");
    27. =========================================================================================
    28. public class Demo02Invoke {
    29.    public static void main(String[] args) throws Exception {
    30.        //1.获取Class类型的对象(推荐使用: Class.forName)
    31.        Class clazz = Class.forName("domain.User");
    32.        //2.Class类型的对象调用newInstance方法,创建具体的对象
    33.        User user = (User) clazz.newInstance();
    34.        //3.Class类型的对象调用getMethod方法,获取get和set方法对应的Method对象
    35.        Method setNameMethod = clazz.getMethod("setName", String.class);
    36.        Method setAgeMethod = clazz.getMethod("setAge", int.class);
    37.        Method getNameMethod = clazz.getMethod("getName");
    38.        Method getAgeMethod = clazz.getMethod("getAge");
    39.        //4.get和set方法对应的Method对象调用invoke方法,执行对应的功能
    40.        //执行set方法,给成员变量赋值
    41.        Object value = setNameMethod.invoke(user, "张三");
    42.        System.out.println(value);//null
    43.        value = setAgeMethod.invoke(user, 38);
    44.        System.out.println(value);//null
    45.        //System.out.println(user);
    46.        //执行get方法,获取成员变量的值
    47.        String name = (String) getNameMethod.invoke(user);
    48.        int age = (int) getAgeMethod.invoke(user);
    49.        System.out.println(name+"::::"+age);
    50.   }
    51. }

    十、反射获取私有方法并运行

    1.    反射获取私有方法并运行
    2.    步骤:
    3.        1.获取Class类型的对象(推荐使用: Class.forName)
    4.        2.Class类型的对象调用newInstance方法,创建具体的对象
    5.        3.Class类型的对象调用getDeclaredMethod方法,获取private修饰的方法对应的Method对象
    6.        4.private修饰的方法对应的Method对象调用setAccessible方法,取消 Java 语言访问检查
    7.        5.private修饰的方法对应的Method对象调用调用invoke方法,执行对应的功能
    8.    注意:
    9.        java.lang.reflect.AccessibleObject类,成员方法:
    10.        public void setAccessible(boolean flag):
    11.            将此对象的 accessible 标志设置为指示的布尔值。
    12.            参数:
    13.                boolean flag
    14.                true: 取消 Java 语言访问检查       private 失效
    15.                false: 实施 Java 语言访问检查       private 有效
    16.        AccessibleObject类,子类:
    17.            Constructor,Field,Method类,都可以调用setAccessible方法
    18.            从而进行暴力反射
    19. =========================================================================================
    20. public class Demo03Invoke {
    21.    public static void main(String[] args) throws Exception {
    22.        //1.获取Class类型的对象(推荐使用: Class.forName)
    23.        Class clazz = Class.forName("domain.User");
    24.        //2.Class类型的对象调用newInstance方法,创建具体的对象
    25.        User user = (User)clazz.newInstance();
    26.        //3.Class类型的对象调用getDeclaredMethod方法,获取private修饰的方法对应的Method对象
    27.        Method m = clazz.getDeclaredMethod("my2CharArray", String.class);
    28.        //4.private修饰的方法对应的Method对象调用setAccessible方法,取消 Java 语言访问检查
    29.        m.setAccessible(true);
    30.        //5.private修饰的方法对应的Method对象调用调用invoke方法,执行对应的功能
    31.        char[] chs = (char[]) m.invoke(user,"helloworld");
    32.        System.out.println(new String(chs));
    33.   }
    34. }

    十一、 反射案例分析

    1. /*
    2.    反射案例
    3.        需求:
    4.            写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
    5.        步骤:
    6.            1.定义配置文件config.properties,以属性名=属性值
    7.                className=itheima02.Dog
    8.                methodName=eat
    9.                注意:
    10.                    配置文件config.properties必须写在src根路径下
    11.            2.需要把配置文件信息,加载到Properties集合对象中
    12.            3.获取类的全名称和方法名称
    13.            4.获取类的Class类型的对象
    14.            5.根据Class类型的对象获取要执行的方法对应的Method对象
    15.            6.Class类型的对象创建一个具体的对象出来
    16.            7.Method对象调用invoke方法,执行具体的功能
    17. */
    18. //抽象父类
    19. public abstract class Animal {
    20.    public abstract void eat();
    21. }
    22. //子类
    23. public class Cat extends Animal {
    24.    @Override
    25.    public void eat() {
    26.        System.out.println("猫吃鱼...");
    27.   }
    28. }
    29. //子类
    30. public class Dog extends Animal {
    31.    @Override
    32.    public void eat() {
    33.        System.out.println("狗吃骨头....");
    34.   }
    35. }

    十二、反射案例代码实现

    1. public class Demo02ReflectTest {
    2.    public static void main(String[] args) throws Exception {
    3.        //2.需要把配置文件信息,加载到Properties集合对象中
    4.        Properties props = new Properties();
    5.        props.load(new FileInputStream("day14\\src\\config.properties"));
    6.        //3.获取类的全名称和方法名称
    7.        //类的全名称
    8.        String className = props.getProperty("className");
    9.        //方法名称
    10.        String methodName = props.getProperty("methodName");
    11.        //4.获取类的Class类型的对象
    12.        Class clazz = Class.forName(className);
    13.        //5.根据Class类型的对象获取要执行的方法对应的Method对象
    14.        Method eatMethod = clazz.getMethod("eat");
    15.        //6.Class类型的对象创建一个具体的对象出来
    16.        Object obj = clazz.newInstance();
    17.        //7.Method对象调用invoke方法,执行具体的功能
    18.        eatMethod.invoke(obj);
    19.   }
    20. }

    十三、 反射案例代码实现优化

    1. /*
    2.    反射案例
    3.        需求:
    4.            写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
    5.        步骤:
    6.            1.定义配置文件config.properties,以属性名=属性值
    7.                className=itheima02.Dog
    8.                methodName=eat
    9.                注意:
    10.                    配置文件config.properties必须写在src根路径下
    11.                    src下写的java源代码,项目完成后,给客户的是.class文件
    12.                    配置文件会跟着.class文件,到类路径(存储.class文件的路径)下,同步的
    13.            2.需要把配置文件信息,加载到Properties集合对象中
    14.            3.获取类的全名称和方法名称
    15.            4.获取类的Class类型的对象
    16.            5.根据Class类型的对象获取要执行的方法对应的Method对象
    17.            6.Class类型的对象创建一个具体的对象出来
    18.            7.Method对象调用invoke方法,执行具体的功能
    19.        java.lang.Class类,成员方法:
    20.            public ClassLoader getClassLoader(): 返回该类的类加载器。
    21.            java.lang.ClassLoader类,成员方法:
    22.                public InputStream getResourceAsStream(String name): 返回读取指定资源的输入流。
    23.                    指定资源: 类路径(该方法直接到类路径下扫描配置文件)
    24.                    如果配置文件写在src根下:
    25.                        String name: 只需要写文件名.扩展名 config.properties
    26.                    如果配置文件写在src/itheima02下:
    27.                        String name: itheima02/config.properties
    28. */
    29. public class Demo03ReflectTest {
    30.    public static void main(String[] args) throws Exception {
    31.        //2.需要把配置文件信息,加载到Properties集合对象中
    32.        Properties props = new Properties();
    33.        //获取类加载器
    34.        ClassLoader classLoader = Demo03ReflectTest.class.getClassLoader();
    35.        //通过类加载器,获取资源的字节输入流
    36.        InputStream is = classLoader.getResourceAsStream("config.properties");
    37.        props.load(is);
    38.        //3.获取类的全名称和方法名称
    39.        //类的全名称
    40.        String className = props.getProperty("className");
    41.        //方法名称
    42.        String methodName = props.getProperty("methodName");
    43.        //4.获取类的Class类型的对象
    44.        Class clazz = Class.forName(className);
    45.        //5.根据Class类型的对象获取要执行的方法对应的Method对象
    46.        Method eatMethod = clazz.getMethod("eat");
    47.        //6.Class类型的对象创建一个具体的对象出来
    48.        Object obj = clazz.newInstance();
    49.        //7.Method对象调用invoke方法,执行具体的功能
    50.        eatMethod.invoke(obj);
    51.   }
    52. }
    53. /*
    54.    反射案例
    55.        需求:
    56.            写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
    57.        步骤:
    58.            1.定义配置文件config.properties,以属性名=属性值
    59.                className=itheima02.Dog
    60.                methodName=eat
    61.                注意:
    62.                    配置文件config.properties必须写在src根路径下
    63.                    src下写的java源代码,项目完成后,给客户的是.class文件
    64.                    配置文件会跟着.class文件,到类路径(存储.class文件的路径)下,同步的
    65.            2.需要把配置文件信息,加载到Properties集合对象中
    66.            3.获取类的全名称和方法名称
    67.            4.获取类的Class类型的对象
    68.            5.根据Class类型的对象获取要执行的方法对应的Method对象
    69.            6.Class类型的对象创建一个具体的对象出来
    70.            7.Method对象调用invoke方法,执行具体的功能
    71.        java.lang.Class类,成员方法:
    72.            public ClassLoader getClassLoader(): 返回该类的类加载器。
    73.            java.lang.ClassLoader类,成员方法:
    74.                public InputStream getResourceAsStream(String name): 返回读取指定资源的输入流。
    75.                    指定资源: 类路径(该方法直接到类路径下扫描配置文件)
    76.                    如果配置文件写在src根下:
    77.                        String name: 只需要写文件名.扩展名 config.properties
    78.                    如果配置文件写在src/itheima02下:
    79.                        String name: itheima02/config.properties
    80.                        
    81. java.util.ResourceBundle类: 获取资源的类
    82.        注意: 该类是抽象类,不能直接创建对象,可以创建子类对象
    83.        发现:
    84.            该类中提供了静态方法,用于获取该抽象类的子类对象
    85.            public static final ResourceBundle getBundle(String baseName):
    86.           获取抽象类ResourceBundle的子类对象
    87.            参数:
    88.                String baseName: 如果配置文件写在src根下,此处只需要写文件名(不需要写扩展名)
    89.    
    90.        ResourceBundle类的成员方法:
    91.            public final String getString(String key):
    92.           根据String类型的属性名,获取String类型属性值(根据键找值)
    93. */
    94. public class Demo04ReflectTest {
    95.    public static void main(String[] args) throws Exception {
    96.        //创建子类管理类ResourceBundle的对象
    97.        ResourceBundle resourceBundle = ResourceBundle.getBundle("config");
    98.        //3.获取类的全名称和方法名称
    99.        String className = resourceBundle.getString("className");
    100.        String methodName = resourceBundle.getString("methodName");
    101.        //4.获取类的Class类型的对象
    102.        Class clazz = Class.forName(className);
    103.        //5.根据Class类型的对象获取要执行的方法对应的Method对象
    104.        Method eatMethod = clazz.getMethod("eat");
    105.        //6.Class类型的对象创建一个具体的对象出来
    106.        Object obj = clazz.newInstance();
    107.        //7.Method对象调用invoke方法,执行具体的功能
    108.        eatMethod.invoke(obj);
    109.   }
    110. }

     

    注解

    一、 注解的介绍

    1.概念:
    注解(Annotation): 也叫元数据。一种代码级别的说明。
    它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
    它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。   
    2.作用分类:
     (1)编写文档:通过代码里标识的注解生成文档【例如,生成文档doc文档】
     (2)代码分析:通过代码里标识的注解对代码进行分析【例如,注解的反射】
     (3)编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【例如,Override】​
    3.常见注解
    (1)@author:用来标识作者名
    (2)@version:用于标识对象的版本号,适用范围:文件、类、方法。
    (3)@Override:用来修饰方法声明,告诉编译器该方法是重写父类中的方法,如果父类不存在该方法,则编译失败。
    (4)@FunctionalInterface: 检测是否是函数式接口的

    Locale: zh_CN

    Other command line arguments:

     -encoding UTF-8 -charset UTF-8 -windowtitle "IOUtils类的使用" -link http://docs.Oracle.com/javase/7/docs/api
    

    二、 自定义注解

    格式:
      public @interface 注解名 {
                 属性集
                }
    ​
    1.空注解: 没有任何属性  看MyAnno01
    2.有属性集的注解:       看MyAnno02
         属性的定义格式一:数据类型 属性名(); 没有默认值的属性
         属性的定义格式二:数据类型 属性名() default 默认值; 有默认值的属性
    ​3.注解属性可以选择的数据类型: 8种基本类型,String类型,枚举类型,注解类型,Class类型以及以上任意类型对应的一维数组
     
    
    1. public class Demo03Annotation {
    2. }
    3. ​​​​​​​//空注解
    4. public @interface MyAnno01 {
    5. }
    6. //定义有属性集的注解
    7. public @interface MyAnno02 {
    8.    String name();//String 类型的属性 name,没有默认值
    9.    int age() default 18;//int 类型的属性 age,默认值 18
    10.    String[] hobbies();//String 类型的数组 hobbies
    11.    MyAnno01 myAnno01();//注解类型
    12. }

    三、自定义注解基本使用

    空注解使用格式: 直接使用
                   @注解名称            
    有属性集注解使用格式:
                   @注解名称(属性名1=属性值1,属性名2=属性值2,属性名3={元素1,元素2...})
    注意事项:
    1.空注解可以直接使用
    2.一个注解只能在一个位置上使用一次,一个位置上可以使用多个不同的注解
    3.如果注解有属性,那么必须给属性赋值才能使用键值对的方式赋值 属性名=属性值 多个属性,隔开。如果属性是数组类型 并且只有一个属性值 那么{}可以省略 如果多个属性值 {}不能省略
    4.如果属性没有默认值 必须赋值 如果有默认值 可以不赋值
    
    1. @MyAnno01
    2. //@MyAnno01 //同一位置不能使用第二次
    3. @MyAnno02(name="张三",age=28,hobbies={"看球","撸代码"},myAnno01=@MyAnno01)
    4. public class Demo04UseAnnotation {
    5.    @MyAnno01
    6.    @MyAnno02(name="李四",hobbies = "看球",myAnno01 = @MyAnno01)
    7.    public static void main(String[] args) {
    8.   }
    9. }

    四、 自定义注解使用的注意事项

    注意事项:
    ----重点----  MyAnno03,MyAnno04,MyAnno05
    - 当注解中只有一个属性且名称是value,在使用注解时给value属性赋值可以直接给属性值,
    无论value是单值元素还是数组类型。
    - 如果属性有默认值,则使用注解的时候,这个属性可以不用赋值。
    - 如果属性没有默认值,那么在使用注解时一定要给属性赋值。
    
    
    1. @MyAnno03("张三")
    2. @MyAnno04 //有默认值的属性,不管属性名是什么,都可以省略
    3. @MyAnno05({"打乒乓球","撸代码"})
    4. public class Demo05AnnotationNotice {
    5.    @MyAnno04("李四")
    6.    public static void main(String[] args) {
    7.   }
    8. }
    9. public @interface MyAnno03 {
    10.    String value();
    11. }
    12. public @interface MyAnno04 {
    13.    String value() default "李四";
    14. }
    15. public @interface MyAnno05 {
    16.    String[] value();
    17. }

    五、 元注解@Target介绍

    1.作用:
      用来限制自定义注解的生命周期(只存在于源代码中,存在于class文件中,存在于运行时期的内存中)
      用来限制自定义注解的使用范围(只能写在类上,只能写方法上,既能写在类上又能写在方法上等等)
    2.限制自定义注解的使用范围(在什么位置可以使用)
                元注解(限制自定义注解的注解)之@Target,源代码:
                public @interface Target {
                    ElementType[] value();
                }
    java.lang.annotation.ElementType 枚举 可以理解为类,里面都是静态内容,直接用类名/枚举名调用
    TYPE: 用在类,接口上
    FIELD:用在成员变量上
    METHOD: 用在方法上
    PARAMETER:用在参数上
    CONSTRUCTOR:用在构造方法上
    LOCAL_VARIABLE:用在局部变量上
    ​
    
    1. @MyAnno06
    2. public class Demo05YuanAnnotation {
    3.    //@MyAnno06 //错误了,该注解只能写在类/方法上
    4.    private String name;
    5.    @MyAnno06
    6.    public static void main(String[] args) {
    7.   }
    8. }
    9. /*
    10.    限制注解的使用范围: 指定写在类上/方法上
    11.    使用元注解: Target
    12. */
    13. @Target({ElementType.TYPE,ElementType.METHOD})
    14. public @interface MyAnno06 {
    15. }

    六、元注解@Retention介绍

    1.作用:
     用来限制自定义注解的生命周期(只存在于源代码中,存在于class文件中,存在于运行时期的内存中)
     用来限制自定义注解的使用范围(只能写在类上,只能写方法上,既能写在类上又能写在方法上等等)
    2.限制自定义注解的生命周期(存在到什么时候,源代码中,生成的.class文件中,还是运行.class文件的时)
                元注解(限制自定义注解的注解)之@Retention
                public @interface Retention {
                    RetentionPolicy value();
                }
    
    该注解是单属性的,属性名value,使用时,可以不写属性名
    java.lang.annotation.RetentionPolicy 枚举 可以理解为类,里面都是静态内容,直接用类名/枚举名调用
    SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了。
    CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,默认值。
    RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解。
    
    
    1. @MyAnno07
    2. //@MyAnno08//只能用在方法上/成员变量上
    3. public class Demo06YuanAnnotation {
    4.    //@MyAnno07 //错误了,该注解只能写在类/方法上
    5.    @MyAnno08
    6.    private String name;
    7.    @MyAnno07
    8.    @MyAnno08
    9.    public static void main(String[] args) {
    10.   }
    11. }
    12. /*
    13.    定义注解:
    14.        只能用在方法上/类上
    15.        保留在class文件中,运行时期内存中没有
    16. */
    17. @Target({ElementType.TYPE,ElementType.METHOD})
    18. @Retention(RetentionPolicy.CLASS)
    19. public @interface MyAnno07 {
    20. }
    21. /*
    22.    定义注解:
    23.        只能用在方法上/成员变量上
    24.        保留在源文件中,class文件中没有
    25. */
    26. @Target({ElementType.METHOD,ElementType.FIELD})
    27. @Retention(RetentionPolicy.SOURCE)
    28. public @interface MyAnno08 {
    29. }

    七、注解解析获取到类上的注解

    注解本质上就是一个接口,该接口默认继承Annotation接口
    java.lang.annotation.Annotation接口:所有注解类型的公共接口,类似所有类的父类是Object。
    前面用过的元注解 @Target @Retention 就是该接口的实现类对象
    需求说明
    1. 定义注解Books,要求如下:
        - 包含属性:String value()   书名
        - 包含属性:double price()  价格,默认值为 100
        - 包含属性:String[] authors() 多位作者
        - 限制注解使用的位置:类和成员方法上
        - 指定注解的有效范围:RUNTIME
    2. 定义BookStore类,在类和成员方法上使用Book注解
    3. 定义Demo06AnnotationTest测试类获取Book注解上的数据
    获取类上定义的注解
     java.lang.Class类,成员方法public  A getAnnotation(Class annotationClass)如果该元素的指定注解类型的注解存在于此对象(Class对象)上,则返回这个注解,否则返回 null;获得当前对象上指定的注解对象。
    ​public boolean isAnnotationPresent(Class annotationClass):判断当前对象(Class对象)是否有指定的注解,有则返回true,否则返回false。​​
    步骤:
    1.获取类的Class类型的对象
    2.Class类型的对象调用方法,判断是否具有Books注解
    3.如果有,Class类型的对象调用方法获取Books注解对象
    4.打印Books注解对象的属性值
    
    1. /*
    2.    定义注解Books,要求如下:
    3.       - 包含属性:String value()   书名
    4.       - 包含属性:double price() 价格,默认值为 100
    5.       - 包含属性:String[] authors() 多位作者
    6.       - 限制注解使用的位置:类和成员方法上
    7.       - 指定注解的有效范围:RUNTIME
    8. */
    9. //限制注解使用的位置:类和成员方法上
    10. @Target({ElementType.TYPE,ElementType.METHOD})
    11. //指定注解的有效范围:RUNTIME
    12. @Retention(RetentionPolicy.RUNTIME)
    13. public @interface Books {
    14.    String value();//书名
    15.    double price() default 100;//价格,默认值为 100
    16.    String[] authors();//多位作者
    17. }
    18. @Books(value = "面向对象",price = 180,authors = {"响哥","刚哥"})
    19. public class BookStore {
    20.    @Books(value = "jdk8新特性",authors = "响哥")
    21.    public void show() {
    22.   }
    23. }
    24. //获取类上注解信息的测试类
    25. public class Demo06AnnotationTest {
    26.    @Test
    27.    public void getParseClassAnnotation() throws Exception {
    28.        //1.获取类的Class类型的对象
    29.        Class clazz = Class.forName("itheima06.BookStore");
    30.        //2.Class类型的对象调用方法,判断是否具有Books注解
    31.        if(clazz.isAnnotationPresent(Books.class)) {
    32.            //3.如果有,Class类型的对象调用方法获取Books注解对象
    33.            Books booksAnno = clazz.getAnnotation(Books.class);
    34.            //4.打印Books注解对象的属性值
    35.            String bookName = booksAnno.value();
    36.            double price = booksAnno.price();
    37.            String[] authors = booksAnno.authors();
    38.            System.out.println(bookName+"::"+price+"::"+ Arrays.toString(authors));
    39.       }
    40.   }
    41. }

    八、注解解析获取到方法上的注解

    注解本质上就是一个接口,该接口默认继承Annotation接口
     java.lang.annotation.Anontation接口:所有注解类型的公共接口,类似所有类的父类是Object。
                前面用过的元注解 @Target @Rentention 就是该接口的实现类对象
    需求说明
    ​1. 定义注解Books,要求如下:
               - 包含属性:String value()   书名
               - 包含属性:double price()  价格,默认值为 100
               - 包含属性:String[] authors() 多位作者
               - 限制注解使用的位置:类和成员方法上
               - 指定注解的有效范围:RUNTIME
    2. 定义BookStore类,在类和成员方法上使用Book注解
    3. 定义Demo06AnnotationTest测试类获取Book注解上的数据
    获取类上定义的注解
    java.lang.reflect.Method类,
    成员方法public  A getAnnotation(Class annotationClass)
    如果该元素的指定注解类型的注解存在于此对象(Class对象)上,则返回这个注解,否则返回 null
    获得当前对象上指定的注解对象。
    public boolean isAnnotationPresent(Class annotationClass):判断当前对象(Class对象)是否有指定的注解,有则返回true,否则返回false。
    步骤:
    1.获取类的Class类型的对象
    2.Class类型的对象调用方法,获取方法对象
    3.方法对象调用方法,判断是否具有Books注解
    4.如果有,方法对象调用方法获取Books注解对象
    5.打印Books注解对象的属性值
    总结:
    1、java.lang.reflect.AnnotatedElement接口: 规定操作注解的方法
    2、public abstract boolean isAnnotationPresent(Class clazz): 判断是否含有指定参数类型的注解,有返回true,没有返回false
    3、public abstract  T getAnnotation(Class clazz):获取指定参数类型的注解对象,没有获取到的,返回null
    参数:Class clazz: 注解的Class对象
    常用实现类:Class,Method,Constructor,Field  类 都实现了以上方法             
    总结:
    1.获取类上的注解: 使用Class对象直接获取
    2.获取方法上的注解: 使用Method对象直接获取
    3.获取构造方法上的注解: 使用Constructor对象直接获取
    4.获取成员变量上的注解: 使用Field对象直接获取
    注意:Method对象/Constructor对象/Field对象 都被必须由Class对象获取
    
    1. public class Demo07AnnotationTest {
    2.    @Test
    3.    public void parseMethodAnnotation() throws Exception {
    4.        //1.获取类的Class类型的对象
    5.        Class clazz = Class.forName("itheima06.BookStore");
    6.        //2.Class类型的对象调用方法,获取方法对象
    7.        Method showMethod = clazz.getMethod("show");
    8.        //2.方法对象调用方法,判断是否具有Books注解
    9.        if(showMethod.isAnnotationPresent(Books.class)) {
    10.            //3.如果有,方法对象调用方法获取Books注解对象
    11.            Books booksAnno = showMethod.getAnnotation(Books.class);
    12.            //4.打印Books注解对象的属性值
    13.            String bookName = booksAnno.value();
    14.            double price = booksAnno.price();
    15.            String[] authors = booksAnno.authors();
    16.            System.out.println(bookName+"::"+price+"::"+ Arrays.toString(authors));
    17.       }
    18.   }
    19. }

     

     

  • 相关阅读:
    双机热备综合实验(VRRP+OSPF+VTP+NAT+DHCP)
    数据结构难题小解析
    Maven编译打包本地jar包rt.jar
    单元测试的重要性
    js数组方法复习汇总
    《搞定音频技术》
    类型与特点
    《动手学深度学习 Pytorch版》 8.6 循环神经网络的简洁实现
    主站侧通讯问题定位工具
    Django更换数据库和迁移数据方案
  • 原文地址:https://blog.csdn.net/qq_49047454/article/details/126921130