基础加强:反射和注解

目录

一、Junit单元测试

1.什么是单元测试

2.Junit的使用步骤

3.单元测试中其它四个注解

二、反射

1.类的加载

2.什么是反射

3.反射在实际开发中的应用

4.反射中万物皆对象的概念

5.反射的第一步获取字节码文件对象(Class对象)

6.Class对象中的三个常用方法

7.通过反射获取构造方法

8.Constructor类中常用方法

9.通过反射获取成员方法

10.Method类中常用方法

11.通过反射获取成员属性(了解)

12.Field类中常用方法(了解)

三、注解

1. JDK1.5的新特性

2.注解的两个作用

3.常用注解介绍

4.自定义注解

5.给自定义注解添加属性

6.使用自定义注解

7.自定义注解中的特殊属性名

8.注解之元注解

(1)@Target元注解

(2)@Retention元注解

9.注解的解析

(1)确定注解所在的对象

(2)确定注解是否真实存在,获取该注解对象

10.注解综合练习


一、Junit单元测试

1.什么是单元测试

Junit是一个Java语言的单元测试框架,属于白盒测试,简单理解为可以用于取代java的main方法。Junit属于第三方工具,需要导入jar包后使用。

2.Junit的使用步骤

(1)编写测试类,简单理解Junit可以用于取代java的main方法

(2)在测试类方法上添加注解 @Test

(3)@Test修饰的方法要求:public void 方法名() {…} ,方法名自定义建议test开头,没有参数。

(4)添加Junit库到lib文件夹中,然后进行jar包关联

3.单元测试中其它四个注解

@Before:修饰的方法会在测试方法之前被自动执行

@After:修饰的方法会在测试方法执行之后自动被执行

@BeforeClass:在所有的测试方法运行之前,只运行一次,而且必须用在静态方法上。

@AfterClass:在所有的测试方法运行之后,只运行一次,而且必须用在静态方法上。

二、反射

1.类的加载

当类的字节码文件被加到内存之后,JVM自动为之创建一个对象(该对象中保存字节码的所有信息),这个对象我们一般称为字节码文件对象或者Class对象

2.什么是反射

获取Class对象,解剖它,从中取出构造方法,成员变量,成员方法,进而使用它们。

3.反射在实际开发中的应用

(1)编写各种IDE(IDEA,Eclipse)

(2)编写各种框架

4.反射中万物皆对象的概念

(1)字节码文件:Class对象
           (2)构造方法:Constructor对象
           (3)成员方法:Method对象
           (4)成员变量:Field对象
           (5)newInstance:创建对象
           (6)invoke:执行/调用

5.反射的第一步获取字节码文件对象(Class对象)

6.Class对象中的三个常用方法

String getSimpleName(); 获得简单类名,只是类名,没有包

String getName(); 获取完整类名,包含包名+类名

T newInstance() ;创建此 Class 对象所表示的类的一个新实例。要求:类必须有public的无参数构造方法

  newInstance()方法在JDK1.9之后过时了,需用下述方法替代:

                      clazz.getDeclaredConstructor().newInstance()

7.通过反射获取构造方法

(1)Constructor getConstructor(Class... parameterTypes)

根据参数类型获取构造方法对象,只能获得public修饰的构造方法。

如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。

(2)Constructor getDeclaredConstructor(Class... parameterTypes)

根据参数类型获取构造方法对象,包括private修饰的构造方法。

如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。

(3)Constructor[] getConstructors()

获取所有的public修饰的构造方法

(4)Constructor[] getDeclaredConstructors()

获取所有构造方法,包括private修饰的构造方法

8.Constructor类中常用方法

(1)T newInstance(Object... initargs)

根据指定参数创建对象。

(2)void setAccessible(true)

暴力反射,设置为可以直接访问私有类型的构造方法。

9.通过反射获取成员方法

(1)Method getMethod("方法名", 方法的参数类型... 类型)

根据方法名和参数类型获得一个方法对象,只能是获取public修饰的

(2)Method getDeclaredMethod("方法名", 方法的参数类型... 类型)

根据方法名和参数类型获得一个方法对象,包括private修饰的

(3)Method[] getMethods()

获取所有的public修饰的成员方法,包括父类

(4)Method[] getDeclaredMethods()

获取当前类中所有的方法,包含私有的,不包括父类

10.Method类中常用方法

(1)Object invoke(Object obj, Object... args)

根据参数args调用对象obj的该成员方法

如果obj=null,则表示该方法是静态方法

(2)void setAccessible(boolean flag)

暴力反射,设置为可以直接调用私有修饰的成员方法

11.通过反射获取成员属性(了解)

public Field[] getFields():获取public修饰的所有的变量对象

public Field[] getDeclaredFields():获取所有的变量对象,包括私有

public Field getField(String name):获取指定变量名的public修饰的变量对象

public Field getDeclaredField(String name):获取指定变量名的变量对象,包括私有

12.Field类中常用方法(了解)

(1)Object get(Object obj):返回由该 Field表示的字段在指定对象上的值。

(2)void set(Object obj, Object value):将指定的对象参数中由此 Field对象表示的字段设置为指定的新值。

(3)void setAccessible(boolean flag) 将此反射对象的 accessible标志设置为指示的布尔值。  

(4)Class<?> getType():返回一个 Class对象,标识由该 Field对象表示的字段的声明类型。  

三、注解

1. JDK1.5的新特性

一种标记,标记在类中,接口中,方法上,变量上。

2.注解的两个作用

(1)编译检查

(2)框架的配置文件

3.常用注解介绍

@override(编译检查方法重写是否正常)

@FunctionalInterface:编译检查是否符合函数式接口的要求(只有一个抽象方法)

@Oeprecated:编译检查是否过时

4.自定义注解

格式:

public @interface 注解名称{

属性列表;

}

5.给自定义注解添加属性

(1)属性的作用

可以让用户在使用注解时传递参数,让注解的功能更加强大。

(2)属性的格式

格式:格式1:数据类型 属性名();

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

(3)属性定义实例

public @interface Student {

String name(); // 姓名

int age() default 18; // 年龄

String gender() default "男"; // 性别

}

// 该注解就有了三个属性:name,age,gender

(4)属性适用的数据类型

八种基本数据类型(int,float,boolean,byte,double,char,long,short)

String类型,Class类型,枚举类型,注解类型

以上所有类型的一维数组

6.使用自定义注解

(1)定义一个注解:Book

包含属性:String value() 书名

包含属性:double price() 价格,默认值为 100

包含属性:String[] authors() 多位作者

(2)使用注解

public class BookShelf {

@Book(value = "西游记",price = 998,authors = {"吴承恩","白求恩"})

                 public void showBook(){

                 }

}

(3)注意事项

①如果属性有默认值,则使用注解的时候,这个属性可以不用赋值。

②如果属性没有默认值,那么在使用注解时一定要给属性赋值。

③属性的出现顺序随意

④如果属性是数组,那么需要使用{}括起来

7.自定义注解中的特殊属性名

(1)当注解中只有一个属性且名称是value,在使用注解时给value属性赋值可以直接给属性值,无论value是单值元素还是数组类型。

(2)如果注解中除了value属性还有其他属性,且至少有一个属性没有默认值,则在使用注解给属性赋值时,value属性名不能省略。

8.注解之元注解

@Target

@Retention

(1)@Target元注解

作用:指明此注解用在哪个位置,如果不写默认是任何地方都可以使用。

TYPE: 用在类,接口上

FIELD:用在成员变量上

METHOD: 用在方法上

PARAMETER:用在参数上

CONSTRUCTOR:用在构造方法上

LOCAL_VARIABLE:用在局部变量上

注意:以上六种属性,是ElementType枚举类中的静态成员

(2)@Retention元注解

作用:定义该注解的生命周期(有效范围)。

SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了。

CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,默认值。

RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解。

注意:以上三种属性,是RetentionPolicy枚举类中的静态成员

9.注解的解析

通过Java技术获取注解数据的过程则称为注解解析。

(1)确定注解所在的对象

如果注解在类上,获取该类的字节码文件对象

如果注解在构造上,先获取字节码文件对象,再获取那个构造方法对象

如果注解在成员方法上,先获取字节码文件对象,再获取那个成员方法对象

如果注解在成员变量上,现获取字节码文件对象,再获取那个成员变量对象

(2)确定注解是否真实存在,获取该注解对象

Anontation:所有注解类型的公共接口,类似所有类的父类是Object。

AnnotatedElement:定义了与注解解析相关的方法,常用方法以下四个:

 

boolean isAnnotationPresent(Class annotationClass); 判断当前对象是否有指定的注解,有则返回true,否则返回false。

T getAnnotation(Class<T> annotationClass); 获得当前对象上指定的注解对象。

Annotation[] getAnnotations(); 获得当前对象及其从父类上继承的所有的注解对象。

Annotation[] getDeclaredAnnotations();获得当前对象上所有的注解对象,不包括父类的。

10.注解综合练习

模拟Junit高级版本,自定义注解时,有一个属性,加value

需求:执行main方法,让Calculate类中被MyTest注解修饰的方法运行,value值是几就运行几次,其他方法不运行

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
    int value();
}
public class MyMethods {
    public void method1(){
        System.out.println("method1");
    }
    @MyTest(3)
    public void method2(){
        System.out.println("method2");
    }
    @MyTest(5)
    public void method3(){
        System.out.println("method3");
    }
    public void method4(){
        System.out.println("method4");
    }

}
 //获取加了注解的MyMethods类
        MyMethods methods = new MyMethods();
        //获取该类的字节码文件
        Class<? extends MyMethods> clazz = methods.getClass();
        //通过反射得到该类对象
        MyMethods myMethods = clazz.getDeclaredConstructor().newInstance();
        //通过反射得到所有方法
        Method[] methods1 = clazz.getMethods();
        //遍历判断是否有MyTest注解存在
        for (Method method : methods1) {
            if (method.isAnnotationPresent(MyTest.class)) {
                //如果存在,获取value属性值,执行相应次数的方法
                MyTest annotation = method.getAnnotation(MyTest.class);
                int value = annotation.value();
                for (int i = 0; i < value; i++) {
                    method.invoke(myMethods);
                }
            }
        }

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值