一、单元测试

1、定义

        针对最小的功能单元:方法,编写测试代码对其进行正确性测试。

2、Junit单元测试框架

        可以用来对方法进行测试,它是第三方公司开源出来的(很多开发工具已经集成了Junit框架,比如IDEA)

        优点:可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。不需要程序员去分析测试的结果,会自动生成测试报告出来。

使用步骤:

        

代码如下:

public class StringUnit {
    //字符串工具类
    public static void PrintNumber(String name) {
        System.out.println("名字长度是:" + name.length());
    }
    //求字符串的最大索引
    public static int PrintIndex(String data) {
        if(data==null||"".equals(data)){
            return -1;
        }
        return data.length()-1;
    }
}
public class StringUnitTest {
    //测试方法:必须是公开public,无参,无返回值
    //必须加上@Test注解
    @Test
    public void testPrintNumber() {
        StringUnit.PrintNumber("张三abc");
        StringUnit.PrintNumber("");
        //StringUnit.PrintNumber(null);
    }

    @Test
    public void testPrintIndex() {
        int index = StringUnit.PrintIndex("abcdefg");
        int index2 = StringUnit.PrintIndex("");
        int index3 = StringUnit.PrintIndex(null);

        System.out.println(index);
        System.out.println(index2);
        System.out.println(index3);

        //做断言,断言结果是否与预期结果正确
        Assert.assertEquals("本轮测试失败,业务获取的1最大索引有问题,请检查",6, index);
        Assert.assertEquals("本轮测试失败,业务获取的2最大索引有问题,请检查",-1, index2);
        Assert.assertEquals("本轮测试失败,业务获取的3最大索引有问题,请检查",-1, index3);
    }
}

二、反射

1、定义

        反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。

反射的第一步:加载类

获取类的字节码:Class对象
获取类的构造器:Constructor对象
获取类的成员变量:Field对象
获取类的成员方法:Method对象
获取Class对象的三种方式
①Class c1 =类名.class
②调用Class提供方法:public static Class forName(String package);
③Object提供的方法:public Class getClass():Class c3 =对象.getClass();

代码如下:

    public static void main(String[] args) throws Exception {

        //1、获取类本身:类名.class
        Class c1=Student.class;
        System.out.println(c1);

        //2、获取类本身:对象.getClass()
        Student s1=new Student();
        Class c2=s1.getClass();
        System.out.println(c2);

        //3、获取类本身:对象.forName()605575422@qq.com
        Class c3=Class.forName("com.genshin.demo2Reflect.Student");
        System.out.println(c3);


        System.out.println(c1==c2);
        System.out.println(c1==c3);


    }

运行结果如下:

2、发射获取类中的成分并操作

先创建一个类:

public class Mygo {
    private String name;
    private int age;
    private String hobby;

    private Mygo() {
        System.out.println("无参构造器");
    }

    private Mygo(String name) {
        System.out.println("一个有参构造器");
        this.name = name;
    }
    public Mygo(String name, int age) {
        System.out.println("两个有参构造器");
        this.name = name;
        this.age = age;
    }

    public void playmusic(){
        System.out.println("正在演奏春日影");
    }

    public String playmusic(String name){
        System.out.println(name + "正在演奏春日影");
        return "长崎素世:为什么要演奏春日影!!!";
    }


        /*getter 与 setter 方法 */

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

①Class提供了从类中获取构造器的方法

获取类构造器的作用:依然是初始化对象返回

代码如下:

    @Test
    public void getclassInfo(){
        //一、获取类的信息
        //1、反射第一步:获取Class对象,代表拿到类
        Class c1=Mygo.class;
        System.out.println(c1.getName());//类名的全类名 com.genshin.demo2Reflect.Mygo
        System.out.println(c1.getSimpleName());//类名 Mygo
    }

运行结果如下:

@Test
    public void getConstructorInfo() throws Exception{
        //二、获取构造器对象并对其进行操作
        //1、反射第一步:获取Class对象
        Class c1=Mygo.class;
        //2、获取构造器对象
        Constructor[] cons= c1.getDeclaredConstructors();
        for (Constructor c:cons) {
            System.out.println(c.getName()+"("+c.getParameterCount()+")");
        }
        //3、获取单个构造器
        Constructor con= c1.getDeclaredConstructor();//获取无参构造器
        System.out.println(con.getName()+"("+con.getParameterCount()+")");

        Constructor con2= c1.getDeclaredConstructor(String.class,int.class);//获取有参构造器
        System.out.println(con2.getName()+"("+con2.getParameterCount()+")");

        //4、获取构造器的作用依然是创建对象
        //暴力反射:暴力反射可以访问私有的构造器、方法、属性
        con.setAccessible(true);
        Mygo m1= (Mygo) con.newInstance();
        System.out.println(m1);

        Mygo m2= (Mygo) con2.newInstance("丰川祥子",16);
        System.out.println(m2);
    }

运行结果如下:

②Class提供从类中获取成员变量的方法

获取到成员变量的作用:

方法代码如下:

    @Test
    //三、获取类的成员变量对象并对其进行操作
    public void getFieldInfo() throws Exception{
        //1、获取Class对象
        Class c1=Mygo.class;
        //2、获取成员变量对象
        Field[] fields=c1.getDeclaredFields();
        for (Field f:fields) {
            System.out.println(f.getName()+"("+f.getType().getName()+")");
        }
        //3、获取单个成员变量对象
        Field f=c1.getDeclaredField("hobby");
        System.out.println(f.getName()+"("+f.getType().getName()+")");

        //4、获取成员变量的目的依然是取值和赋值
        Mygo m1=new Mygo("丰川祥子",16);
        f.setAccessible(true);
        f.set(m1,"弹钢琴");
        System.out.println(m1);

        String hobby= (String) f.get(m1);
        System.out.println(hobby);
    }

运行结果:

③Class提供了从类中获取成员方法的API

成员方法的作用:依然是执行

代码如下:

@Test
    //四、获取类的成员方法对象并对其进行操作
    public void getMethodInfo() throws Exception{
        //1、获取Class对象
        Class c1=Mygo.class;
        //2、获取成员方法对象
        Method[] methods=c1.getDeclaredMethods();
        for (Method m:methods) {
            System.out.println(m.getName()+"("+m.getParameterCount()+")");
        }
        //3、获取单个成员方法对象
        Method playmusic1 = c1.getDeclaredMethod("playmusic");
        Method playmusic2 = c1.getDeclaredMethod("playmusic", String.class);
        System.out.println(playmusic1.getName()+"("+playmusic1.getParameterCount()+")");
        System.out.println(playmusic2.getName()+"("+playmusic2.getParameterCount()+")");

        //4、获取成员方法的目的依然是调用方法
        Mygo m1=new Mygo("丰川祥子",16);
        playmusic1.setAccessible(true);
        Object rs1=playmusic1.invoke(m1);//唤醒对象m1的playmusic方法,相当于m1.playmusic()
        System.out.println(rs1);//null

        Object rs2=playmusic2.invoke(m1,"要乐奈");
        System.out.println(rs2);

运行结果:

3、反射的基本作用

①可以得到类的全部成分并操作
②可以破坏封装性
③可以绕过泛型的约束

代码如下:

    public static void main(String[] args) throws Exception {
        List<String> list = new ArrayList<>();
        list.add("Sakiko");
        list.add("Anno");
        list.add("Soyorin");

        Class c = list.getClass();//c==ArrayList.class
        //获取ArrayList的add方法
        Method add=c.getDeclaredMethod("add", Object.class);
        add.invoke(list, 9.9);//翻墙
        add.invoke(list, true);//翻墙
        System.out.println(list);

运行结果:

反射的用途:适合拿来做java的高级框架

三、注解

1、注解的定义

        Java代码里的特殊标记,比如:@Override、@Test等,作用是:让其他程序根据注解信息来决定怎么执行该程序。可以用在类上、构造器上、方法上、成员变量上、参数上、等位置处。

2、自定义注解

pubilc @interface 注解名称{
    pubilc 属性类型 属性名() default 默认值;
}

注意:对于特殊属性名-value,如果注解中只有一个value属性,使用注解时,value名称可以不写

3、注解的原理

        注解本质是一个接口,Java中所有注解都是继承了Annotation接口的。@注解(...):其实就是一个实现类对象,实现了该注解以及Annotation接口。

代码如下:

public @interface A {
    String value();
    String hobby() default "弹吉他";
}
public @interface Mybook {
    String name();
    int age() default 18;
    String[] address();
}
@Mybook(name="二见原莉莉子",age=18,address = {"霓虹","日本"})
@A("delete")

public class AnnotationDemo1 {
    @Mybook(name="千早爱音",age=18,address = {"霓虹","日本"})
    public static void main(@A("delete") String[] args) {

        //自定义注解
        @A("delete")
        int a;
    }
}

4、元注解

        意思:注解 注解 的注解

元注解

@Target @Retention
作用:声明注解只能在哪个位置使用 作用:声明注解的保留周期
1.TYPE,类,接口

1. SOURCE
只作用在源码阶段,字节码文件中不存在。

2. FIELD,成员变量
3.METHOD,成员方法

2. CLASS(默认值)

保留到字节码文件阶段,运行阶段不存在。

4.PARAMETER,方法参数
5. CONSTRUCTOR,构造器

3.RUNTIME(开发常用)

一直保留到运行阶段。

6.LOCAL_VARIABLE,局部变量

代码如下:

@Target(ElementType.METHOD) //表示注解的作用目标为方法
@Retention(RetentionPolicy.RUNTIME)

public @interface MyTest1 {
}
//@MyTest1//报错
public class AnotationDemo2 {
    @MyTest1 //成员变量-报错
    private int age;

    @MyTest1 //构造器-报错
    public AnotationDemo2() {}

    @MyTest1
    public static void main(String[] args) {}

    @MyTest1
    public void getagetest() {}
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
//注解的目标是方法
public @interface MyTest2 {

}

5、注解的解析

        就是判断类上、方法上、成员变量上是否存在注解,并把注解里的内容给解析出来。

如何解析注解?

        指导思想:要解析谁上面的注解,就应该先拿到谁:比如要解析类上面的注解,则应该先获取该类的Class对象,再通过Class对象解析其上面的注解。要解析成员方法上的注解,则应该获取到该成员方法的Method对象,再通过Method对象解析其上面的注解。
        Class、Method、Field,Constructor、都实现了AnnotatedElement接口,它们都拥有解析注解的能力。

代码如下:

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest2 {
    String value();
    double height() default 160.5;
    String[] address();
}
@MyTest2(value = "丰川祥子",address = {"日本","霓虹"})
public class Demo {
    @MyTest2(value = "长崎素世",address = {"日本","霓虹"})
    public void go(){
    }
}
    @Test
    public void parseClass() throws Exception {
        //获取Class对象
        Class c1=Demo.class;
        //获取方法对象
        Method m=c1.getMethod("go");
        //判断类上是否有@MyTest2注解(使用isAnnotationPresent)
        if(c1.isAnnotationPresent(MyTest2.class)){
            //获取注解对象
            MyTest2 mt= (MyTest2) c1.getDeclaredAnnotation(MyTest2.class);

            //获取注解属性值
            String[] address=mt.address();
            double height=mt.height();
            String value=mt.value();
            //打印注解属性值
            System.out.println(Arrays.toString(address));
            System.out.println(height);
            System.out.println(value);
        }
    }
}

运行结果:

四、代理

        对象如果嫌身上干的事太多,可以通过代理来转移部分职责,对象有什么方法想被代理,代理就要有对应的方法。

public interface StarService {
    void sing(String name);
    String dance();
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Star implements StarService {
    private String name;

    @Override
    public void sing(String name) {
        System.out.println(this.name + "表演唱歌" + name);
    }

    @Override
    public String dance() {
        System.out.println(this.name + "表演跳舞");
        return "";
    }

}

创建代理对象:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyUtil {
    public static StarService createProxy(Star s){
        //参数一:用于执行哪个类加载器去加载生成的代理类
        //参数二:代理类要实现的接口:明星类实现了哪些接口,代理类就实现哪些接口
        //参数三:用于指定代理类需要如何去代理(代理要做的事情)
        StarService proxy=(StarService) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                s.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //代理要做的事情
                        String MethodName=method.getName();
                        if("sing".equals(MethodName))
                            System.out.println("准备话筒,收钱20w");
                        else if("dance".equals(MethodName))
                            System.out.println("准备场地,收钱100w");
                        Object result=method.invoke(s,args);
                        return result;
                    }
                });
        return proxy;
}
}
public class Test {
    public static void main(String[] args) {
    //准备一个明星对象,创建明星类
        Star star=new Star("羊宫妃娜");
        //为其创建一个代理类
        StarService proxy=ProxyUtil.createProxy(star);
        proxy.sing("《春日影》");
        System.out.println(proxy.dance());
    }
}

运行结果如下:

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐