2021-05-12

junit,反射,注解,正则表达式(基础加强)

学习目标

01_能够通过反射技术获取Class字节码对象

02_能够通过反射技术获取构造方法对象,并创建对象。

03_能够通过反射获取成员方法对象,并且调用方法。

04_能够通过反射获取属性对象,并且能够给对象的属性赋值和取值。

06_能够说出注解的作用

07_能够自定义注解和使用注解

08_能够说出常用的元注解及其作用

09_能够解析注解并获取注解中的数据

10_可以使用Junit测试框架

11_可以理解正则表达式

第01章 反射【重点】

1.1反射的概述

1.1.1什么是反射

反射是一种机制/功能,利用该机制/功能可以在程序运行过程中对类进行解剖并操作类中的构造方法,成员方法,成员属性。

1.1.2反射的应用场景

  1. 开发工具中写代码时的提示

开发工具之所能够把该对象的方法和属性展示出来就使用利用了反射机制对该对象所有类进行了解剖获取到了类中的所有方法和属性信息,这是反射在IDE中的一个使用场景。

 

  1. 各种框架的设计


以上三个图标上面的名字就是Java的三大框架,简称SSH。

这三大框架的内部实现也大量使用到了反射机制,所以要想学好这些框架,则必须要

求对反射机制熟练了。

1.1.3使用反射机制解剖类的前提

必须先要获取到该类的字节码文件对象,即Class类型对象。关于Class描述字节码

文件如下图所示:

说明:

  1. Java中使用Class类表示class文件。
  2. 任何一个class文件都是Class类的一个对象。

1.2获取Class对象的三种方式

1.2.1通过类名.class获取

User.java

/**
 * 用户
 * JavaBean
 */
public class User {

    //项目开发中,字段和属性名相同

    private int id;//编号
    private String name;//姓名
    private double sal;//薪水

    public User(){}



    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

}

 

 

Demo01.java

/**
 * 通过类名.class获取
 */
public void test1(){
    //String.class,int.class,void.class
    Class clazz = User.class;
    System.out.println(clazz);
}

 

1.2.2通过Object类的成员方法getClass()方法获取

Demo01.java

/**
 * 通过Object类的成员方法getClass()方法获取
 */
public void test2(){
   //new String().getClass()
   //User user = new User();
   //Class clazz = user.getClass();
   //System.out.println(clazz);
}

 

1.2.3通过Class.forName("全限定类名")方法获取

Demo01.java

/**
 * 通过Class.forName("全限定类名")方法获取
 */
public void test3() throws Exception {
    //User类的全路径名,且User在当前项目中
    //String str = "com.itheima.ref.User";
    //通过String创建User对象
    //Class clazz = Class.forName(str);
    //System.out.println(clazz);
    String str = "java.langx.String";
    Class clazz = Class.forName(str);
    System.out.println(clazz);
}

 

1.3获取Class对象的信息

知道怎么获取Class对象之后,接下来就介绍几个Class类中常用的方法了。

1.3.1获取简单类名

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

 

Demo02.java

/**
 * 获取简单类名
 */
public void test1() throws Exception{
    String str = "com.itheima.ref.User";
    Class clazz = Class.forName(str);
    //获取该Class对象的简单类名
    String simpleName = clazz.getSimpleName();
    System.out.println(simpleName);
}

1.3.2获取完整类名

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

 

Demo02.java

/**
 * 获取完整类名
 */
public void test2() throws Exception{
    String str = "com.itheima.ref.User";
    Class clazz = Class.forName(str);
    //获取包名+类名
    String name = clazz.getName();
    System.out.println(name);
}

1.3.3创建对象

T newInstance() ; 创建此 Class对象所表示的类的一个新实例。要求:类必须有

public的无参数构造方法

 

Demo02.java

/**
 * 创建对象
 */
public void test3() throws Exception{
    String str = "com.itheima.ref.User";
    Class clazz = Class.forName(str);
    //根据Class创建对象
    Object obj = clazz.newInstance();
    //如果obj的引用是User类型的话
    if(obj instanceof User){
        //强转
        User user = (User) obj;
        System.out.println(user);
    }
}

1.4获取Class对象的Constructor信息

一开始在阐述反射概念的时候,我们说到利用反射可以在程序运行过程中对类进行

解剖并操作里面的成员。而一般常操作的成员:构造方法,成员方法,成员属性,

那么接下来看看怎么利用反射来操作这些成员以及操作这些成员能干什么,先来看

看怎么操作构造方法。而要通过反射操作类的构造方法,我们需要先知道一个

Constructor类。

1.4.1 Constructor类概述

Constructor是构造方法类,类中的每一个构造方法都是Constructor的对象,通过

Constructor对象可以实例化对象。

1.4.2 Class类中与Constructor相关方法

1. Constructor[] getConstructors()

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

2. Constructor[] getDeclaredConstructors()

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

3. Constructor getConstructor(Class... parameterTypes)

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

4. Constructor getDeclaredConstructor(Class... parameterTypes)

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

1.4.3 Constructor类中常用方法

1. T newInstance(Object... initargs)

根据指定参数创建对象

2. void setAccessible(true)

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

1.4.4示例代码

User.java

/**
 * 用户
 * JavaBean
 */
public class User {

    //项目开发中,字段和属性名相同

    private int id;//编号
    private String name;//姓名
    private double sal;//薪水

    public User(){}



    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

}

 

 

Demo03.java

/**
 * 获取Class对象的Constructor信息
 */
public class Demo03 {

    /**
     * 演示Constructor[] getConstructors()
     */
    public void test1(){
        //获取Class对象
        Class clazz = User.class;
        Constructor[] cs = clazz.getConstructors();
        for(Constructor c : cs){
            System.out.println(c);
        }
    }

    /**
     * 演示Constructor[] getDeclaredConstructors()
     */
    public void test2(){
        Class clazz = User.class;
        Constructor[] cs = clazz.getDeclaredConstructors();
        for(Constructor c : cs){
            System.out.println(c);
        }
    }

    /**
     * 演示Constructor getConstructor(Class... parameterTypes)
     */
    public void test3() throws Exception{
        Class clazz = User.class;
        //获取User()构造器
        Constructor c = clazz.getConstructor(null);
        System.out.println(c);
    }

    /**
     * 演示Constructor getDeclaredConstructor(Class... parameterTypes)
     */
    public void test4() throws Exception{
        Class clazz = User.class;
        //获取private User(int id,String name)
        Constructor c = clazz.getDeclaredConstructor(int.class,String.class);
        System.out.println(c);
    }

    /**
     * 演示T newInstance(Object... initargs)
     */
    public void test5() throws Exception{
        //Class clazz = User.class;
        //获取无参构造器
        //参数一:参数的Class对象
        //Constructor c = clazz.getConstructor(null);
        //使用无参构造器创建对象
        //参数一:实际参数
        //Object obj = c.newInstance(null);
        //System.out.println(obj);

        Class clazz = User.class;
        //底层只能调用无参构造器
        //Object obj = clazz.newInstance();

        //获取User(int i)
        Constructor c = clazz.getConstructor(int.class);
        //创建对象
        Object obj = c.newInstance(2018);
        System.out.println(obj);
    }

    /**
     * 演示void setAccessible(true)
     */
    public void test6() throws Exception{
        Class clazz = User.class;
        //获取private User(int id,String name)
        Constructor c = clazz.getDeclaredConstructor(int.class,String.class);
        //在默认情况下,我们不得访问私有的构造器
        //暴力反射
        c.setAccessible(true);
        Object obj = c.newInstance(2018,"赵君");
        //System.out.println(obj);
    }

    public static void main(String[] args) throws Exception{
        Demo03 test = new Demo03();
        //test.test1();
        //test.test2();
        //test.test3();
        //test.test4();
        //test.test5();
        test.test6();
    }

}

 

1.5获取Class对象的Method信息

操作完构造方法之后,就来看看反射怎么操作成员方法了。同样在操作成员方法

之前我们需要学习一个类:Method类。

1.5.1 Method类概述

Method是方法类,类中的每一个方法都是Method的对象,通过Method对象可以

调用方法。

1.5.2 Class类中与Method相关方法

1. Method[] getMethods()

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

2. Method[] getDeclaredMethods()

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

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

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

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

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

1.5.3 Method类中常用方法

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

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

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

2. void setAccessible(true)

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

1.5.4示例代码

User.java

/**
 * 用户
 * JavaBean
 */
public class User {

    //项目开发中,字段和属性名相同

    private int id;//编号
    private String name;//姓名
    private double sal;//薪水

    public User(){}



    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

}

 

 

Demo04.java

/**
 * 获取Class对象的Method信息
 */
public class Demo04 {

    /**
     * 演示Method[] getMethods()
     * JUnit单元测试
     */
    @Test
    public void test1() {
        Class clazz = User.class;
        Method[] ms = clazz.getMethods();
        for(Method m:ms){
            System.out.println(m);
        }
    }

    /**
     * 演示Method[] getDeclaredMethods()
     */
    @Test
    public void test2(){
        Class clazz = User.class;
        Method[] ms = clazz.getDeclaredMethods();
        for(Method m:ms){
            System.out.println(m);
        }
    }

    /**
     * 演示Method getMethod("方法名", 方法的参数类型... 类型)
     */
    @Test
    public void test3() throws Exception{
        Class clazz = User.class;
        //参数一:方法名
        //参数二:方法名中参数的Class类型,如果无的话,书写null
        Method m = clazz.getMethod("set",null);
        System.out.println(m);
    }

    /**
     * 演示Method getDeclaredMethod("方法名", 方法的参数类型... 类型)
     */
    @Test
    public void test4() throws Exception{
        Class clazz = User.class;
        Object obj = clazz.newInstance();
        Method m = clazz.getDeclaredMethod("show",null);
        System.out.println(m);
    }

    /**
     * 演示Object invoke(Object obj, Object... args)
     */
    @Test
    public void test5() throws Exception{
        Class clazz = User.class;
        Object obj = clazz.newInstance();
        //参数一:方法名
        //参数二:方法名中参数的Class类型,如果无的话,书写null
        Method m = clazz.getMethod("set",null);
                //调用方法
        //参数一:对象
        //参数二:实际参数,如果无的话,书写null
        m.invoke(obj,null);
    }

    /**
     * 演示void setAccessible(true)
     */
    @Test
    public void test6()throws Exception{
        Class clazz = User.class;
        Object obj = clazz.newInstance();
        Method m = clazz.getDeclaredMethod("show",null);
        //暴力反射
        m.setAccessible(true);
        m.invoke(obj,null);
    }







}

 

1.6获取Class对象的Field信息

1.6.1 Field类概述

Field是属性类,类中的每一个属性都是Field的对象,通过Field对象可以

给对应的属性赋值和取值。

1.6.2 Class类中与Field相关方法

1. Field[] getFields()

获取所有的public修饰的属性对象,返回数组

2. Field[] getDeclaredFields()

获取所有的属性对象,包括private修饰的,返回数组

3. Field getField(String name)

根据属性名获得属性对象,只能获取public修饰的

4. Field getDeclaredField(String name)

根据属性名获得属性对象,包括private修饰的

1.6.3 Field类中常用方法

set通用方法都是给对象obj的属性设置使用
get通用方法是获取对象obj对应的属性值的

void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性

1.6.4 示例代码

User.java

/**
 * 用户
 * JavaBean
 */
public class User {

    //项目开发中,字段和属性名相同

    private int id;//编号
    private String name;//姓名
    private double sal;//薪水

    public User(){}



    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

}

 

 

Demo05.java

/**
 * 获取Class对象的Field信息
 */
public class Demo05 {

    /**
     * 演示Field[] getFields()
     */
    @Test
    public void test1() throws Exception{
        Class clazz = User.class;
        Field[] fs = clazz.getFields();
        for (Field f : fs) {
            System.out.println(f);
        }
    }

    /**
     * 演示Field[] getDeclaredFields()
     */
    @Test
    public void test2()throws Exception{
        Class clazz = User.class;
        Field[] fs = clazz.getDeclaredFields();
        for (Field f : fs) {
            System.out.println(f);
        }
    }

    /**
     * 演示Field getField(String name)
     */
    @Test
    public void test3()throws Exception{
        Class clazz = User.class;
        //获取某个Field对象
        //参数一:字段名
        Field f = clazz.getField("id");
        System.out.println(f);
    }

    /**
     * 演示Field getDeclaredField(String name)
     */
    @Test
    public void test4()throws Exception{
        Class clazz = User.class;
        Field f = clazz.getDeclaredField("sal");
        System.out.println(f);
    }

    /**
     * 演示set/get()
     */
    @Test
    public void test5()throws Exception{
        Class clazz = User.class;
        Object obj = clazz.newInstance();
        //获取某个Field对象
        //参数一:字段名
        Field f = clazz.getField("id");
        //id字段设置值
        //参数一:对象
        //参数二:实际值
        f.setInt(obj,2018);
        //id字段中获取值
        System.out.println(f.getInt(obj));
    }

    /**
     * 演示void setAccessible(true)
     */
    @Test
    public void test6()throws Exception{
        Class clazz = User.class;
        Object obj = clazz.newInstance();
        //f指向私有成员变量
        Field f = clazz.getDeclaredField("sal");
        //暴力反射
        f.setAccessible(true);
        f.setDouble(obj,5555.55);
        System.out.println(f.getDouble(obj));

    }



}

 

02章: Junit单元测试

Junit介绍

我们以后在开发中会经常对我们自己书写的代码进行测试,如果都在main方法里边进行测试,main方法就会显得臃肿。而且不便于以后其他人测试以及查看测试数据,用Junit 测试的话,一个方法对应一个测试方法,简单明了,也方便别人查看测试方法以及测试数据。

如果你的类里有多个方法,用main方法测试的话就很不方便,想测试全部方法的话就得把测试代码全部写到main里,或者你测一个重写一次。且更重要的是,这样会使测试代码与运行逻辑代码混在一起,不规范。在一个正规的java项目中(尤其是使用了SSH或者SSM之类的框架),几乎是不会写main方法的,写了就是无用代码。

但是使用junit就方便多了,这是单元测试,你想测哪个方法就写一个对应的测试方法,然后用junit运行。每个方法之间是独立的,非常灵活。而且测试方法一般不会直接写在原类中,而是单独的测试类,这样测试代码就完全与逻辑代码分开了。

Junit是Java语言编写单元测试框架,最直观的理解,就是取代java类中的main方法。Junit属于第三方工具,一般情况下需要导入jar包,而多数Java开发环境都集成了Junit。

使用方式

问题:在之前,我们写了一个方法,我们都需要使用通过main方法来调用。当我们需要测试的方法很多的时候,每次使用main

方法来调用时是非常麻烦的。所以我们有了接下来的单元测试,在开发中使用调用方法就显得特别的简单。

创建java项目,并创建“com.itheima.sh.junit”包

 

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

说明:如果以前想让一个方法运行必须在main方法中调用该方法。

 

  2.在测试类JunitDemo01方法上添加注解 @Test(说明:关于什么是注解,下面会详细讲解)

   

  • 3.@Test修饰的方法要求:public void 方法名() {…} ,没有参数。

说明:单元测试的方法必须是public修饰,void表示没有返回值,没有参数列表,否则就会不满足单元测试要求,报异常。

 

4.添加Idea中集成的Junit库,鼠标放在“@Test”处,使用快捷键“alt+Enter”,点击“Add Junit …”

 

 

  • 5.使用:选中方法右键,执行当前方法;选中类名右键,执行类中所有方法(方法必须标记@Test)

   uploading.4e448015.gif转存失败重新上传取消

  1. 常用注解

@Test,用于修饰需要执行的方法

@Before,测试方法前执行的方法

@After,测试方法后执行的方法

创建一个测试类,代码如下:测试结果如下。

public class JunitDemo02 {

@Test

         public void myTest(){

                 System.out.println("测试 test");

        }

 

@Before

         public void myBefore(){

                 System.out.println("方法前");

        }

 

@After

          public void myAfter(){

                     System.out.println("方法后");

       }

}

 

运行结果:

uploading.4e448015.gif转存失败重新上传取消

第03章 注解

3.1注解的概述

3.1.1什么是注解

注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标

记,以后,javac编译器、开发工具和其他程序可以通过反射来了解你的类及各种

元素上有无标记,看你的程序有什么标记,就去干相应的事,标记可以加在

包、类,属性、方法,方法的参数以及局部变量上定义。

3.1.2注解的应用场景

  1. 重写父类方法时。

public class Demo01 {
    @Override
    public String toString(){
        return "123";
    }
}

 

  1. 运行一个无main的方法时,带有@Test的成员方法可以直接运行,无需main方法。

public class Demo01 {
    @Test
    public void test1(){
        System.out.println("test1");
    }
    @Test
    public void test2(){
        System.out.println("test2");
    }
}

uploading.4e448015.gif转存失败重新上传取消

 

3.框架中的配置。

现在框架都是基于注解的配置,简单方便。

3.1.3常见注解

JDK中内置了很多注解,以下例举一些:

1. @Override 重写
        1. 被 override 注解修饰的方法必须是父类中重写方法或接口中的抽象方法
    2. @FunctionalInterface(JDK8) : 检测是否是函数式接口
        1. 被FunctionalInterface修饰的接口必须是函数式接口,才能通过编译
    3. SuppressWarnings    抑制警告
        1. 让编译器不要报出警告信息

 

3.2自定义注解

就算JDK中内置了很多注解,但也不一定能满足所有企业的需求,所以不排除我们需要

根据需求自定义注解。

3.2.1定义格式

public @interface 注解名{

}

 

如:定义一个名为Student的注解

 

public @interface Student {

}

 

以上定义出来的注解就是一个最简单的注解了,但这样的注解意义不大,因为注解中

没有任何内容,就好像我们定义一个类而这个类中没有任何成员变量和方法一样,这

样的类意义也是不大的,所以在定义注解时会在里面添加一些成员来让注解功能更加

强大,这些成员就是属性。接下来就看看怎么给注解添加属性。

3.2.2注解的属性

1. 属性的作用

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

 

2. 属性的格式

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

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

 

3. 属性定义示例

Book.java

/**
 * 自定义注解
 */
public @interface Book {
}

 

4. 属性适用的数据类型

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

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

以上所有类型的一维数组

3.3使用自定义注解

3.3.1在成员方法上使用自定义注解

Demo02.java

@Book
public void test1(){
}

 

  1. 使用注意事项

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

如果属性有默认值,则使用注解的时候,这个属性如果赋值了,以赋值为准。

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

 

3.3.2 一个特殊的注解属性value

1. 当注解中只有一个属性且名称是value,在使用注解时给value属性赋值可以直接给

属性值,无论value是单值元素还是数组类型。

Book.java

/**
 * 自定义一个注解
 */
public @interface Student {
    String value();
}

 

2.如果注解中除了value属性还有其他属性,且至少有一个属性没有默认值,则在使

用注解给属性赋值时,value属性名不能省略

Book.java

/**
 * 自定义一个注解
 */
public @interface Student {
    String value();
    int age() default 44;
}

3.4元注解

3.4.1什么是元注解

用来定义注解的注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

3.4.2元注解的作用

用来说明自定义注解的在类中出现的位置和生命周期

3.4.3常用元注解

3.4.3.1 @Target

作用:定义该注解用在哪个位置,如果不写,默认是类中任何地方都可以使用。

可选的参数值在枚举类ElemenetType中包括:

TYPE: 用在类,接口上

FIELD:用在成员变量上

METHOD: 用在方法上

PARAMETER:用在参数上

CONSTRUCTOR:用在构造方法上

LOCAL_VARIABLE:用在局部变量上

3.4.3.2 @Retention

作用:定义该注解的生命周期

可选的参数值在枚举类型RetentionPolicy中包括:

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

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

有,这个是默认值。

RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,

程序可以通过反射获取该注解

3.4.4使用元注解

Book.java

/**
 * 自定义注解
 */
@Retention(value=RetentionPolicy.RUNTIME)
@Target(value={ElementType.FIELD,ElementType.METHOD})
public @interface Book {
    int id() default 10;//图书编号
    String author() default "赵君";//作者
    double price() default 11.11;//单价
}

 

uploading.4e448015.gif转存失败重新上传取消

3.5解析注解

3.5.1什么是解析注解

通过Java技术,在程序运行时,获取注解中所有属性的过程则称为解析注解。

3.5.2与注解解析相关的接口

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

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

  1. boolean isAnnotationPresent(Class annotationClass); 判断当前对象是否有

指定的注解,有则返回true,否则返回false。

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

象。

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

象。

  1. Annotation[] getDeclaredAnnotations();获得当前对象上所有的注解对象,不包

括父类的。

3.5.3获取注解数据的原理

注解作用在那个成员上,就通过反射获得该成员的对象来得到它的注解。

如:

如注解作用在方法上,就通过方法(Method)对象得到它的注解

// 得到方法对象

Method method = clazz.getDeclaredMethod("方法名");

// 根据注解名得到方法上的注解对象

Book book = method.getAnnotation(Book.class);

 

如注解作用在类上,就通过Class对象得到它的注解

// 获得Class对象

Class c = 类名.class;

// 根据注解的Class获得使用在类上的注解对象

Book book = c.getAnnotation(Book.class);

3.5.4使用反射获取注解的数据

Demo03.java

/**
 * 解析注解Book
 */
public class Demo03 {

    /**
     * 在程序运行时,获取注解Book的所有属性值
     */
    @Book
    public void test1() throws Exception{
        //@Book->test1()->Class

        //获取Demo03类的Class对象
        Class clazz = Demo03.class;
        //获取Class对象的Method对象
        Method m = clazz.getMethod("test1",null);
        //获取Method对象中的@Book注解
        //参数一:注解类型的Class
        //返回值:注解
        Book book = m.getAnnotation(Book.class);
        //获取Book注解里面的所有属性值
        System.out.println(book.id());
        System.out.println(book.author());
        System.out.println(book.price());
    }


    public static void main(String[] args) throws Exception{
        Demo03 test = new Demo03();
        test.test1();;
    }

}

3.6注解案例

3.6.1需求

模拟JUnit测试的@Test注释

3.6.2分析

1. 模拟JUnit测试的@Test注释,首先需要编写自定义注解@MyTest,并添加元注解,

保证自定义注解只能修饰方法,且在运行时可以获得。

2. 编写测试类,给目标方法使用 @MyTest注解,编写三个方法,其中两个加上@MyTest注解。

3. 编写调用类,使用main方法调用测试类,模拟JUnit的运行,只要有@MyTest注

释的方法都会运行。

3.6.3实现

/**
 * @MyTest注解
 */
@Retention(value= RetentionPolicy.RUNTIME)
@Target(value= ElementType.METHOD)
public @interface MyTest {
}

 

/**
 * 使用MyTest注解
 */
public class MyTestDemo {
    @MyTest
    public void test1(){
        System.out.println("public void test1()");
    }
    public void test2(){
        System.out.println("public void test2()");
    }
    @MyTest
    public void test3(){
        System.out.println("public void test3()");
    }
}

 

Demo04.java

 

第04章 正则表达式

正则表达式

在开发中,通常很多数据都会使用String类存储。原因:操作字符串的功能比较多,比较方便。

在操作String类对象时,会经常遇到对字符串进行验证的功能,而按照我们之前学习的String类,我们使用String类中的诸多函数是可以完成对字符串校验功能的,但是代码相对来说比较麻烦,所以在Java中引入正则表达式的概念来解决上述问题,即简化代码。

正则表达式:专门用于操作字符串的技术,并且可以简化代码,用于对字符串的复杂操作。

正则表达式弊端:代码可读性比较差。

验证

案例1:

需求:验证QQ号码是否合法。

  分析:

  1、第一位不能是零;

  2、QQ号码在5到12之间(包含);

  3、Q号码都是由数字组成;

说明:

  1. String类中提供一个matches()函数,可以判断字符串对象是否匹配正则表达式。

uploading.4e448015.gif转存失败重新上传取消

1)如果匹配,则返回true;

2)如果不匹配,则返回false;

2、 [1-9]:表示字符串中第一位能够出现1~9任何一个数字;

3、 [0-9]{4,11}:表示字符串中从第2位开始后面的数字只能出现0~9之间的数字,并且最少出现4次,最多出现11次;

4、 如果满足上述条件则返回true,否则返回false

 

上述案例代码如下:

 

package cn.itcast.sh.a_regex_demo;

/*

 * 需求:验证QQ号码是否合法。

 分析:

 1、第一位不能是零;

 2QQ号码在512之间(包含);

 3QQ号码都是有数字组成;

 */

public class RegexDemo {

         public static void main(String[] args) {

                 method_1();

          }

       // 使用正则表达式完成QQ号码的验证

         private static void method_1() {

        // 定义一个字符串变量

         String QQ = "12345";

/*

 * String类中提供一个matches()函数,可以判断字符串对象是否匹配正则表达式

 * 如果匹配,则返回true

 * 如果不匹配,则返回false

 * [1-9]:表示字符串中第一位能够出现1~9任何一个数字

 * [0-9]{4,11}:表示字符串中从第2位开始后面的数字只能出现0~9之间的数字,并且最少出现4次,最多出现11

 * 如果满足上述条件则返回true,否则返回false

 */

            boolean flag = QQ.matches("[1-9][0-9]{4,11}");

            System.out.println(flag);

       }

}

说明:

  1. 在正则中[]表示在某一位字符串中出现的范围;
  2. 在正则中{}表示前面离他最近的前面的正则出现的次数;

 

 

注意:正则表达式只能使用在字符串上

案例2:需求:验证手机号码

分析:手机号码的规则:

  1. 长度必须是11位;
  2. 第一位只能是数字1;
  3. 第二位可以是3 4 5 7 8;
  4. 从第三位开始可以是0-9

步骤:

  1. 定义一个RegexDemo1类,在这个类中定义一个主函数main;
  2. 在main函数中定义一个String类型的变量tel,并赋值为15066668888;
  3. 定义一个手机号码的正则规则regex=”1[34578][0-9]{9}”;
  4. 使用字符串变量tel调用String类中的matches()函数,regex正则规则作为参数进行传递,打印结果;

package cn.itcast.sh.a_regex_demo;

/*

 * 需求:验证手机号码

 分析:手机号码的规则:

 1)长度必须是11位;

 2)第一位只能是数字1

 3)第二位可以是3 4 5 7 8

 4)从第三位开始可以是0-9

 */

public class RegexDemo1 {

         public static void main(String[] args) {

         // 定义一个字符串

               String tel = "15066668888";

         // 定义一个手机号的正则

               String regex = "1[34578][0-9]{9}";

        // 使用字符串对象tel调用String类中的matches函数,判断字符串是否匹配正则表达式

               System.out.println(tel.matches(regex));

         }

}

 

切割

 

需求:使用String类中的split函数根据正则表达式规则,以数字对已知的字符串进行切割。

  1. 定义RegexDemo2 类;
  2. 在这个类中定义一个字符串str,并赋值为sfajs12321dbfj234d23sjfk454sdjf565sdhd757hf;
  3. 定义一个正则表达式规则:regex=[0-9]+;
  4. 使用定义好的字符串str调用split()函数按照正则表达式进行切割;
  5. 遍历切割后的数组;

 

package cn.itcast.sh.a_regex_demo;

/*

 * 需求:使用String类中的split函数根据正则表达式规则,以数字对已知的字符串进行切割。

 1)定义RegexDemo2 类;

 2)在这个类中定义一个字符串str,并赋值为sfljs12321dlfj234d23sjfk454sdjf565sdhd757hf”;

 3)定义一个正则表达式规则:regex=”\\d+”;

 4)使用定义好的字符串str调用split()函数对正则表达式进行切割;

 5)遍历切割后的数组;

 */

public class RegexDemo2 {

public static void main(String[] args) {

         // 定义一个字符串

              String str = "sfajs12321dbfj234d23sjfk454sdjf565sdhd757hf";

             // 定义一个正则表达式,以数字对上述字符串进行切割{"sfajs","dbfj","d","sjfk"}

             String regex = "\\d+";

             String[] strs = str.split(regex);

             // 遍历数组

            for (int i = 0; i < strs.length; i++) {

            // 打印数组中的数据

                      System.out.println(strs[i]);

             }

       }

}

 

说明:

  1. 在正则中\\d就是数字[0-9];
  2. 在正则中+ 表示1 n次,* 表示0 1 n次,? 表示0 1次;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值