Java进阶学习完结:【单元测试、反射、暴力反射、注解、模拟WEB服务器】

  • A+
所属分类:Java Java进阶

01. 单元测试的基本使用

/*
    单元测试用于替换程序中的main方法, 程序可以从单元测试方法开始执行。
    如果在一个方法上加上了@Test注解,那么这个方法就是单元测试方法了,程序可以从这个方法开始执行。

    方法的要求:
        1. 一般以test开头(软性规定)
        2. public修饰,没有返回值, 没有参数(硬性规定)

    运行方式:
        1. 选中方法,然后右键run
        2. 选中类,然后右键run。 会运行该类所有的单元测试方法。
 */
public class Demo01JUnit {
    @Test
    public void testMethod() {
        System.out.println("testMethod");
    }
    @Test
    public void testFunction() {
        System.out.println("testFunction");
    }
}

02. 单元测试的其他注解

/*
    单元测试中的其他注解:
        @Before: 使用Before修饰的方法, 会在每次单元测试方法执行之前执行。
        @After: 使用After修饰的方法, 会在每次单元测试方法执行之后执行。
        @BeforeClass: 使用BeforeClass修饰的方法, 会在所有单元测试方法执行之前执行。终身只执行一次。
        @AfterClass: 使用AfterClass修饰的方法, 会在所有单元测试方法执行之后执行。终身只执行一次。
                      被BeforeClass以及AfterClass修饰的方法必须使用static修饰。
 */
public class Demo02JUnit {

    @AfterClass
    public static void afterClassMethod() {
        System.out.println("afterClassMethod...");
    }

    @BeforeClass
    public static void beforeClassMethod() {
        System.out.println("beforeClassMethod...");
    }

    @Before
    public void beforeMethod() {
        System.out.println("beforeMethod...");
    }

    @After
    public void afterMethod() {
        System.out.println("afterMethod...");
    }

    @Test
    public void testMethod() {
        System.out.println("testMethod...");
    }

    @Test
    public void testFunction() {
        System.out.println("testFunction...");
    }
}

03. 反射的介绍

参考 Java基础学习完结:【Junit、反射、注解】的图

04. 获取Class对象的三种方式

public class Person {
    private String name;
    private int age;
    public String hobby;//爱好

    public void sleep(String address, int time) {
        System.out.println("在" + address + "睡觉, 睡了" + time + "秒");
    }

    public void eat() {
        System.out.println("吃饭");
    }

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

    public Person() {
    }

    private Person(String name) {
        this.name = name;
    }

    public Person(String name, int age) {

        this.name = name;
        this.age = 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;
    }
}

/*
    获取一个类的Class对象的三种方式:
        1. 通过对象调用getClass方法获取。
            Class getClass():可以通过对象获取类的Class
        2. 通过类的class属性获取。 每一个数据类型都有一个隐藏的属性叫做class, 可以获取对应的Class对象
            类名.class
        3. 通过Class的静态方法forName获取
            static Class forName(String className): 参数要传递一个全类名(包含包的类名), 并获取该类的Class对象。

    一个类只有一个Class类型的对象,无论怎么获取,获取的都是同一个Class
 */
public class Demo01GetClass {
    public static void main(String[] args) throws ClassNotFoundException {
        //1. 通过对象调用getClass方法获取。
        Person p = new Person();
        Class clazz = p.getClass();//获取到的Class对象里面保存的是Person类的信息,是用来描述Person类的。
        System.out.println(clazz);

        //2. 通过类的class属性获取。
        Class clazz2 = Person.class;
        System.out.println(clazz2);

        //3. 通过Class的静态方法forName获取
        Class clazz3 = Class.forName("cn.itcast.demo02_reflect.Person");
        System.out.println(clazz3);

        System.out.println(clazz == clazz2);
    }
}

05. Class中的常见方法

/*
    Class中的常见的方法:
        String getName(): 获取类的名字(含有包的类名)
        String getSimpleName(): 获取简单的类名(不含包的类名)
        (重要)T newInstance():直接创建该类的对象(使用的空参构造创建对象)
 */
public class Demo02ClassMethod {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //获取Person类的Class对象
        //该Class对象保存了Person类的信息。
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //String getName(): 获取类的名字(含有包的类名)
        System.out.println(clazz.getName()); //cn.itcast.demo02_reflect.Person
        //String getSimpleName(): 获取简单的类名(不含包的类名)
        System.out.println(clazz.getSimpleName());//Person
        System.out.println("===========================");

        //(重要)T newInstance():直接创建该类的对象(使用的空参构造创建对象)
        Object obj = clazz.newInstance(); //因为clazz是Person的Class对象,所以使用newInstance方法创建的是Person对象。
        //System.out.println(obj);
        Person p = (Person) obj;
        System.out.println(p.getName() + "-" + p.getAge());
    }
}

06. 反射获取空参构造方法并使用

/*
    反射获取构造方法

    在Class中,有一个方法叫做getConstructor,可以获取一个类中的构造方法
        Constructor[] getConstructors(): 获取类的中的所有的构造方法。
        Constructor getConstructor(Class... parameterTypes): 获取一个类中指定的构造方法。 参数为构造方法的参数列表。
        上面两个方法只能获取public权限的方法,其他权限的无法获取。

    Constructor表示构造方法, 里面的功能有:
        T newInstance(Object... initargs): 使用该构造方法创建对象, 参数为调用构造方法时传递的实际参数。
 */
public class Demo03ReflectConstructor {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        method2();
    }

    /*
        Constructor getConstructor(Class... parameterTypes): 获取一个类中指定的构造方法。
        获取Person类中的空参数的构造方法, 然后根据这个空参数的构造方法创建对象。
     */
    public static void method2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取Person类的Class对象
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //获取类中的空参数构造方法
        //Constructor getConstructor(Class... parameterTypes): 获取一个类中指定的构造方法。 参数是要获取的构造方法的参数列表
        Constructor c = clazz.getConstructor();//如果getConstructor不写任何参数,表示的是获取空参数的构造方法。
        //使用空参构造方法创建对象
        Object obj = c.newInstance();//因为获取的是空参数构造方法,所以不需要传递参数, 所以newInstance省略参数。
        System.out.println(obj);
    }

    /*
        Constructor[] getConstructors(): 获取类的中的所有的构造方法。
     */
    public static void method() throws ClassNotFoundException {
        //获取Person类的Class对象
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //Constructor[] getConstructors(): 获取类的中的所有的构造方法。
        Constructor[] cs = clazz.getConstructors();
        //遍历数组,打印里面的每一个内容
        for(Constructor c : cs) {
            System.out.println(c);
        }
    }
}

07. 反射获取有参构造方法并使用

/*
    Class中获取Constructor的方法
        Constructor[] getConstructors(): 获取类的中的所有的构造方法。
        Constructor getConstructor(Class... parameterTypes): 获取一个类中指定的构造方法。 参数为构造方法的参数列表。
        上面两个方法只能获取public权限的方法,其他权限的无法获取。

    Constructor表示构造方法, 里面的功能有:
        T newInstance(Object... initargs): 使用该构造方法创建对象, 参数为调用构造方法时传递的实际参数。

    注意: 所有的数据类型都有class属性,包括基本类型。

    反射主要就三个步骤:
        1. 获取类的Class对象。
        2. 通过Class对象获取类的内容(构造方法,成员方法, 成员变量)
        3. 使用这个内容。
 */
public class Demo04ReflectConstructor {
    //通过反射获取有参构造,并根据有参构造创建对象。
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取类的Class对象
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //获取有参构造
        //public Person(String name, int age)
        Constructor c = clazz.getConstructor(String.class, int.class);//表示要获取的构造方法第一个参数是String,第二个参数是int。
        //T newInstance(Object... initargs): 使用该构造方法创建对象。参数表示调用构造方法时传递的实际参数。
        Object obj = c.newInstance("老王", 20);//因为c表示的是两个参数的构造方法,所以使用该构造方法创建对象时,必须要传递两个实际参数。
        System.out.println(obj);
    }
}

08. 暴力反射构造方法

/*
    暴力反射(不推荐,因为会破坏封装性)

    暴力反射构造方法,可以使用Class中的以下方法获取Constructor:
        Constructor[] getDeclaredConstructors():获取所有的构造方法(任何权限,包括私有)
        Constructor getDeclaredConstructor(Class... parameterTypes): 获取指定给的构造方法(任何权限,包括私有)

    私有的成员虽然可以通过暴力反射的方法获取到,但是不能直接使用, 因为在Java中有一个安全检查机制,私有的内容是不能再外边直接使用的。
    解决方式: 取消这个安全检查机制。

    Constructor表示构造方法
    Method 表示成员方法
    Field 表示成员变量。
    上面这些类有一个公共的父类AccessibleObject, 这个父类中有一个方法可以取消安全检查机制。
        void setAccessible(boolean flag): 如果参数是true表示取消权限检查。
 */

public class Demo05ReflectConstructor {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        method2();
    }

    /*
        Constructor getDeclaredConstructor(Class... parameterTypes)获取指定给的构造方法(任何权限,包括私有)
        获取Person中的private修饰的构造方法,并且使用该构造方法创建对象
        构造方法:private Person(String name)
     */
    public static void method2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取类的Class对象
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //获取指定的私有的构造方法
        //private Person(String name)
        Constructor c = clazz.getDeclaredConstructor(String.class);
        //在使用私有的构造方法之前,取消安全检查机制
        c.setAccessible(true);
        //通过获取到的构造方法创建对象
        Object obj = c.newInstance("诸葛亮");
        System.out.println(obj);
    }

    /*
        Constructor[] getDeclaredConstructors():获取所有的构造方法(任何权限,包括私有)
     */
    public static void method() throws ClassNotFoundException {
        //获取类的Class对象
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //调用getDeclaredConstructors获取所有的构造方法
        Constructor[] cs = clazz.getDeclaredConstructors();
        //遍历数组
        for (Constructor c : cs) {
            System.out.println(c);
        }
    }
}

09. 反射获取空参成员方法并执行

/*
    反射获取成员方法。

    Class中有一些方法,可以获取到一个类中的成员方法:
        Method[] getMethods(): 获取到类中所有的成员方法。
        Method getMethod(String name, Class... parameterTypes):获取到的类中的指定的成员方法。 第一个参数是方法名, 第二个参数是该方法的参数列表。
        上面两个方法只能获取到一个类中public权限的成员方法。

    Method表示的是成员方法,Method有一些功能:
        Object invoke(Object obj, Object... args): 让该方法执行。
            参数obj: 表示调用者对象。  如果调用的是静态方法,该参数传递null。
            参数args: 表示调用方法时传递的实际参数。
            返回值Object表示方法调用后的结果。
 */
public class Demo06ReflectMethod {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        method2();
    }
    /*
         Method getMethod(String name, Class... parameterTypes):获取到的类中的指定的成员方法。 第一个参数是方法名, 第二个参数是该方法的参数列表。
         获取Person中的eat()方法, 并让eat方法执行
     */
    public static void method2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //获取类的Class对象
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //获取Person中的eat方法
        Method m = clazz.getMethod("eat");//第一个参数eat表示要获取的方法名是eat,第二个参数可变参数没有传递任何内容,表示获取的是空参数的eat方法
        //调用invoke,让方法执行
        //创建一个Person对象,用来执行方法
        Object obj = clazz.newInstance();
        //Object invoke(Object obj, Object... args): 让该方法执行。
        //m表示的是eat方法,所以是eat方法执行, 因为第一个参数是obj,所以表示通过obj调用了eat方法,
        //第二个参数应该是可变参数, 但是没有写任何东西,表示没有传递任何实际参数
        m.invoke(obj); //相当于 obj.eat();
    }

    /*
        Method[] getMethods(): 获取到类中所有的成员方法。
     */
    public static void method() throws ClassNotFoundException {
        //获取类的Class对象
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //通过类的Class对象调用getMethods获取所有的成员方法
        Method[] methods = clazz.getMethods();
        //遍历打印数组
        for (Method method : methods) {
            System.out.println(method);
        }
    }
}

10. 反射获取成员方法

/*
    反射获取有参成员方法并执行

    Class中有一些方法,可以获取到一个类中的成员方法:
        Method[] getMethods(): 获取到类中所有的成员方法。
        Method getMethod(String name, Class... parameterTypes):获取到的类中的指定的成员方法。 第一个参数是方法名, 第二个参数是该方法的参数列表。
        上面两个方法只能获取到一个类中public权限的成员方法。

    Method表示的是成员方法,Method有一些功能:
        Object invoke(Object obj, Object... args): 让该方法执行。
            参数obj: 表示调用者对象。  如果调用的是静态方法,该参数传递null。
            参数args: 表示调用方法时传递的实际参数。
            返回值Object表示方法调用后的结果。
 */
public class Demo07ReflectMethod {
    //获取有参成员方法并执行
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //获取类的Class
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //获取Person中的sleep方法
        //public void sleep(String address, int time)
        Method method = clazz.getMethod("sleep", String.class, int.class);
        //调用这个sleep方法,让它执行
        //创建一个Person对象
        Object obj = clazz.newInstance();
        //通过invoke方法让sleep执行
        method.invoke(obj, "天上人间", 3);// 相当于obj.sleep("天上人间", 3);
    }
}

11. 反射获取set方法以及get方法完成赋值以及取值

/*
    反射获取set/get方法分别完成赋值和取值的操作。

    setName/getName
 */
public class Demo08ReflectMethod {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //获取Person的Class
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //通过Class创建Person对象
        Object obj = clazz.newInstance();
        //获取setName方法给对象属性赋值
        //clazz调用getMethod获取方法
        Method setMethod = clazz.getMethod("setName", String.class);//获取setName方法,setName有一个字符串的参数
        //执行setName
        setMethod.invoke(obj, "王叔叔");//相当于obj.setName("王叔叔");

        //获取getName方法,然后通过getName方法获取姓名的值。
        Method getMethod = clazz.getMethod("getName");
        Object result = getMethod.invoke(obj); //obj.getName();
        System.out.println(result);
    }
}

12. 反射操作成员变量

/*
    反射获取成员变量(了解)

    在Class中有一些方法可以获取到成员变量
        Field[] getFields():获取到类中所有的成员变量。
        Field getField(String name) :获取类中的指定的成员变量,参数是成员变量的名字。
        上面两个方法只能获取到public权限的成员变量。

    Field表示成员变量,里面也有一些功能:
        void set(Object obj, Object value):给成员变量设置值。
            参数obj:表示给哪个对象的成员变量设置值。
            参数value:表示设置成什么值。
        Object get(Object obj): 获取该成员变量的值。
            参数obj: 表示获取哪个对象的成员变量的值。
            返回值Object: 表示获取到的结果。

 */
public class Demo09ReflectFiled {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        method2();
    }

    /*
        获取Person中的hobby成员变量,赋值。
     */
    public static void method2() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        //获取Person的Class
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //获取hobby成员变量
        Field field = clazz.getField("hobby");
        //给hobby属性赋值
        //创建Person对象
        Object obj = clazz.newInstance();
        //给Person对象的hobby属性赋值
        field.set(obj, "编程");//相当于obj.hobby="编程"
        //获取obj的hobby属性值
        System.out.println(field.get(obj));//相当于输出流 obj.hobby
    }

    /*
        获取Person中的所有的成员变量
     */
    public static void method() throws ClassNotFoundException {
        //获取Person的Class
        Class clazz = Class.forName("cn.itcast.demo02_reflect.Person");
        //通过class对象获取所有的成员变量
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
    }
}

14. 常见的注解以及作用

/*
    注解: @XXX

    1. 注解是从JDK5之后才开始有的。
    2. 注解可以加在类上面, 方法上, 成员变量上, 方法参数上....
    3. 注解是用来完成功能的,每一个注解都可以完成一些功能。

    注解和注释的区别:
        注释:注释是给程序员看的, 注释不会影响到程序的编译和执行。
        注解:注解是给程序看的, 会影响到程序的运行, 程序会根据注解完成一些功能。

    常见的注解:
        @Override: 用来检查方法是否是重写父类的方法。
        @FunctionalInterface: 检查接口是否是函数式接口。
        @Deprecated:标注方法已经过时,不推荐使用。
 */
public class Demo01Anno {
    public static void main(String[] args) {
        method();
    }

    @Deprecated
    public static void method() {
        System.out.println("非常好用的方法");
    }
}

15. 注解的定义以及使用

/*
    自定义注解的格式:
        public @interface 注解名 {

        }
 */
public class Demo02Anno {
    @Student(name = "王叔叔", age = 18, hobbies = "洗脚")
    public void method() {

    }
}
/*
    在注解中,可以定义一些属性

    属性格式:
        数据类型 属性名();
        数据类型 属性名() default 默认值;

    注解中的属性的数据类型只能是下面这几种
        1. 八种基本数据类型(byte short int long float double boolean char)
        2. Class, String, 枚举, 注解
        3. 以上所有类型的一维数组。

    注解可以加在类上面, 方法上, 成员变量上, 方法参数上....
    使用格式为@注解名

    给注解属性赋值的格式
        @注解名(属性名=属性值, 属性名=属性值)

    注意:
        1. 如果注解中的属性没有默认值,那么在使用的时候必须要进行赋值
        2. 如果注解中的属性有默认值,那么在使用的时候可以赋值也可以不赋值, 如果不赋值该属性的值就是默认值。
        3. 如果注解中的属性是一个数组, 那么在赋值的使用可以使用大括号包裹多个内容。
        4. 如果注解中的属性是一个数组, 在赋值的时候只需要赋值一个元素,那么可以省略大括号。
 */
public @interface Student {
    //姓名
    String name();

    //年龄属性,默认值为0
    int age() default 0;

    //爱好属性
    String[] hobbies();
}

16. 注解中的特殊属性value

/*
    特殊属性value

    如果一个注解中只有一个没有默认值的属性(可以有多个属性,但是没有默认值必须是1个), 并且这个属性叫做value,那么在给该属性赋值的使用,可以省略属性名。否则必须写全。
 */
public @interface Book {
    String value();
    int price() default 10;
}
@Book("西游记")
public class Demo03Anno {
    @Book("红楼梦")
    int num;

    @Book("三国演义")
    public void method() {

    }
}

17. Target元注解的使用

/*
    元注解:
        1. 元注解也是注解。
        2. 元注解是用来修饰注解的注解。
        3. 元注解要加在注解上面, 可以对某些注解进行一些限制。

    常见的元注解:
        [email protected]
        [email protected]
 */
@MyAnno
public class Demo01Anno {
    @MyAnno
    public void method() {

    }
}

/*
    @Target是一个元注解,用来修饰注解。

    @Target用来限制注解的使用位置, 如果不使用@Target进行限制,那么注解可以在任何位置使用。

    Target中有一个属性叫做value, 这个属性用来表示被修饰的注解可以使用在哪些位置。
    value是ElementType数组类型, 里面可以传递多个数据。

    ElementType是一个枚举,枚举就是一个特殊的类, 枚举中的每一个属性都是本身类型, 枚举中的属性可以通过枚举名直接调用。
    ElementType中的每一个属性都有特别的含义:
        ElementType.TYPE: 用在类,接口上
        ElementType.FIELD:用在成员变量上
        ElementType.METHOD: 用在方法上
        ElementType.PARAMETER:用在参数上
        ElementType.CONSTRUCTOR:用在构造方法上
        ElementType.LOCAL_VARIABLE:用在局部变量上

    我们要向Target的value属性位置传递ElementType中的属性,不同的属性有不同的含义。

 */
//@Target(ElementType.TYPE)//被修饰的注解只能使用在类的上面。
//@Target(ElementType.METHOD) //被修饰的注解只能用在方法上
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnno {
}

18. Retention元注解的使用

@MyAnno1
@MyAnno2
@MyAnno3
public class Demo02Anno {
}
/*
    @Retention 元注解, 用来修饰注解。
    @Retention用来限制注解的生命周期, 如果使用@Retention修饰, 注解默认只在源代码阶段以及.class文件中有效,运行时期内存中是没有的。

    Retention只有一个属性叫做value, 这个属性是RetentionPolicy类型。 该属性表示的是被修饰的注解的生命周期。

    RetentionPolicy是一个枚举类型, 里面的每一个属性都有特别的含义。 我们要向Retention的value属性位置传递RetentionPolicy的属性。

    RetentionPolicy每个属性的含义:
       RetentionPolicy.SOURCE: 被修饰的注解只在源代码阶段有效, 一旦编译,到了.class中就会消失。
       RetentionPolicy.CLASS: 被修饰的注解只在源代码以及编译后的.class中有效
       RetentionPolicy.RUNTIME: 被修饰的注解在源代码阶段,编译后的.class中,运行时内存中有效。
 */
@Retention(RetentionPolicy.SOURCE)//表示被修饰的注解只在源代码阶段有效
public @interface MyAnno1 {
}

@Retention(RetentionPolicy.CLASS)//被修饰的注解在源代码以及class中有效
public @interface MyAnno2 {
}

@Retention(RetentionPolicy.RUNTIME)//被修饰的注解在源代码,class,运行时内存中都有效。
public @interface MyAnno3 {
}

19. 注解的解析

/*
    注解的解析: 注解解析就是获取注解中的内容(比如属性),并进行处理。

    解析相关的API:
        Annotation:接口, 所有注解都默认实现了这个接口。
        AnnotatedElement: 接口, 里面定义了很多方法可以操作注解
            Annotation[] getAnnotations():获取所有的注解
            T getAnnotation(Class annotationClass):获取指定的注解, 方法参数传递的是哪个注解的Class,那么获取的就是哪个注解。
            boolean isAnnotationPresent(Class annotationClass): 判断指定注解是否存在。 参数为注解的Class。

        解析注解需要结合反射技术去使用, 我们之前学习的Class,Method,Constructor,File反射有关的都实现了AnnotatedElement接口

        如果要操作类上面的注解,那么我们就使用Class调用AnnotatedElement中的方法操作注解就可以了
        如果要操作方法上面的注解,那么我们就使用Method调用AnnotatedElement中的方法操作注解就可以了
        如果要操作成员变量上面的注解,那么我们就使用Field调用AnnotatedElement中的方法操作注解就可以了

 */
//获取BookStore这个类上面的Book注解中的属性,并进行输出。
public class Demo01AnnoParse {
    public static void main(String[] args) throws ClassNotFoundException {
        //因为要获取BookStore类上面的注解,所以要先获取BookStore的Class对象
        Class clazz = Class.forName("cn.itcast.demo05_anno_parse.BookStore");
        //调用isAnnotationPresent判断这个类上面有么有注解。
        boolean flag = clazz.isAnnotationPresent(Book.class);//判断有没有Book注解
        //判断,如果有注解,那么就获取该注解
        if(flag) {
            //获取BookStore这个类上面Book注解
            Annotation a = clazz.getAnnotation(Book.class);
            //向下转型
            Book book = (Book)a;
            //获取book中的属性并输出
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(book.author());
        }
    }
}

@Book(value = "Java从入门到精通", author = "佚名")
public class BookStore {

}
@Retention(RetentionPolicy.RUNTIME) //修改该注解的生命周期,让这个注解在运行时期内存中也有效。
public @interface Book {
    //value表示书名
    String value();
    //price表示价格
    int price() default 100;
    //author 作者
    String author();
}

20. 模拟单元测试

/*
    练习: 定义@MyTest注解, 模拟单元测试。

    定义@MyTest注解,在多个方法上面加上这个@MyTest注解,然后运行带有@MyTest注解的方法。

    步骤:
        获取MyTestDemo的所有的方法,遍历这些方法,判断遍历到的方法上有没有@Test注解,如果有,就让该方法执行。
 */
public class Demo01Test {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //获取MyTestDemo的Class对象
        Class clazz = Class.forName("cn.itcast.demo06_anno_test.MyTestDemo");
        //创建对象,以后调用方法使用。
        Object obj = clazz.newInstance();
        //clazz调用getMethods,获取到所有的方法(public权限)
        Method[] methods = clazz.getMethods();
        //遍历这些方法
        for (Method method : methods) {
            //判断遍历到的方法上有没有MyTest注解
            if(method.isAnnotationPresent(MyTest.class)) {
                //如果方法上有这个注解,那么就让这个方法执行。
                method.invoke(obj);
            }
        }
    }
}
@Retention(RetentionPolicy.RUNTIME) //使用元注解修饰, 让该注解在运行时期内存中也有效。
@Target(ElementType.METHOD)//限制该注解只能用在方法上。
public @interface MyTest {
}
public class MyTestDemo {
    public void methodA() {
        System.out.println("methodA....");
    }

    @MyTest
    public void methodB() {
        System.out.println("methodB....");
    }

    public void methodC() {
        System.out.println("methodC....");
    }

    @MyTest
    public void methodD() {
        System.out.println("methodD....");
    }

    public void methodE() {
        System.out.println("methodE....");
    }
}
  • 资源分享QQ群
  • weinxin
  • 官方微信公众号
  • weinxin
沙海
美女讲师教你学C语言
网站https安全证书安装,伪静态配置
C语言速查手册
AnyNode:最便宜的国外服务器

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: