Java:高级技术讲解

单元测试:

没有单元测试时是怎么测试代码的?

Junit单元测试框架

优点:

单元测试的具体步骤:

常用注解:

这里我们采用Junit4的版本的注解,这个版本比较经典。

示例代码:

比如我们有一个StringUtil类,是我们写好的一个类:------也就是等待测试的类

java 复制代码
package com.itheima.d1_junit;

public class StringUtil {
    public static void printNumber(String name){
        if(name == null){
            System.out.println(0);
            return; // 停掉方法
        }
        System.out.println("名字长度是:" + name.length());
    }

    /**
     * 求字符串的最大索引
     */
    public static int getMaxIndex(String data){
        if(data == null) {
            return -1;
        }
        return data.length() - 1;
    }
}

我们要测试其中的方法,看看有没有问题

创建一个StringUtilTest类来开始进行单元测试:---步骤上面说过了,一共有四步

java 复制代码
package com.itheima.d1_junit;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * 测试类
 */
public class StringUtilTest {
    @Before
    public void test1(){
        System.out.println("---> test1 Before 执行了---------");
    }
    @Test
    public void testPrintNumber(){
        StringUtil.printNumber("admin");
        StringUtil.printNumber(null);//测试的时候要全面一点
    }

    @Test
    public void testGetMaxIndex(){
        int index1 = StringUtil.getMaxIndex(null);
        System.out.println(index1);

        int index2 = StringUtil.getMaxIndex("admin");
        System.out.println(index2);


        //断言机制:程序员可以通过预测业务方法的结果。
        //4!=index2  --输出bug
        Assert.assertEquals("方法内部有bug!", 4, index2);


    }

}

测试的时候,把鼠标光标点到某测试方法中,想要一键测试某个类中的所有方法,那就把光标点到StringUtilTest上,如何想把整个模块的测试类都一键测试,怎么实现?

点击Run All Tests即可,非常方便。

反射:

反射学什么?

学习获取类的信心,操作它们:

反射第一步:

获取class对象的三种方法:

代码演示:

准备一个学生类:

java 复制代码
package com.itheima.d2_reflect;

public class Student {
    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;

    public Student() {
    }

    public Student(String name, int age, char sex, double height, String hobby) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
        this.hobby = hobby;
    }

    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;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
}

获取该学生类的class对象:

java 复制代码
package com.itheima.d2_reflect;

public class Test1Class {
    public static void main(String[] args) throws Exception {
        Class c1 = Student.class;
        System.out.println(c1.getName()); // 全类名
        System.out.println(c1.getSimpleName()); // 简名:Student

        Class c2 = Class.forName("com.itheima.d2_reflect.Student");
        System.out.println(c1 == c2);

        Student s = new Student();
        Class c3 = s.getClass();
        System.out.println(c3 == c2);
        //com.itheima.d2_reflect.Student
        //Student
        //true
        //true
    }
}

获取类的构造器,并对其进行操作:

获取类的构造器作用:

初始化对象返回。

代码演示:

这里准备一个Cat类:

java 复制代码
package com.itheima.d2_reflect;

public class Cat {
    public static int a;
    public static final String COUNTRY = "中国";
    private String name;
    private int age;

    private Cat(){
        System.out.println("无参数构造器执行了~~");
    }

    private Cat(String name, int age) {
        System.out.println("有参数构造器执行了~~");
        this.name = name;
        this.age = age;
    }

    private void run(){
        System.out.println("🐱跑的贼快~~");
    }

    public void eat(){
        System.out.println("🐱爱吃猫粮~");
    }

    private String eat(String name){
        return "🐱最爱吃:" + name;
    }

    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;
    }

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

写测试代码:----讲解在注释中

java 复制代码
package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.util.concurrent.atomic.AtomicInteger;

public class Test2Constructor {
    @Test
    public void testGetConstructors(){
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        // 2、获取类的全部构造器
        // Constructor[] constructors = c.getConstructors();
        Constructor[] constructors = c.getDeclaredConstructors();
        // 3、遍历数组中的每个构造器对象
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "--->"
                    + constructor.getParameterCount());//名和参数
        }
    }

    @Test
    public void testGetConstructor() throws Exception {
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        // 2、获取类的某个构造器:无参数构造器
        Constructor constructor1 = c.getDeclaredConstructor();
        System.out.println(constructor1.getName() + "--->"
                + constructor1.getParameterCount());
        constructor1.setAccessible(true); // 禁止检查访问权限  因为是private权限,不加这一行下面2行会出现异常
        Cat cat = (Cat) constructor1.newInstance();//返回Object类型,强转
        System.out.println(cat);



        // 3、获取有参数构造器
        Constructor constructor2 =
                c.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor2.getName() + "--->"
                + constructor2.getParameterCount());
        constructor2.setAccessible(true); // 禁止检查访问权限
        Cat cat2 = (Cat) constructor2.newInstance("叮当猫", 3);
        System.out.println(cat2);

    }
}

获取类的成员变量:

获取到成员变量的作用:

赋值,取值。

代码演示:

这里准备一个Cat类:

java 复制代码
package com.itheima.d2_reflect;

public class Cat {
    public static int a;
    public static final String COUNTRY = "中国";
    private String name;
    private int age;

    public Cat(){
        System.out.println("无参数构造器执行了~~");
    }

    private Cat(String name, int age) {
        System.out.println("有参数构造器执行了~~");
        this.name = name;
        this.age = age;
    }

    private void run(){
        System.out.println("🐱跑的贼快~~");
    }

    public void eat(){
        System.out.println("🐱爱吃猫粮~");
    }

    private String eat(String name){
        return "🐱最爱吃:" + name;
    }

    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;
    }

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

测试代码:

java 复制代码
package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Field;

public class Test3Field {
    @Test
    public void testGetFields() throws Exception {
        // 1、反射第一步:必须是先得到类的Class对象
        Class c = Cat.class;
        // 2、获取类的全部成员变量。
        Field[] fields = c.getDeclaredFields();
        // 3、遍历这个成员变量数组
        for (Field field : fields) {
            System.out.println(field.getName() +  "---> "+ field.getType());
        }
        // 4、定位某个成员变量
        Field fName = c.getDeclaredField("name");
        System.out.println(fName.getName() + "--->" + fName.getType());

        Field fAge = c.getDeclaredField("age");
        System.out.println(fAge.getName() + "--->" + fAge.getType());

        // 赋值
        Cat cat = new Cat();
        fName.setAccessible(true); // 禁止访问控制权限    因为:private String name;
        fName.set(cat, "卡菲猫");
        System.out.println(cat);

        // 取值
        String name = (String) fName.get(cat);
        System.out.println(name);
    }
}

获取类的成员方法:

获取类的成员方法作用:

执行。

代码演示:

借用------获取成员变量里面的Cat类

开始测试:

java 复制代码
package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Method;

public class Test4Method {
    @Test
    public void testGetMethods() throws Exception {
        //  1、反射第一步:先得到Class对象。
        Class c = Cat.class;
        // 2、获取类的全部成员方法。
        Method[] methods = c.getDeclaredMethods();
        // 3、遍历这个数组中的每个方法对象
        for (Method method : methods) {
            System.out.println(method.getName() + "--->"
                    + method.getParameterCount() + "---->"
                    + method.getReturnType());
        }
        //  4、获取某个方法对象
        Method run = c.getDeclaredMethod("run"); // 拿run方法,无参数的
        System.out.println(run.getName() + "--->"
                + run.getParameterCount() + "---->"
                + run.getReturnType());

        Method eat = c.getDeclaredMethod("eat", String.class);
        System.out.println(eat.getName() + "--->"
                + eat.getParameterCount() + "---->"
                + eat.getReturnType());

        Cat cat = new Cat();
        run.setAccessible(true); // 禁止检查访问权限
        Object rs = run.invoke(cat); // 调用无参数的run方法,用cat对象触发调用的。
        System.out.println(rs);//null

        eat.setAccessible(true); // 禁止检查访问权限
        String rs2 = (String) eat.invoke(cat, "鱼儿");
        System.out.println(rs2);//🐱最爱吃:鱼儿
    }
}

反射的作用:

反射的重要用途:

使用反射做一个简易版的框架

需求:

实现步骤:

准备一个Student类:

java 复制代码
package com.itheima.d2_reflect;

public class Student {
    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;

    public Student() {
    }

    public Student(String name, int age, char sex, double height, String hobby) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
        this.hobby = hobby;
    }

    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;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
}

准备一个Teacher类:

java 复制代码
package com.itheima.d2_reflect;

public class Teacher {
    private String name;
    private double salary;

    public Teacher() {
    }

    public Teacher(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}

测试类如下:

java 复制代码
package com.itheima.d2_reflect;

import org.junit.Test;

public class Test5Frame {
    @Test
    public void save() throws Exception {
        Student s1 = new Student("黑马吴彦祖", 45, '男', 185.3, "蓝球,冰球,阅读");
        Teacher t1 = new Teacher("播妞", 999.9);

        // 需求:把任意对象的字段名和其对应的值等信息,保存到文件中去。
        ObjectFrame.saveObject(s1);
        ObjectFrame.saveObject(t1);
    }
}

还剩一个框架没写,如下是框架类:

java 复制代码
package com.itheima.d2_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("D:\\code\\javasepro\\helloworld-app\\src\\data.txt", true));
        // obj是任意对象,到底有多少个字段要保存。
        Class c = obj.getClass();
        String cName = c.getSimpleName();
        ps.println("---------------" + cName + "------------------------");
        // 2、从这个类中提取它的全部成员变量
        Field[] fields = c.getDeclaredFields();
        // 3、遍历每个成员变量。
        for (Field field : fields) {
            // 4、拿到成员变量的名字
            String name = field.getName();
            // 5、拿到这个成员变量在对象中的数据。
            field.setAccessible(true); // 禁止检查访问控制
            String value =  field.get(obj)+"";  //(String)强转不可用
            ps.println(name + "=" + value);
        }
        ps.close();
    }
}

注意注释中的细节。

测试结果图:-----正常运行

注解

自定义注解:

在IDEA中创建注解:----选择Annotation即可。

这里我们准备一个MyTest注解:

java 复制代码
package com.itheima.d3_annotation;

public @interface MyTest1 {


    //public可以不写
    String aaa();
    boolean bbb() default true;
    String[] ccc();


}

我们准备一个MyTest2注解:

java 复制代码
package com.itheima.d3_annotation;

public @interface MyTest2 {
    String value(); // 特殊属性
    int age() default 23;
}

创建测试类:---注意注释

java 复制代码
package com.itheima.d3_annotation;
@MyTest1(aaa="牛魔王",ccc={"HTML", "Java"})
// @MyTest2(value = "孙悟空")
//@MyTest2("孙悟空")    只有一个value可以这样写
//@MyTest2(value = "孙悟空", age = 1000)   加个age就不行,age没有默认值
@MyTest2("孙悟空")     //如果age有 默认值,又可以这样写
public class AnnotationTest1 {
    @MyTest1(aaa="铁扇公主", bbb=false, ccc={"Python", "前端", "Java"})
    public void test1(){

    }

    public static void main(String[] args) {
    //执行main方法
    }
}

我们执行main方法后,每个注解会生成一个.class文件,这个文件在哪?

右击我们的模块,找到Open ln ->Explorer,点击它,出现下方图:

点out文件夹,一直找到我们的包,就能看到.class文件:---只截取一部分

我们要用反编译软件编译它:

下面链接是反编译软件。

链接:https://pan.baidu.com/s/1MhyR5wqQHCwHVU84fHvGsw?pwd=8888

提取码:8888

下载完反编译软件后,点击下图的exe文件:

把MyTest1.class文件拖进去就能看到真正的源码了:

总结:

元注解

定义:

代码示例:

元注解写法: ---元注解是修饰注解的注解。

java 复制代码
package com.itheima.d3_annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD}) // 当前被修饰的注解只能用在类上,方法上。
@Retention(RetentionPolicy.RUNTIME) // 控制下面的注解一直保留到运行时
public @interface MyTest3 {

}

测试代码:

java 复制代码
package com.itheima.d3_annotation;
@MyTest3
public class AnnotationTest2 {
    // @MyTest3 不能用在变量上
    private String name;

    @MyTest3
    public void test(){

    }
}

注解的解析

如何解析注解:

解析注解案例

需求:

代码示例:

MyTest4类:

java 复制代码
package com.itheima.d3_annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest4 {
    String value();
    double aaa() default 100;
    String[] bbb();
}

Demo类:

java 复制代码
package com.itheima.d3_annotation;
@MyTest4(value = "蜘蛛精", aaa=99.5, bbb = {"至尊宝", "黑马"})
@MyTest3
public class Demo {
    @MyTest4(value = "孙悟空", aaa=199.9, bbb = {"紫霞", "牛夫人"})
    public void test1(){
    }
}

测试类:

java 复制代码
package com.itheima.d3_annotation;

import org.junit.Test;

import java.lang.reflect.Method;
import java.util.Arrays;

public class AnnotationTest3 {
    @Test
    public void parseClass(){
        // 1、先得到Class对象
        Class c = Demo.class;
        // 2、解析类上的注解
        // 判断类上是否包含了某个注解
        if(c.isAnnotationPresent(MyTest4.class)){
            MyTest4 myTest4 =
                    (MyTest4) c.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }
    @Test
    public void parseMethod() throws Exception {
        // 1、先得到Class对象
        Class c = Demo.class;
        Method m = c.getDeclaredMethod("test1");
        // 2、解析方法上的注解
        // 判断方法对象上是否包含了某个注解
        if(m.isAnnotationPresent(MyTest4.class)){
            MyTest4 myTest4 =
                    (MyTest4) m.getDeclaredAnnotation(MyTest4.class);
            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }
}

模拟Junit框架

需求:

代码示例:

MyTest类:

java 复制代码
package com.itheima.d3_annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD) // 注解只能注解方法。
@Retention(RetentionPolicy.RUNTIME) // 让当前注解可以一直存活着。
public @interface MyTest {

}

开始模拟:

java 复制代码
package com.itheima.d3_annotation;

import java.lang.reflect.Method;

public class AnnotationTest4 {
    // @MyTest
    public void test1(){
        System.out.println("===test1====");
    }

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

    //@MyTest
    public void test3(){
        System.out.println("===test3====");
    }

    @MyTest
    public void test4(){
        System.out.println("===test4====");
    }
    public static void main(String[] args) throws Exception {
        AnnotationTest4 a = new AnnotationTest4();
        // 启动程序!
        // 1、得到Class对象
        Class c = AnnotationTest4.class;
        // 2、提取这个类中的全部成员方法
        Method[] methods = c.getDeclaredMethods();
        // 3、遍历这个数组中的每个方法,看方法上是否存在@MyTest注解,存在
        // 触发该方法执行。
        for (Method method : methods) {
            if(method.isAnnotationPresent(MyTest.class)){
                // 说明当前方法上是存在@MyTest,触发当前方法执行。
                method.invoke(a);
            }
        }
    }
}

模拟结果: ---完美运行

动态代理

程序为什么需要代理?代理长什么样?

代理的案例图:

如何为Java对象创建一个代理对象?

代码示例:

根据案例图

先创建Star接口---当作中介公司:

java 复制代码
package com.itheima.d4_proxy;

public interface Star {
    String sing(String name);
    void dance();
}

创建BigStar类:-----明星类

java 复制代码
package com.itheima.d4_proxy;

public class BigStar implements Star {
    private String name;

    public BigStar(String name) {
        this.name = name;
    }
    public String sing(String name){
        System.out.println(this.name + "正在唱:" + name);
        return "谢谢!谢谢!";
    }
    public void dance(){
        System.out.println(this.name  + "正在优美的跳舞~~");
    }
}

创建代理类:

java 复制代码
package com.itheima.d4_proxy;

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

public class ProxyUtil {
    public static Star createProxy(BigStar bigStar){
       /* newProxyInstance(ClassLoader loader,
                Class<?>[] interfaces,
                InvocationHandler h)
                参数1:用于指定一个类加载器
                参数2:指定生成的代理长什么样子,也就是有哪些方法
                参数3:用来指定生成的代理对象要干什么事情
                */
        // 主程序:Star starProxy = ProxyUtil.createProxy(s);
        //       starProxy.sing("好日子") starProxy.dance()  去调用 invoke
        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.getName().equals("sing")){
                            System.out.println("准备话筒,收钱20万");
                        }else if(method.getName().equals("dance")){
                            System.out.println("准备场地,收钱1000万");
                        }
                        return method.invoke(bigStar, args);
                    }
                });
        return starProxy;
    }
}

创建测试类:

java 复制代码
package com.itheima.d4_proxy;

public class Test {
    public static void main(String[] args) {
        BigStar s = new BigStar("杨超越");
        Star starProxy = ProxyUtil.createProxy(s);

        String rs = starProxy.sing("好日子");
        System.out.println(rs);

        starProxy.dance();
    }
}

运行结果图:

相关推荐
2401_857617621 分钟前
SpringBoot校园资料平台:开发与部署指南
java·spring boot·后端
quokka564 分钟前
Springboot 整合 logback 日志框架
java·spring boot·logback
计算机学姐9 分钟前
基于SpringBoot+Vue的在线投票系统
java·vue.js·spring boot·后端·学习·intellij-idea·mybatis
救救孩子把25 分钟前
深入理解 Java 对象的内存布局
java
落落落sss28 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
万物皆字节33 分钟前
maven指定模块快速打包idea插件Quick Maven Package
java
夜雨翦春韭40 分钟前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法
简单.is.good1 小时前
【测试】接口测试与接口自动化
开发语言·python
我行我素,向往自由1 小时前
速成java记录(上)
java·速成
一直学习永不止步1 小时前
LeetCode题练习与总结:H 指数--274
java·数据结构·算法·leetcode·数组·排序·计数排序