黑马程序员JavaSE基础加强d6

------------javaSE基础加强d6---01-Java高级技术-Junit单元测试---------------------------------------------

反射、注解、动态代理;

属于源码、框架、架构师层面的技术;

前置知识:单元测试:

  1. 针对最小的功能单元:方法,编写测试代码对其进行正确性测试;
  2. 之前是如何进行单元测试的?有什么问题?
    1. 在main方法里调用,去调用其他方法进行测试,
    2. 无法实现自动化测试,一个方法测试失效,可能影响其他方法的测试;
    3. 无法得到测试的报告,需要程序员自己去观察测试是否成功;
  3. Junit单元测试框架:
    1. 可以用来对方法进行测试,它是第三方公司开源出来的(很多开发工具已经集成了Junit框架,比如IDEA)
    2. 优点:
      1. 可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立;
      2. 不需要程序员去分析测试的结果,会自动生成测试报告出来;
  4. Junit单元测试的使用步骤:
    1. 需求:某个系统,有多个业务方法,请使用Junit单元测试框架,编写测试代码,完成对这些方法的正确性测试;
    2. 具体步骤:
      1. 将Junit框架的jar包导入到项目中(注意:IDEA集成了Junit框架,不需要我们自己手工导入了)
      2. 为需要测试的业务类,定义对应的测试类,并为每个业务方法,编写对应的测试方法(必须:公共、无参、无返回值);
      3. 测试方法上必须声明@Test注解;然后在测试方法中,编写代码调用被测试的业务方法进行测试;
      4. 开始测试:选中测试方法,右键选择"Junit运行",如果测试通过则是绿色,测试失败是红色;

小结:

  1. Junit单元测试是做什么的?
    1. 测试类中方法的正确性;
  2. Junit单元测试的优点是什么?
    1. Junit可以选择执行哪些测试方法,可以一键执行全部测试方法的测试;
    2. Junit可以生成测试报告,如果测试良好则是绿色,如果测试失败则是红色;
    3. 单元测试中某个方法测试失败了,不会影响其他测试方法的测试;
  3. Junit单元测试的实现过程?
    1. 必须导入Junit框架的jar包;
    2. 定义的测试方法必须是无参数无返回值,且公开的方法;
    3. 测试方法使用@Test注解标记;
  4. Junit测试某个方法,测试全部方法怎么处理?成功的标志是什么?
    1. 测试某个方法直接右键该方法启动测试;
    2. 测试全部方法,可以选择类或模块启动;
    3. 红色失败、绿色代表通过;

------------javaSE基础加强d6---02-Java高级技术-反射概述---------------------------------------------------

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

反射具体学什么?

学习获取类的信息,操作他们;

  1. 反射第一步:加载类,获取类的字节码:Class对象;
  2. 获取类的构造器:Constructor对象;
  3. 获取类的成员变量:Field对象;
  4. 获取类的成员方法:Method对象;
  5. 全部认识完后,再看反射的应用场景;

获取Class对象的三种方式:

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

小结:

  1. 反射指的是什么?
  2. 反射主要学什么?
  3. 反射第一步是什么?
  4. 如何获取Class?

------------javaSE基础加强d6---03-Java高级技术-反射获取类的成分并对其进行操作------------------

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

|-----------------------------------------------------------------------|-------------------------|
| 方法 | 说明 |
| Constructor<?>[ ] getConstructors() | 获取全部的构造器(只能获取public修饰的) |
| Constructor<?> [ ] getDeclaredConstryctors() | 获取全部构造器(只要存在就能拿到) |
| Constructor<T> getConstructor(Class<?> ...parameterTypes) | 获取某个构造器(只能public修饰的) |
| Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 获取某个构造器(只要存在就能拿到) |

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

|-----------------------------------------|----------------------------------|
| Constructor提供的方法 | 说明 |
| T newInstance(Object... initargs) | 调用此构造器对象标识的构造器,并传入参数,完成对象的初始化并返回 |
| public void setAccessible(boolean flag) | 设置为ture,标识进制检查访问控制(暴力反射) |

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

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


//使用方法
public class Demo2_2Reflect {
    //目标:掌握反射第二步:获取类的对象;并对其进行操作;
    //1、反射第一步:获取类本身;
    @Test
    public void getClassInfo() {
        Class c1 = Dog.class;
        System.out.println(c1.getName());           //类名的全类名;
        System.out.println(c1.getSimpleName());     //类名;
    }

    @Test
    public void getConstructorInfo() throws Exception {
        //目标:获取类的构造方法;
        Class c1 = Dog.class;
        //2、获取构造器对象;
        Constructor[] cons = c1.getDeclaredConstructors();
        for (Constructor con : cons) {
            System.out.println(con.getName() + "2、获取构造器对象  (" + con.getParameterCount() + ")");
        }
        //3、获取单个构造器:
        Constructor con1 = c1.getDeclaredConstructor();
        System.out.println(con1.getName() + "3、获取单个构造器  (" + con1.getParameterCount() + ")");

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

        //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        //拿到构造器的作用依然是创建对象:

        //ok报错没关系,因为前面设置的无参构造器是私有的,这里可以暴力反射,可以访问私有的构造器、方法、属性;
        con1.setAccessible(true);
        Dog d1 = (Dog)con1.newInstance();   //它也不知道这是什么构造器,所以要强转为狗构造器;
        System.out.println(d1);

        Dog d2 = (Dog) con2.newInstance("小花", 10);
        System.out.println(d2);
    }

    //3、获取类的成员变量并对其进行操作:
    @Test
    public void testGetFieldInfo() throws Exception {
        //目标:获取类的成员变量并操作;
        //1、反射第一步,获取Class对象,代表拿到类:
        Class c1 = Dog.class;
        Field[] fields = c1.getDeclaredFields();
        for (Field field : fields){
            System.out.println(field.getName() + "  " + field.getType().getName());
        }
System.out.println("------------------------------------------------------------------------------------------------------------------------------------------");
        //2、获取单个成员变量并操作
        Field field = c1.getDeclaredField("hobby");
        System.out.println(field.getName() + "  " + field.getType().getName());

        Field field1 = c1.getDeclaredField("age");
        System.out.println(field1.getName() + "  " + field1.getType().getName());

        //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        //获取成员变量的目的依然是取值和赋值;
        Dog d = new Dog("泰迪" , 5);
        field.setAccessible( true);     //暴力反射;;
        field.set(d,"社交");
        //d.setHobby("社交");
        System.out.println(d);

        String hobby = (String) field.get(d);
        System.out.println(hobby);
    }

    //4、获取成员变量并操作
    @Test
    public void testGetFields() throws Exception {
        Class c1 = Dog.class;
        Method[] methods = c1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + "(" + method.getParameterCount() + ")");
            //获取方法的名称 + 参数个数
        }
        System.out.println("------------------------------------------------------------------------------------------------------------------------------------------");
        Method m = c1.getDeclaredMethod("eat");
        System.out.println(m.getName() + "(" + m.getParameterCount() + ")");

        Method m2 = c1.getDeclaredMethod("eat" , String.class);
        System.out.println(m2.getName() + "(" + m2.getParameterCount() + ")");

        System.out.println("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
        //获取方法的作用也是为了调用方法;
        Dog dog = new Dog("社交" , 3);
        m.setAccessible( true);     //这里的m就代表上边的eat方法;;
//        m.invoke(dog);            //唤醒对象dog的eat方法执行,相当于dog.eat();
        Object rs1 = m.invoke(dog);            //
        System.out.println("返回值:  ---"  + rs1);        //没有返回值

        //m2方法:    public void eat(String name){
        //        System.out.println(name + "狗子吃吃吃");
        Object rs2 = m2.invoke(dog,"三十斤胖");
        System.out.println("返回值:  ---"  + rs2);            //因为它是对象dog带String参数类型的eat方法执行,相当于dog.eat("三十斤胖");
    }

}

小结:

  1. 如何去获取类的构造器、成员变量、方法?
  2. 获取到他们、各自有啥作用?
  3. 如何突破访问权限?
    1. 对象。setAccessible(ture);暴力反射;

------------javaSE基础加强d6---04-Java高级技术-反射的作用------------------------------------------------

  1. 反射的作用?
    1. 基本作用:可以得到一个类的全部成分然后操作;
    2. 破坏封装性;
    3. 可以绕过泛型的约束;
    4. 最重要的用途是:适合做java的框架,
    5. 基本上,主流的框架都会基于反射设计出一些通用的技术功能;
  2. 使用反射做一个简易版的框架:
    1. 需求:
      1. 对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去;
    2. 实现步骤:
      1. 定义一个方法,可以接收任意对象;
      2. 每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量;
      3. 遍历成员变量,然后提取成员变量在该对象中的具体值;
      4. 把成员变量名,和其值,写出到文件中即可;

简易框架代码:

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

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;

public class SaveObjectFrameWork {
    //保存任意对象的静态方法:
    public static void saveObject(Object obj)throws  Exception{
//        PrintStream ps = new PrintStream("day06-junit-reflect-annotation-proxy\\src\\com\\itheima\\demo2reflect\\demo2_Save.txt");
        PrintStream ps = new PrintStream(new FileOutputStream("day06-junit-reflect-annotation-proxy\\src\\com\\itheima\\demo2reflect\\demo4_Save.txt",true));

        //obj 可能是老师、学生、狗
        //只有反射可以知道对象有多少个字段;
        //1、获取Class对象
        Class c1 = obj.getClass();

        String simpleName = c1.getSimpleName();
        ps.println("======================" + simpleName + "======================");
        //2、获取所有字段
        Field[] fields = c1.getDeclaredFields();
        //3、遍历所有的字段;
        for (Field field : fields){
            //4、获取字段值
            //4.1、获取字段名称:
            field.setAccessible(true);
            String fieldName = field.getName();
            //4.2、获取字段值
            Object fieldValue = field.get(obj) +  "";
            //5、打印到文件中;
            ps.println(fieldName + "=" + fieldValue);
        }
        ps.close();
    }
}

测试代码:

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

public class demo4Reflect {
    public static void main(String[] args) throws  Exception{
        //目标:搞清楚反射的作用,做框架的通用技术:
        Dog dog = new Dog("二蛋","睡大觉",10);
        SaveObjectFrameWork.saveObject(dog);
        Student s = new Student("小王",18,"睡觉");
        SaveObjectFrameWork.saveObject(s);
        Teacher t = new Teacher("小李",18,"女","爱自己在家玩",dog,60000,"123456");
        SaveObjectFrameWork.saveObject(t);
    }
}

(需要提前定义好着几个类)

------------javaSE基础加强d6---05-Java高级技术-注解-自定义注解-元注解---------------------------------

注解:相对抽象;;

  1. 注解概述:

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

    1. 就是自己定义注解:
    java 复制代码
    public @interface 注解名称{
        public 属性类型 属性名() default 默认值;
    }

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

  3. 注解的原理:

    1. 反编译后发现,注解本质是接口,这个接口继承了Annotation类(所有的注解都继承了这个类)

    2. 所有的属性都是抽象方法;

    3. @注解(...):其实就是一个实现类对象,实现了该注解以及Annotation接口;

  4. 注解的作用:

    1. 对Java中类、方法、成员变量做标记,然后进行特殊处理;

    2. 例如:JUnit框架中,标记了注解@Test的方法就可以被当成测试方法执行,没用标记的就不能当测试方法执行;

元注解:

  1. 元注解指的是:注解注解的注解;
    1. @Target:目标位置:

      1. 声明被修饰的注解只能在哪些位置使用:
      java 复制代码
      @Target(ElementType.TYPE)
      1、TYPE;类、接口
      2、FIELE; 成员变量
      3、METHOD; 成员方法
      
      4、PARAMETER; 方法参数
      5、CONSTRUCTOR ;构造器
      6、LOCAL_VARIABLE ; 局部变量

      1

    2. @Retention:保留周期;

      1. 作用:声明注解的保留周期;

      java 复制代码
      @Retention(RetentionPolicy.RUNTIME)
      1、SOURCE;;只作用在源码阶段;字节码中不存在;
      2、CLASS(默认);保留到字节码文件阶段,运行阶段不存在;
      3、RUNTIME(开发常用); 一直保留到运行阶段;

------------javaSE基础加强d6---06-Java高级技术-注解的解析------------------------------------------------

  1. 注解的解析:

    1. 就是判断类、方法、成员变量上是否存在注解,并把注解里的内容给解析出来;
  2. 如何解析注解?

    1. 指导思想:要解析谁上边的注解,就应该先拿到谁;

    2. 比如要解析类上边吗注解,就应该先拿到该类的Class对象,再通过Class对象在解析其上边的注解;

    3. Class、Method、Field、Constructor、都实现了AnnotatedElement接口,他们都有解析注解的能力

      |-------------------------------------------------------------------------|-----------------|
      | AnnotatedElement接口提供了解析注解的方法 | 说明 |
      | public Annotation[ ] getDeclaredAnnotations( ) | 获取当前对象上边的注解 |
      | public T getDeclaredAnnotation(Class<T> annotationClass) | 获取指定的注解对象 |
      | public boolean isAnnotationPresent(Class<Annotation> annotationClass) | 判断当前对象上是否存在某个注解 |

      1

  3. 解析注解的案例:

    1. 定义注解MyTest4,要求:

      1. 包含属性:String value()

      2. 包含属性:double aaa(),默认值为100;

      3. 包含属性:String[ ] bbb()

      4. 限制注解使用的位置:类和成员方法上

      5. 指定注解的有效范围:一直到运行时;

    2. 定义一个类叫:Demo,在类中定义一个test1方法,并在该类和其方法上使用MyTest4注解;

    3. 定义AnnotationTest3测试类,解析Demo类中的全部注解;

------------javaSE基础加强d6---07-Java高级技术-注解的应用场景------------------------------------------

注解的作用:进行特殊标记,方便别人特殊使用;

注解的属性:比如属性int count() default 1; 然后有一个方法注解count = 5就是这个方法要测五次;

使用注解开发出一个简易版的Junit框架:

  1. 需求:定义若干个方法,只要加了MyTest注解,就会触发该方法执行;
  2. 分析:
    1. 定义一个自定义注解MyTest,只能注解方法,存货范围一直都在;
    2. 定义若干个方法,部分方法加上@MyTest注解修饰,部分方法不加;
    3. 模拟一个junit程序,可以触发加了@MyTest注解的方法执行;

注解类:

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

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 {
    int count() default 1;
}

测试类:

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

import java.lang.reflect.Method;

public class Demo5Annnotation {
    public static void main(String[] args) {
        //目标:搞清楚注解的应用场景:模拟Junit框架,有MyTest注解的方法就执行;
        //1、获取类对象
        Class c1 = Demo5Annnotation.class;
        //2、获取所有方法
        Method[] methods = c1.getDeclaredMethods();
        //3、遍历方法,判断方法上是否有MyTest注解
        for (Method method : methods) {
            if (method.isAnnotationPresent(MyTest.class)){
//                System.out.println("执行方法:"+method.getName());
                try {
                    int count = method.getAnnotation(MyTest.class).count();
                    for (int i = 0; i < count; i++) {
//                        method.invoke(new Demo5Annnotation());      //需要有对象才能触发;
                        Demo5Annnotation d = new Demo5Annnotation();
                        method.invoke(d);                           //跟上边一样;

                    }
                }catch (Exception e){e.printStackTrace();}
            }
        }
    }
    public void test1(){
        System.out.println("test1方法执行了...");
    }
    @MyTest
    public void test2(){
        System.out.println("test2方法执行了...");
    }
    public void test3(){
        System.out.println("test3方法执行了...");
    }
    @MyTest
    public void test4(){
        System.out.println("test4方法执行了...");
    }
    @MyTest(count = 5)
    public void test5(){
        System.out.println("test5方法执行了...");
    }
}

------------javaSE基础加强d6---08-Java高级技术-代理概述-动态代理的代码实现------------------------

动态代理:一种设计模式;

相当于中介,提前为对象准备好需要的资源,然后传给对象;

  1. 如何为java对象创建一个代理对象?

    1. java.lang.reflect.Proxt类:提供了为对象产生代理对象的方法:
    java 复制代码
    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
    //参数一:用于指定用哪个类加载器,去加载生成的代理类;
    //参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法?
    //参数三:用来指定生成的代理对象要干什么事情

1

  1. 程序为什么需要代理?代理长什么样子?
    1. 后期很多

小结:

  1. Java提供了什么API帮我们创建代理?
    1. Proxy。newproxyInstance()
  2. Proxy.newProxyInstance方法在创建代理时,需要接几个参数?每个参数的含义是什么?
    1. 参数一:用于执行用哪个类加载器去加载生成的代理类;
    2. 参数二:代理对象要代理的接口;明星类实现了哪些接口,代理类就实现了哪些接口;
    3. 参数三:用于指定代理类需要如何去代理(代理要做的事情);
  3. 通过invokehandler的invoke方法指定代理干的事时,这个invoke会被谁调用,要接哪几个参数?
    1.

------------javaSE基础加强d6---09-Java高级技术-动态代理-解决实际问题-优势---------------------------

解决实际问题;掌握使用代理的好处:

案例:使用代理优化用户管理类:

  1. 场景:
    1. 某系统有一个用户管理类:包含用户登录;删除用户,查询用户等功能,系统要求统计每个功能的执行耗时情况,以便后期观察程序性能;
  2. 需求:
    1. 现在,某个初级程序员已经开发好了该模块,请观察该模块的代码,找出目前存在的问题,并对其进行改造;

Java中的王者框架:Spring框架;可以理解为一个代理加工厂,可以处理所有的方法;

一种思想:

AOP切面编程:在调我方法的时候,方法前植入了一段代码;方法执行之后植入了一段代码;

相关推荐
superman超哥9 小时前
Rust VecDeque 的环形缓冲区设计:高效双端队列的奥秘
开发语言·后端·rust·rust vecdeque·环形缓冲区设计·高效双端队列
幽络源小助理9 小时前
springboot基于Java的教学辅助平台源码 – SpringBoot+Vue项目免费下载 | 幽络源
java·vue.js·spring boot
电商API&Tina9 小时前
电商数据采集 API:驱动选品、定价、运营的数据分析核心引擎
大数据·开发语言·人工智能·python·数据分析·json
亓才孓9 小时前
JUnit--Before,After,Test标签
java·junit·log4j
susu10830189119 小时前
maven-3.9.12的conf配置settings.xml
xml·java·maven
半路程序员9 小时前
Go内存泄漏排查pprof和trace使用
开发语言·后端·golang
沐知全栈开发9 小时前
PHP MySQL 插入数据
开发语言
WongLeer9 小时前
Go + GORM 多级分类实现方案对比:内存建树、循环查询与 Preload
开发语言·后端·mysql·golang·gorm
一直都在5729 小时前
MyBatis入门:CRUD、参数处理与防 SQL 注入
java·sql·mybatis