• Java学习之路 —— Java高级


    前言

    终于走到新手村的末端了,这一部分主要包括了单元测试、发射、注解、动态代理。学完这些就算是走出新手村了,准备去学框架了。

    1. 单元测试

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

    在这之前,都是在Main方法里面编写测试代码,去调用方法进行测试。但这样无法实现自动化测试,一个方法测试失败,可能影响其他方法的测试。同时无法得到测试的报告,需要程序员自己去观察测试是否成功。

    于是就有了Junit单元测试框架。

    优点

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

    具体步骤

    1. 将Junit框架的jar包导入到项目中(IDEA集成了junit框架,不需要手工导入)
    2. 为需要测试的业务类,定义对应的测试类,并为每个业务方法,编写对应的测试方法(必须:公共、无参、无返回值)
    3. 测试方法上必须声明@Test注解,然后在测试方法中,编写代码调用被测试的业务方法进行测试
    4. 开始测试:选中测试方法,右键选择JUnit运行,如果测试通过是绿色,反之是红色

    自己写的一个类

    package junit;
    
    public class StringUtil {
        public static void printNumber(String name) {
            System.out.println("长度是:" + name.length());
        }
        public static int getMaxIndex(String data) {
            if(data == null)
                return -1;
            return data.length();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    测试类

    package junit;
    
    import org.junit.Assert;
    import org.junit.Test;
    
    /*
    测试类
     */
    public class StringUtilTest {
        // 公开 无返回值 无参数
        @Test // 测试方法
        public void testPrintNumber() {
            StringUtil.printNumber("admin");
    //        StringUtil.printNumber(null);
        }
        @Test
        public void testGetMaxIndex() {
            int index1 = StringUtil.getMaxIndex(null);
            int index2 = StringUtil.getMaxIndex("admin");
            System.out.println(index1 + " " + index2);
    
            // 断言机制:程序员可以通过预测业务方法的结果
            Assert.assertEquals("方法内部有bug", 4, index2);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    Emm,,感觉现在我可能用不到,就当了解一下吧。

    2. 反射

    后面的这些东西都是后面理解框架、学习框架的时候,看底层源码用得到的,所以目前也就当是一个了解吧。

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

    1. 反射第一步:加载类,获取类的字节码:Class对象
    2. 获取类的构造器:Constructor对象
    3. 获取类的成员变量:Field对象
    4. 获取类的成员方法:Method对象

    2.1 获取Class对象的三种方式

    • Class c1 = 类名.class
    • 调用Class提供方法:public static Class forName(String package);
    • Object提供的方法:public Class getClass(); Class c3 = 对象.getClass();

    2.2 获取类的构造器的方法

    在这里插入图片描述
    或许以我现在的知识来看,真是有点脱裤子放屁,还不了解这些的作用。

    2.3 获取类的成员变量

    在这里插入图片描述
    获取到成员变量的作用:赋值、取值。
    在这里插入图片描述

    2.4 获取类的成员方法

    在这里插入图片描述

    2.5 反射的作用

    • 基本作用:可以得到一个类的全部成分然后操作
    • 可以破坏封装性
    • 最重要的用途:适合做Java的框架

    写一个Demo框架

    Student

    package reflect;
    
    public class Student {
        private String name;
        private int age;
        private char sex;
        private double height;
    
        public Student(String name, int age, char sex, double height) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.height = height;
        }
    
        public  String getName() {
            return name;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    框架

    package reflect;
    
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    import java.lang.reflect.Field;
    
    public class ObjectFrame {
        public static void saveObject(Object obj) throws Exception {
            PrintStream ps = new PrintStream(new FileOutputStream("text.txt"));
            Class c = obj.getClass();
            String cName = c.getSimpleName();   // 获取类的简单名称
            ps.println("__________" + cName + "__________");
            Field[] fields = c.getDeclaredFields();
            // 遍历每个成员变量
            for (Field field : fields) {
                field.setAccessible(true);  // 禁止检查访问控制
                // 拿到成员变量的名字
                String name = field.getName();
                // 拿到这个成员变量在对象中的数据
                String val = field.get(obj) + "";
                ps.println(name + " = " + val);
            }
            ps.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    测试类

    package reflect;
    
    import org.junit.Test;
    
    public class TestFrame {
        @Test
        public void save() throws Exception{
            Student s = new Student("jehan", 21, 'm', 180.5);
            ObjectFrame.saveObject(s);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果

    在这里插入图片描述

    3. 注解

    注解就是Java代码里面的一些特殊标记,比如@Override、@Test等,作用是:让其他程序根据注解信息来决定怎么执行该程序,比如加了注解就执行,没有加注解就不执行,这也是Junit框架的原理。

    3.1 自定义注解

    public @interface 注解名称 {
    	public 属性类型 属性名() default 默认值;
    }
    
    • 1
    • 2
    • 3

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

    3.2 注解的原理

    在这里插入图片描述

    注解本质是一个接口,继承自Annotation类,里面都是一些抽象方法。

    当使用@使用注解的时候,里面的信息都是在创建一个对象,实现了该注解以及Annotation接口。

    3.3 元注解

    指的是修饰注解的注解。

    常用的元注解就2个:

    • @Target:声明被修饰的注解只能在哪些位置使用
    • @Retention:声明注解的保留周期
      在这里插入图片描述

    3.4 注解的解析

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

    如何解析注解?

    • 要解析类上的注解,就应该先获取该类的Class对象,再通过Class对象解析其上面的注解
    • 要解析成员方法上的注解,则应该获取到该成员方法的Method对象,再通过Method对象解析其上面的注解
    • Class、Method、Field、Constructor都实现了AnnotatedElement接口,它们都拥有解析注解的能力。
      在这里插入图片描述

    4. 动态代理

    动态代理是一种在程序运行时创建目标对象的代理对象,并对目标对象的方法进行功能性增强的技术。这是一种结构设计模式,也称为委托模式。其核心思想在于,当需要对已有的代码(方法)前后添加新功能,而不想修改或不方便修改原代码时,可以利用动态代理来实现。

    例如,假设我们有一个Human接口,我和黄牛都实现了这个接口。现在我和黄牛都已经准备好了,怎么把这二者关联起来呢?我们要明确的是黄牛是要帮我买票的,买票必然就需要帮我实现Human接口中的方法。在这种情况下,我们可以创建一个动态代理对象来“委托”黄牛来执行某些功能。
    在这里插入图片描述
    这一块先留个坑吧,后面用到了再好好学一下,就跟着视频敲了一遍demo。

    自己写的类

    package proxy;
    
    public class SuperStar implements Star{
        private String name;
    
        public SuperStar(String name) {
            this.name = name;
        }
        public String sing(String name) {
            System.out.println(this.name + "正在唱:" + name);
            return "Thanks";
        }
        public void dance() {
            System.out.println("dancing~");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    代理

    package proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ProxyUtil {
        public static Star createProxy(SuperStar ss) {
            // 参数1:默认
            // 参数2:指定生成的代理长什么样子,也就是有哪些方法
            // 参数3:指定生成的代理要干什么事情
            Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                    new Class[]{Star.class}, new InvocationHandler() {
                        @Override   // 回调方法
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            // 代理对象要做的事情,会在这里写代码
                            if(method.equals("sing")) {
                                System.out.println("准备话筒和场地");
                            } else if(method.equals("dance")) {
                                System.out.println("准备场地, 伴舞");
                            }
                            return method.invoke(ss, args);
                        }
                    });
            return starProxy;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    主函数

    package proxy;
    
    public class Test {
        public static void main(String[] args) {
            SuperStar s = new SuperStar("IU");
            Star starproxy = ProxyUtil.createProxy(s);
            String res = starproxy.sing("blueming");
            System.out.println(res);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    5. 总结

    花了差不多一周,把Java全部过完了一遍,目前后面的计划安排是每天刷几道力扣,进一步熟悉熟悉Java,然后去学JavaWeb吧,大概就是这样,也希望能在12月之前开到奖,这样我想是今年生日送给我的最好的一份礼物了。后面我会把一些写好了的面经帖和我这一年的一个经历与心路历程发出来,本来想着就不发了,但是还是有一些朋友私信我希望我能够分享一下,那后面就整理一下发吧。我也不知道后面还有多少机会去产出博客,也是希望给后来者一条清晰的路吧,大学生最大的敌人是信息差

    So,有缘再见吧,Bye~

  • 相关阅读:
    嵌入式面试常见问题(三)
    【深度学习实验】注意力机制(四):点积注意力与缩放点积注意力之比较
    RISC-V架构——物理内存属性和物理内存保护
    LeetCode 1726. 同积元组:哈希表(组合数学)
    MyBatis-----4、MyBatis各种查询功能
    SAP 让ALV表格修改后保存到数据库(1.设置图标事件;2.LVC_S_GLAY-EDT_CLL_CB字段直接实现)
    加解密和加签验签
    第四章 - vi和vim编辑器
    mybatis-plus 操作json字段
    项目部署;流程
  • 原文地址:https://blog.csdn.net/weixin_51322383/article/details/134474662