当前位置: 首页 > news >正文

反射, 注解, 动态代理

文章目录

    • 单元测试
      • 什么是单元测试
      • 咱们之前是如何进行单元测试的? 有啥问题 ?
      • 现在使用方法进行测试
      • 优点
      • Junit单元测试的使用步骤
      • 删除不需要的jar包
      • 总结
    • 反射
      • 认识反射、获取类
        • 什么是反射
        • 反射具体学什么?
        • 反射第一步:或者Class对象
      • 获取类中的成分、并对其进行操作
        • 获取类中构造器
        • 获取类的成员变量
        • 获取类的成员方法
      • 作用、应用场景
        • 使用反射做一个简易版的框架
    • 注解
      • 注解概述
        • 注解概述-自定义注解
        • 注解概述-注解的原理
        • 注解的作用
      • 元注解
        • 元注解是什么
      • 注解的解析
        • 如何解析注解?
        • 解析注解的案例
        • 总结
      • 作用、应用场景
    • 动态代理(设计模式)
      • 程序为什么需要代理?代理长什么样?
        • 什么是代理
        • 如何为Java对象创建一个代理对象?
        • 代码
        • 代码运行流程
      • 解决实际问题、掌握使用代理的好处

这些是源码、框架、架构师层面的技术

单元测试

什么是单元测试

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

咱们之前是如何进行单元测试的? 有啥问题 ?

  • 只能在main方法编写测试代码,去调用其他方法进行测试。
  • 无法实现自动化测试,一个方法测试失败,可能影响其他方法的测试。(报错就无法继续进行了)
  • 无法得到测试的报告,需要程序员自己去观察测试是否成功。(一个一个写main方法进行测试很麻烦)
    在这里插入图片描述

现在使用方法进行测试

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

优点

  • 可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。
  • 不需要程序员去分析测试的结果,会自动生成测试报告出来。如果测试良好则是绿色;如果测试失败,则是红色。
  • 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。

在这里插入图片描述

Junit单元测试的使用步骤

需求

  • 某个系统,有多个业务方法,请使用Junit单元测试框架,编写测试代码,完成对这些方法的正确性测试。
    具体步骤
  1. 将Junit框架的jar包导入到项目中(注意:IDEA集成了Junit框架,不需要我们自己手工导入了)
  2. 为需要测试的业务类,定义对应的测试类,并为每个业务方法,编写对应的测试方法(必须:公共、无参、无返回值)
  3. 测试方法上必须声明@Test注解,然后在测试方法中,编写代码调用被测试的业务方法进行测试;
  4. 开始测试:选中测试方法,右键选择“JUnit运行” ,如果测试通过则是绿色;如果测试失败,则是红色

业务

// StringUtil.java
/*** 字符串工具类*/
public class StringUtil {public static void printNumber(String name){if(name == null){System.out.println("参数为null!请注意");return;}System.out.println("名字长度是:" + name.length());}/*** 求字符串的最大索引*/public static int getMaxIndex(String data){if(data == null || "".equals(data)) {return -1;}return data.length() - 1;}
}

测试

// StringUtilTest.java
import org.junit.Assert;
import org.junit.Test;// 测试类:junit单元测试框架,对业务类中的业务方法进行正确性测试。
public class StringUtilTest {// 测试方法:必须是公开public,无参,无返回值。// 测试方法必须加上@Test注解(Junit框架的核心步骤)@Testpublic void testPrinNumber() {// 测试步骤:StringUtil.printNumber("张三abc"); // 5// 测试用例StringUtil.printNumber("");StringUtil.printNumber(null);}@Testpublic void testGetMaxIndex() {// 测试步骤:int index = StringUtil.getMaxIndex("abcdefg"); // 6// 测试用例int index2 = StringUtil.getMaxIndex("");int index3 = StringUtil.getMaxIndex(null);System.out.println(index);System.out.println(index2);System.out.println(index3);// 做断言:断言结果是否与预期结果一致// assertEquals("手写错误提示",预期结果,实际结果);Assert.assertEquals("本轮测试失败,业务获取的最大索引有问题!请检查",6, index);Assert.assertEquals("本轮测试失败,业务获取的最大索引有问题!请检查",-1, index2);Assert.assertEquals("本轮测试失败,业务获取的最大索引有问题!请检查",-1, index3);}
}

在这里插入图片描述

删除不需要的jar包

在这里插入图片描述
在这里插入图片描述

总结

1 Junit单元测试是做什么的?

  • 测试类中方法的正确性的。

2 Junit单元测试的优点是什么?

  • JUnit可以选择执行哪些测试方法,可以一键执行全部测试方法的测试。
  • JUnit可以生测试报告,如果测试良好则是绿色;如果测试失败,则是红色。
  • 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。

3 JUnit单元测试的实现过程是什么样的?

  • 必须导入Junit框架的jar包。
  • 定义的测试方法必须是无参数无返回值,且公开的方法。
  • 测试方法使用@Test注解标记。

4 JUnit测试某个方法,测试全部方法怎么处理?成功的标志是什么

  • 测试某个方法直接右键该方法启动测试。
  • 测试全部方法,可以选择类或者模块启动。
  • 红色失败,绿色通过。

反射

认识反射、获取类

什么是反射

反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。
比如idea中当你.一个对象为什么会有提示,这就是用了反射。反射可以解剖类的所有成员变量和方法。
在这里插入图片描述

反射具体学什么?

学习获取类的信息、操作它们
1、反射第一步:加载类,获取类的字节码:Class对象
2、获取类的构造器:Constructor对象
3、获取类的成员变量:Field对象
4、获取类的成员方法:Method对象

全部认识完后,再看反射的应用场景
在这里插入图片描述

反射第一步:或者Class对象

1、反射第一步:加载类,获取类的Class对象

在这里插入图片描述
获取Class对象的三种方式

  1. Class c1 = 类名.class
  2. 调用Class提供方法:public static Class forName(String package);
  3. Object提供的方法: public Class getClass(); Class c3 = 对象.getClass();
public class ReflectDemo1 {public static void main(String[] args) throws Exception {// 目标:掌握反射第一步操作:或者类的Class对象。(获取类本身)。// 1、获取类本身:类.classClass c1 = Student.class;System.out.println(c1);// class com.itheima.demo2reflect.Student// 2、获取类本身:Class.forName("类的全类名")Class c2 = Class.forName("com.itheima.demo2reflect.Student");System.out.println(c2);// class com.itheima.demo2reflect.Student// 3、获取类本身:对象.getClass()Student s = new Student();Class c3 = s.getClass();System.out.println(c3);// class com.itheima.demo2reflect.StudentSystem.out.println(c1 == c2); // trueSystem.out.println(c2 == c3); // true}
}
// student类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {private String name;private int age;private String hobby;
}

获取类中的成分、并对其进行操作

获取类中构造器

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

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

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

Constructor提供的方法说明
T newInstance(Object… initargs)调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回
public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)
获取类的成员变量

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

方法说明
public Field[] getFields()获取类的全部成员变量(只能获取public修饰的)
public Field[] getDeclaredFields()获取类的全部成员变量(只要存在就能拿到)
public Field getField(String name)获取类的某个成员变量(只能获取public修饰的)
public Field getDeclaredField(String name)获取类的某个成员变量(只要存在就能拿到)

获取到成员变量的作用:依然是赋值、取值。

方法说明
void set(Object obj, Object value):赋值
Object get(Object obj)取值
public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)
获取类的成员方法

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

方法说明
Method[] getMethods()获取类的全部成员方法(只能获取public修饰的)
Method[] getDeclaredMethods()获取类的全部成员方法(只要存在就能拿到)
Method getMethod(String name, Class<?>… parameterTypes)获取类的某个成员方法(只能获取public修饰的)
Method getDeclaredMethod(String name, Class<?>… parameterTypes)获取类的某个成员方法(只要存在就能拿到)

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

Method****提供的方法说明
public Object invoke(Object obj, Object… args)触发某个对象的该方法执行。
public void setAccessible(boolean flag)设置为true,表示禁止检查访问控制(暴力反射)
public class Dog {private String name;private int age;private String hobby;private Dog() {System.out.println("无参数构造器执行了~~");}private Dog(String name) {System.out.println("1个参数有参数构造器执行了~~");this.name = name;}public Dog(String name, int age) {System.out.println("2个参数有参数构造器执行了~~");this.name = name;this.age = age;}private void eat(){System.out.println("狗吃骨头!");}public String eat(String name){System.out.println("狗吃" + name);return "狗说:谢谢!谢谢!汪汪汪!";}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 String getHobby() {return hobby;}public void setHobby(String hobby) {this.hobby = hobby;}@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", age=" + age +", hobby='" + hobby + '\'' +'}';}
}
import org.junit.Test;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class ReflectDemo2 {@Testpublic void getClassInfo(){// 目标:获取类的信息。// 1、反射第一步:或者Class对象,代表拿到类。Class c1 = Student.class;System.out.println(c1.getName()); // 类名的全类名 com.itheima.demo2reflect.StudentSystem.out.println(c1.getSimpleName()); // 类名 Student}// 2、获取类的构造器对象并对其进行操作。@Testpublic void getConstructorInfo() throws Exception {// 目标:获取类的构造器对象并对其进行操作。// 1、反射第一步:或者Class对象,代表拿到类。Class c1 = Dog.class;// 2、获取构造器对象。Constructor[] cons = c1.getDeclaredConstructors();for (Constructor con : cons) {System.out.println(con.getName() + "(" + con.getParameterCount() + ")");}// com.itheima.demo2reflect.Dog(0)// com.itheima.demo2reflect.Dog(1)// com.itheima.demo2reflect.Dog(2)System.out.println("----------------------------------------------------------------");// 3、获取单个构造器Constructor con = c1.getDeclaredConstructor(); // 无参数构造器System.out.println(con.getName() + "(" + con.getParameterCount() + ")");//com.itheima.demo2reflect.Dog(0)Constructor con2 = c1.getDeclaredConstructor(String.class, int.class); // 2个参数的有参数构造器System.out.println(con2.getName() + "(" + con2.getParameterCount() + ")");// com.itheima.demo2reflect.Dog(2)// 4、获取构造器的作用依然是创建对象:创建对象。// 我们完全可以new Dog() 这里之所以不用new Dog(),是为了之后的学习打下基础。// 暴力反射:暴力反射可以访问私有的构造器、方法、属性。con.setAccessible(true); // 绕过访问权限,直接访问!Dog d1 = (Dog) con.newInstance();System.out.println(d1);// 无参数构造器执行了~~// Dog{name='null', age=0, hobby='null'}Dog d2 = (Dog)con2.newInstance("小黑", 3);System.out.println(d2);// 2个参数有参数构造器执行了~~// Dog{name='小黑', age=3, hobby='null'}}// 3、获取类的成员变量对象并对其进行操作。@Testpublic void getFieldInfo() throws Exception {// 目标:获取类的成员变量对象并对其进行操作。// 1、反射第一步:或者Class对象,代表拿到类。Class c1 = Dog.class;// 2、获取成员变量对象。Field[] fields = c1.getDeclaredFields();for (Field field : fields) {System.out.println(field.getName() + "(" + field.getType().getName() + ")");}// name(java.lang.String)// age(int)// hobby(java.lang.String)// 3、获取单个成员变量对象。Field field = c1.getDeclaredField("hobby");System.out.println(field.getName() + "(" + field.getType().getName() + ")");// hobby(java.lang.String)Field field2 = c1.getDeclaredField("age");System.out.println(field2.getName() + "(" + field2.getType().getName() + ")");// age(int)// 4、获取成员变量的目的依然是取值和赋值。Dog d = new Dog("泰迪", 3);// 2个参数有参数构造器执行了~~field.setAccessible(true); // 绕过访问权限,直接访问!field.set(d, "社交");  //  相当于 d.setHobby("社交");System.out.println(d);// Dog{name='泰迪', age=3, hobby='社交'}String hobby = (String) field.get(d); // 相当于 d.getHobby();System.out.println(hobby);// 社交}// 4、获取类的成员方法对象并对其进行操作。@Testpublic void getMethodInfo() throws Exception {// 目标:获取类的成员方法对象并对其进行操作。// 1、反射第一步:或者Class对象,代表拿到类。Class c1 = Dog.class;// 2、获取成员方法对象。Method[] methods = c1.getDeclaredMethods();for (Method method : methods) {System.out.println(method.getName() + "(" + method.getParameterCount() + ")");}// eat(0)// eat(1)// setHobby(1)// getHobby(0)// getAge(0)// setAge(1)// 3、获取单个成员方法对象。Method m1 = c1.getDeclaredMethod("eat");// 获取是无参数的eat方法Method m2 = c1.getDeclaredMethod("eat", String.class);// 获取是有参数的eat方法System.out.println(m1.getName() + "(" + m1.getParameterCount() + ")");// getName(0)System.out.println(m2.getName() + "(" + m2.getParameterCount() + ")");// toString(0)System.out.println("--------------------------------------");// 4、获取成员方法的目的依然是调用方法。Dog d = new Dog("泰迪", 3);// 2个参数有参数构造器执行了~~m1.setAccessible(true); // 绕过访问权限,直接访问!Object rs1 = m1.invoke(d); // 唤醒对象d的eat方法执行,相当于 d.eat(); //狗吃骨头!System.out.println(rs1); // nullObject rs2 = m2.invoke(d, "牛肉"); // 唤醒对象d的eat带String参数的方法执行,相当于 d.eat("牛肉");// 狗吃牛肉System.out.println(rs2);// 狗说:谢谢!谢谢!汪汪汪!}
}

作用、应用场景

反射的作用?

  • 基本作用:可以得到一个类的全部成分然后操作。
  • 可以破坏封装性。
  • 可以绕过泛型的约束
  • 最重要的用途是:适合做Java的框架,基本上,主流的框架都会基于反射设计出一些通用的功能。

在这里插入图片描述

import java.lang.reflect.Method;
import java.util.ArrayList;public class ReflectDemo3 {public static void main(String[] args) throws Exception {// 3、可以绕过泛型的约束。ArrayList<String> list = new ArrayList<>();list.add("张无忌");list.add("令狐冲");list.add("东方不败");
//        list.add(9.9);// 报错
//        list.add(true);Class c1 = list.getClass(); // c1 == ArrayList.class// 这是编译后,类名.class// 获取 ArrayList 类的add方法Method add = c1.getDeclaredMethod("add", Object.class);// 编译好后的文件已经把泛型擦除了, 所以这里可以添加任意类型的数据。// 触发list集合对象的add方法执行。add.invoke(list, 9.9); // 翻墙add.invoke(list, true); // 翻墙System.out.println(list);// [张无忌, 令狐冲, 东方不败, 9.9, true]}
}
使用反射做一个简易版的框架

需求:
对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去。
在这里插入图片描述
实现步骤

  1. 定义一个方法,可以接收任意对象。
  2. 每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量。
  3. 遍历成员变量,然后提取成员变量在该对象中的具体值。
  4. 把成员变量名、和其值,写出到文件中去即可。

反射有啥作用?
可以在运行时得到一个类的全部成分然后操作。
可以破坏封装性。(很突出)
也可以破坏泛型的约束性。(很突出)
更重要的用途是适合:做Java高级框架
基本上主流框架都会基于反射设计一些通用技术功能。

// 框架
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;public class SaveObjectFrameWork {// 保存任意对象的静态方法public static void saveObject(Object obj) throws Exception {PrintStream ps = new PrintStream(new FileOutputStream("day-15\\src\\com\\itheima\\demo2reflect\\obj.txt", true));// obj 可能是学生  老师  狗// 只有反射可以直到对象有多少个字段:// 1. 获取Class对象Class c = obj.getClass();String simpleName = c.getSimpleName();ps.println("==============" + simpleName + "====================");// 2. 获取Class对象的所有字段。Field[] fields = c.getDeclaredFields();// 3. 遍历字段for (Field field : fields) {// 4. 获取字段的值// 4.1 获取字段名称String fieldName = field.getName();// 4.2 获取字段的值field.setAccessible(true); // 暴力反射Object fieldValue = field.get(obj) + "";// 5. 打印到文件中去ps.println(fieldName + "=" + fieldValue);}ps.close();}
}
// 编写入口方法
public class ReflectDemo4 {public static void main(String[] args) throws Exception {// 目标:搞清楚反射的应用:做框架的通用技术。Dog d = new Dog("小黑", 3);SaveObjectFrameWork.saveObject(d);// 创建学生对象Student s = new Student("小明", 18, "爱问问题");SaveObjectFrameWork.saveObject(s);// 创建老师对象Teacher t = new Teacher("小红", 19, "java、前端、动漫", 3000, "422期", '女', "12345678901");SaveObjectFrameWork.saveObject(t);}
}
==============Dog====================
name=小黑
age=3
hobby=null
==============Student====================
name=小明
age=18
hobby=爱问问题
==============Teacher====================
name=小红
age=19
hobby=java、前端、动漫
salary=3000.0
className=422期
sex=女
phone=12345678901

注解

注解概述

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

注解概述-自定义注解

自定义注解
就是自己定义注解。

public @interface 注解名称 {public 属性类型 属性名() default 默认值 ;
}
@MyBook(name = "赵丽颖", age = 18, address = {"北京", "上海"})
public class AnnotationDemo1 {@MyBook(name = "王菲", age = 52, address = {"北京", "香港"})public static void main( String[] args ) {// 目标:自定义注解。int a;}
}// 自定义注解
public @interface MyBook {String name();int age() default 18;String[] address();
}

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

public  @interface A {String value(); // 特殊属性value,在使用时如果只有一个value属性,value名称可以不写String hobby() default "打篮球"; // 当这个有默认值,value名称也可以不写
}// @A(value = "delete")
//@A("delete") // 特殊属性value,在使用时如果只有一个value属性,value名称可以不写
//@A(value = "delete", hobby = "打篮球")
@A("delete")
public class AnnotationDemo1 {public static void main( @A("delete") String[] args ) {// 目标:自定义注解。@A("delete")int a;}
}
注解概述-注解的原理

在这里插入图片描述
注解本质是一个接口,Java中所有注解都是继承了Annotation接口的。
@注解(…):其实就是一个实现类对象,实现了该注解以及Annotation接口。

注解的作用
  • 对Java中类、方法、成员变量做标记,然后进行特殊处理。
  • 例如:JUnit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行

元注解

元注解是什么

指的是:注解(动词)注解(名词)的注解(名词)。

在这里插入图片描述
元注解是什么?
注解注解的注解
各自的作用是什么?
@Target约束自定义注解可以标记的范围。
@Retention用来约束自定义注解的存活范围。

//@MyTest1
public class AnnotationDemo2 {@MyTest1private int age;//    @MyTest1public AnnotationDemo2(){}@MyTest1public static void main(String[] args) {// 目标:搞清楚元注解的作用。}@MyTest1public void getAgeTest(){}
}// 元注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD, ElementType.FIELD}) // 表示注解的作用目标为方法,成员变量
@Retention(RetentionPolicy.RUNTIME) // 表示注解的保留策略: 编译器运行时(一直活着)
public @interface MyTest1 {  }

注解的解析

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

如何解析注解?
  • 指导思想:要解析谁上面的注解,就应该先拿到谁。
  • 比如要解析类上面的注解,则应该先获取该类的Class对象,再通过Class对象解析其上面的注解。
  • 比如要解析成员方法上的注解,则应该获取到该成员方法的Method对象,再通过Method对象解析其上面的注解。
  • Class 、 Method 、 Field , Constructor、都实现了AnnotatedElement接口,它们都拥有解析注解的能力。
AnnotatedElement 接口提供了解析注解的方法说明
public Annotation[] getDeclaredAnnotations()获取当前对象上面的注解。
public T getDeclaredAnnotation(Class annotationClass)获取指定的注解对象
public boolean isAnnotationPresent(Class annotationClass)判断当前对象上是否存在某个注解
解析注解的案例
  1. 定义注解MyTest4,要求如
    • 包含属性:String value()
    • 包含属性:double aaa(),默认值为 100
    • 包含属性:String[] bbb()
    • 限制注解使用的位置:类和成员方法上
    • 指定注解的有效范围:一直到运行时
  2. 定义一个类叫:Demo,在类中定义一个test1方法,并在该类和其方法上使用MyTest4注解
  3. 定义AnnotationTest3测试类,解析Demo类中的全部注解。
// 第一步
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD, ElementType.TYPE}) // 表示注解的作用目标为方法,成员变量
@Retention(RetentionPolicy.RUNTIME) // 表示注解的保留策略: 编译器运行时(一直活着)
public @interface MyTest2 {String value();double height() default 169.5;String[] address();
}// 第二步
@MyTest2(value = "刘亦菲", address = {"北京", "上海", "深圳"})
public class Demo {@MyTest2(value = "欧阳娜娜", address = {"湖南", "湖北"})public void go(){}
}// 第三步
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.Arrays;public class AnnotationDemo3 {// 目标:解析注解@Testpublic void parseClass() throws Exception {// 1.获取类对象Class c1 = Demo.class;// 2、使用isAnnotationPresent判断这个类上是否陈列了注解MyTest2if (c1.isAnnotationPresent(MyTest2.class)) {// 3、获取注解对象MyTest2 myTest2 = (MyTest2) c1.getDeclaredAnnotation(MyTest2.class);// 4、获取注解属性值String[] address = myTest2.address();double height = myTest2.height();String value = myTest2.value();// 5、打印注解属性值System.out.println(Arrays.toString(address));System.out.println(height);System.out.println(value);// [北京, 上海, 深圳]// 169.5// 刘亦菲}}@Testpublic void parseMethod() throws Exception {// 1.获取类对象Class c1 = Demo.class;// 2、获取方法对象Method method = c1.getMethod("go");// 3、使用isAnnotationPresent判断这个方法上是否陈列了注解MyTest2if (method.isAnnotationPresent(MyTest2.class)) {// 4、获取注解对象MyTest2 myTest2 = method.getDeclaredAnnotation(MyTest2.class);// 5、获取注解属性值String[] address = myTest2.address();double height = myTest2.height();String value = myTest2.value();// 6、打印注解属性值System.out.println(Arrays.toString(address));System.out.println(height);System.out.println(value);// [湖南, 湖北]// 169.5// 欧阳娜娜}}
}
总结

什么是注解的解析?注解解析的步骤是啥?

方法
Annotation[] getDeclaredAnnotations()
T getDeclaredAnnotation(Class<T> annotationClass)
boolean isAnnotationPresent(Class<Annotation> annotationClass)

作用、应用场景

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

需求

  • 定义若干个方法,只要加了MyTest注解,就会触发该方法执行。
    分析
  1. 定义一个自定义注解MyTest,只能注解方法,存活范围是一直都在。
  2. 定义若干个方法,部分方法加上@MyTest注解修饰,部分方法不加。
  3. 模拟一个junit程序,可以触发加了@MyTest注解的方法执行。
import java.lang.reflect.Method;
public class AnnotationDemo4 {// 目标:搞清楚注解的应用场景:模拟junit框架。有MyTest注解的方法就执行,没有的就不执行。public static void main(String[] args) throws Exception {AnnotationDemo4 ad = new AnnotationDemo4();// 1、获取类对象Class c = AnnotationDemo4.class;// 2、获取所有方法Method[] methods = c.getMethods();// 3、遍历所有方法,判断方法上是否有MyTest注解,有就执行,没有就不执行。for (Method method : methods) {// 4、判断方法上是否有MyTest注解if (method.isAnnotationPresent(MyTest.class)) {// 获取到这个方法的注解MyTest myTest = method.getDeclaredAnnotation(MyTest.class);int count = myTest.count();// 5、有就执行这个method方法for (int i = 0; i < count; i++) {method.invoke(ad);}// test3方法执行了// test3方法执行了// test1方法执行了// test4方法执行了}}}// 测试方法:public 无参 无返回值@MyTestpublic void test1(){System.out.println("test1方法执行了");}public void test2(){System.out.println("test2方法执行了");}@MyTest(count = 2)public void test3(){System.out.println("test3方法执行了");}@MyTestpublic void test4(){System.out.println("test4方法执行了");}
}// 注解。
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对象创建一个代理对象?

java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
参数一:用于指定用哪个类加载器,去加载生成的代理类
参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情
代码
// 接口:StarService
package com.itheima.demo4proxy;
// 明星行为接口
public interface StarService {void sing(String name);String dance();
}// Star.java
package com.itheima.demo4proxy;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Star implements StarService{private String name;@Overridepublic void sing(String name) {System.out.println(this.name + "表演唱歌:" + name);}@Overridepublic String dance() {System.out.println(this.name + "表演跳舞:魅力四射!" );return "谢谢!谢谢!";}
}
// ProxyUtil.java
package com.itheima.demo4proxy;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() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 用来声明代理对象要干的事情。// 参数一: proxy接收到代理对象本身(暂时用处不大)// 参数二: method代表正在被代理的方法// 参数三: args代表正在被代理的方法的参数String methodName = method.getName();if("sing".equals(methodName)){System.out.println("准备话筒,收钱20万!");}else if("dance".equals(methodName)){System.out.println("准备场地,收钱100万!");}// 真正干活(把真正的明星对象叫过来正式干活)// 找真正的明星对象来执行被代理的行为:method方法Object result = method.invoke(s, args);return result;}});return proxy;}
}
package com.itheima.demo4proxy;import java.lang.reflect.Proxy;public class Test {public static void main(String[] args) {// 目标:创建代理对象。// 1、准备一个明星对象:设计明星类。Star star = new Star("章若楠");// 2、为章若楠创建一个专属与她的代理对象。StarService proxy = ProxyUtil.createProxy(star);proxy.sing("《红昭愿》");System.out.println(proxy.dance());}
}
代码运行流程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Java提供了什么API帮我们创建代理?
Proxy的newProxyInstance方法。

newIProxyInstance方法在创建代理时,需要接几个参数,每个参数的含义是什么?

  1. 参数一:用于执行用哪个类加载器去加载生成的代理类。
  2. 参数二:用于指定代理类需要实现的接口: 明星类实现了哪些接口,代理类就实现哪些接口
  3. 参数三:用于指定代理类需要如何去代理(代理要做的事情)。

通过invokehandler的invoke方法指定代理干的事时,这个invoke会被谁调用?要接哪几个参数?
谁去调用触发谁的方法。
参数一: proxy接收到代理对象本身(暂时用处不大)
参数二: method代表正在被代理的方法
参数三: args代表正在被代理的方法的参数

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

使用代理优化用户管理类

场景
某系统有一个用户管理类,包含用户登录,删除用户,查询用户等功能,系统要求统计每个功能的执行耗时情况,以便后期观察程序性能。

需求
现在,某个初级程序员已经开发好了该模块,请观察该模块的代码,找出目前存在的问题,并对其进行改造。

package com.itheima.demo05proxy2;
/***  用户业务接口*/
public interface UserService {// 登录功能void login(String loginName,String passWord) throws Exception;// 删除用户void deleteUsers() throws Exception;// 查询用户,返回数组的形式。String[] selectUsers() throws Exception;String[] selectUsers2() throws Exception;
}package com.itheima.demo05proxy2;
/*** 用户业务实现类(面向接口编程)*/
public class UserServiceImpl implements UserService{@Overridepublic void login(String loginName, String passWord) throws Exception {// ----------------------if("admin".equals(loginName) && "123456".equals(passWord)){System.out.println("您登录成功,欢迎光临本系统~");}else {System.out.println("您登录失败,用户名或密码错误~");}Thread.sleep(1000);// --------------------------}@Overridepublic void deleteUsers() throws Exception{System.out.println("成功删除了1万个用户~");Thread.sleep(1500);}@Overridepublic String[] selectUsers() throws Exception{System.out.println("查询出了3个用户");String[] names = {"张全蛋", "李二狗", "牛爱花"};Thread.sleep(500);return names;}@Overridepublic String[] selectUsers2() throws Exception {System.out.println("查询出了3000个用户");String[] names = {"张全蛋2", "李二狗2", "牛爱花2"};Thread.sleep(2500);return names;}
}
package com.itheima.demo05proxy2;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtil {public static <T> T createProxy(T obj) {T proxy = (T) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),obj.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long start = System.currentTimeMillis(); // 记录开始时间 1970年1月1日0时0分0秒 走到此刻的总毫秒值// 真正调用业务对象被代理的方法Object result = method.invoke(obj, args);long end = System.currentTimeMillis();System.out.println(method.getName() + "方法耗时:"+(end-start)/1000.0+"秒");return result;}});return proxy;}
}
package com.itheima.demo05proxy2;import java.util.Arrays;/*** 目标:使用动态代理解决实际问题,并掌握使用代理的好处。*/
public class Test {public static void main(String[] args) throws Exception{// 1、创建用户业务对象。UserService userService = ProxyUtil.createProxy(new UserServiceImpl());// 2、调用用户业务的功能。userService.login("admin", "123456");userService.deleteUsers();String[] names = userService.selectUsers();System.out.println("查询到的用户是:" + Arrays.toString(names));String[] names2 = userService.selectUsers2();System.out.println("查询到的用户是:" + Arrays.toString(names2));}
}
您登录成功,欢迎光临本系统~
login方法耗时:1.007秒
成功删除了1万个用户~
deleteUsers方法耗时:1.506秒
查询出了3个用户
selectUsers方法耗时:0.515秒
查询到的用户是:[张全蛋, 李二狗, 牛爱花]
查询出了3000个用户
selectUsers2方法耗时:2.514秒
查询到的用户是:[张全蛋2, 李二狗2, 牛爱花2]

在这里插入图片描述

相关文章:

反射, 注解, 动态代理

文章目录 单元测试什么是单元测试咱们之前是如何进行单元测试的&#xff1f; 有啥问题 &#xff1f;现在使用方法进行测试优点Junit单元测试的使用步骤删除不需要的jar包总结 反射认识反射、获取类什么是反射反射具体学什么&#xff1f;反射第一步&#xff1a;或者Class对象 获…...

继续预训练 LLM ——数据筛选的思路

GPT生成数据微调qwen-2.5多模态模型实战项目 作者&#xff1a;柠檬养乐多 原文地址&#xff1a;https://zhuanlan.zhihu.com/p/30645776656 qwen2.5-vl是阿里通义实验室推出的qwen系列最新多模态大模型&#xff0c;在许多指标上已经超过或接近了gpt-4o。更为方便的是&#xff0…...

深入解析 PostgreSQL 外部数据封装器(FDW)的 SELECT 查询执行机制

引言 PostgreSQL 中的外部数据封装器&#xff08;Foreign Data Wrapper, FDW&#xff09;是一种扩展&#xff0c;允许您像访问 PostgreSQL 数据库中的表一样&#xff0c;访问和操作存储在外部数据源中的数据。FDW 使 PostgreSQL 能够与多种数据存储系统&#xff08;包括关系型…...

数据库系统概论|第六章:关系数据理论—课程笔记2

前言 前文我们介绍了规划化的基本概念&#xff0c;同时引入了关于规范化的相关定义与基本概念&#xff0c;低一级范式的关系模式&#xff0c;通过模式分解&#xff0c;可以转换为若干个高一级范式的关系模式的集合&#xff0c;这种过程就叫规范化。本文将围绕范式展开讨论&…...

package-lock.json能否直接删除?

package-lock.json能否直接删除&#xff1f; package-lock.json 生成工具&#xff1a;由 npm 自动生成。 触发条件&#xff1a;当运行 npm install 时&#xff0c;如果不存在 package-lock.json&#xff0c;npm 会创建它&#xff1b;如果已存在&#xff0c;npm 会根据它精确安…...

Ubuntu磁盘空间分析:du命令及常用组合

1、du命令的作用 du&#xff08;Disk Usage&#xff09;是 Ubuntu 系统中用于查看目录或文件磁盘使用情况的命令&#xff0c;主要用于分析磁盘空间占用。 2、语法 du [选项] [目录/文件路径]常用选项 2.1、-h 以 KB、MB、GB 等人性化可读格式&#xff08;Human-readable&am…...

《数据库原理》部分习题解析1

《数据库原理》部分习题解析1 1. 名词解释 &#xff08;1&#xff09;关系&#xff08;2&#xff09;属性&#xff08;3&#xff09;域&#xff08;4&#xff09;元组&#xff08;5&#xff09;码&#xff08;6&#xff09;分量&#xff08;7&#xff09;关系模式 &#xff0…...

汇川Easy系列PLC数据值改变功能块(随动增益改变判断)

PLC值改变事件 值改变触发功能块 PLC值改变事件 值改变触发功能块(SCL ST完整源代码)-CSDN博客文章浏览阅读1.1k次。本文介绍了在PLC中处理值改变事件的方法,包括值改变触发功能块的实现,详细讲解了FB接口定义、ST代码,并提供了在博途平台上的实现。此外,还分享了如何利用…...

数据清洗的艺术:如何为AI模型准备高质量数据集?

数据清洗的艺术&#xff1a;如何为AI模型准备高质量数据集&#xff1f; 引言 在人工智能和机器学习领域&#xff0c;我们常常听到"垃圾进&#xff0c;垃圾出"(Garbage in, garbage out)这句格言。无论你的模型架构多么精妙&#xff0c;算法多么先进&#xff0c;如果…...

怎么查看当前vue项目,要求的node.js版本

怎么查看当前vue项目&#xff0c;要求的node.js版本 找到 package.json package-lock.json 搜索 node...

游戏引擎学习第278天:将实体存储移入世界区块

总结并为今天的内容做好铺垫 今天的内容是关于开发一个完整的实体系统&#xff0c;目标是让这个系统更加实际和有效。之前讨论了如何通过一个模拟区域来处理无限大的世界。最初&#xff0c;使用浮动点数而不是双精度浮点数来避免潜在的精度问题&#xff0c;因为一些平台&#…...

计算机组成与体系结构:缓存设计概述(Cache Design Overview)

目录 Block Placement&#xff08;块放置&#xff09; Block Identification&#xff08;块识别&#xff09; Block Replacement&#xff08;块替换&#xff09; Write Strategy&#xff08;写策略&#xff09; 总结&#xff1a; 高速缓存设计包括四个基础核心概念&#xf…...

在Linux中如何使用Kill(),向进程发送发送信号

kill()函数 #include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig); 函数参数和返回值含义如下: pid:参数 pid 为正数的情况下,用于指定接收此信号的进程 pid;除此之外,参数 pid 也可设置为 0 或-1 以及小于-1 等不同值,稍后给说明。 …...

ElasticSearch重启之后shard未分配问题的解决

以下是Elasticsearch重启后分片未分配问题的完整解决方案&#xff0c;结合典型故障场景与最新实践&#xff1a; 一、快速诊断定位 ‌检查集群状态 GET /_cluster/health?pretty # status为red/yellow时需关注unassigned_shards字段值 ‌ 2.查看未分配分片详情 …...

基于 Spring Boot 瑞吉外卖系统开发(十四)

基于 Spring Boot 瑞吉外卖系统开发&#xff08;十四&#xff09; 查询订单 在管理端的首页&#xff0c;单击左侧菜单栏中的“订单明细”&#xff0c;会在右侧打开订单明细页面。 请求路径&#xff1a;/order/page 请求方法&#xff1a;GET 参数&#xff1a;page pageSize …...

【软件测试】第二章·软件测试的基本概念

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a;&#x1f3c0;软件测试与软件项目管理_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 …...

部署安装gitlab-ce-17.9.7-ce.0.el8.x86_64.rpm

目录 ​编辑 实验环境 所需软件 实验开始 安装部署gitlab171.配置清华源仓库&#xff08;版本高的系统无需做&#xff09;vim /etc/yum.repos.d/gitlab-ce.repo 2.提前下载包dnf localinstall gitlab-ce-17.9.7-ce.0.el8.x86_64.rpm --rocklinux 3.修改配…...

2025五一杭州西湖三天游

2025五一杭州西湖三天游 文章目录 2025五一杭州西湖三天游一、前言二、杭州游玩记录三、杭州三日游小结四、杭州美食街1、河坊街2、胜利河美食街3、高银街4、中山南路美食街5、武林夜市6、啦喜街美食广场7、大兜路美食街 五、豆包推荐的杭州三日游攻略三天主要行程**第一天&…...

实验五:以太网UDP全协议栈的实现(通过远程实验系统)

文章目录 FPGA以太网:从ARP到UDP的完整协议栈一、引言二、核心模块详解1. ARP协议处理模块1.1 `arp_cache`:ARP缓存模块1.2 `arp_tx`:ARP请求与应答发送模块1.3 `arp_rx`:ARP接收与解析模块2. MAC层处理模块2.1 `mac_layer`:MAC层顶层模块2.2 `mac_tx_mode`:MAC发送模式选…...

现代计算机图形学Games101入门笔记(八)

三角形三点已经知道在uv的位置了&#xff0c;那三角形内部的点&#xff0c;怎么算。 先看A 任一点 面积比求 根据三点坐标属性差值出内部点的位置。 纹理太小了&#xff0c;映射处理方式&#xff0c;取邻近的Nearest感觉一格格的&#xff0c;取周围4个权重Bilinear,取4*4Bicubi…...

C语言学习之文件操作

经过前面的学习&#xff0c;我们已经基本掌握了如何去写一个C语言的代码了。但是在实际的项目中&#xff0c;我们不可能不需要文件去操作。因为如果没有文件&#xff0c;我们写的程序是存储在电脑的内存中的。如果程序推出&#xff0c;内存回收数据就随之丢失了。如果我们要对数…...

《AI大模型应知应会100篇》第63篇:AutoGPT 与 BabyAGI:自主代理框架探索

第63篇&#xff1a;AutoGPT 与 BabyAGI&#xff1a;自主代理框架探索 摘要 随着大语言模型&#xff08;LLM&#xff09;技术的不断演进&#xff0c;自主代理&#xff08;Autonomous Agent&#xff09; 正在成为 AI 应用的新范式。它不仅能够理解用户意图&#xff0c;还能自主规…...

使用大模型预测急性结石性疾病技术方案

目录 1. 数据预处理与特征工程伪代码 - 数据清洗与特征处理数据预处理流程图2. 大模型构建与训练伪代码 - 模型训练模型训练流程图3. 术前预测系统伪代码 - 术前风险评估术前预测流程图4. 术中实时调整系统伪代码 - 术中风险预警术中调整流程图5. 术后护理系统伪代码 - 并发症预…...

基于运动补偿的前景检测算法

这段代码实现了基于运动补偿的前景检测算法。 主要功能包括&#xff1a; 运动补偿模块&#xff1a;使用基于网格的 KLT 特征跟踪算法计算两帧之间的运动&#xff0c;然后通过单应性变换实现帧间运动补偿。前景检测模块&#xff1a;结合两帧运动补偿结果&#xff0c;通过帧间差…...

鸿蒙OSUniApp开发富文本编辑器组件#三方框架 #Uniapp

使用UniApp开发富文本编辑器组件 富文本编辑在各类应用中非常常见&#xff0c;无论是内容创作平台还是社交软件&#xff0c;都需要提供良好的富文本编辑体验。本文记录了我使用UniApp开发一个跨平台富文本编辑器组件的过程&#xff0c;希望对有类似需求的开发者有所启发。 背景…...

W5500使用SocketTool工具测试

W5500使用SocketTool工具测试 1、按“WINR” 2、输入“IPCONFIG”&#xff0c;得到计算机的IP地址&#xff0c;子网掩码和网关 3、设置W5500设备网络参数如下&#xff1a; 本地网关&#xff1a;192.168.1.1 本地子网掩码: 255.255.255.0 本地物理地址&#xff1a;0C 2…...

《Python星球日记》 第71天:命名实体识别(NER)与关系抽取

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、命名实体识别&#xff08;NER&#xff09;基础1. 什么是命名实体识别&#…...

双向长短期记忆网络-BiLSTM

5月14日复盘 二、BiLSTM 1. 概述 双向长短期记忆网络&#xff08;Bi-directional Long Short-Term Memory&#xff0c;BiLSTM&#xff09;是一种扩展自长短期记忆网络&#xff08;LSTM&#xff09;的结构&#xff0c;旨在解决传统 LSTM 模型只能考虑到过去信息的问题。BiLST…...

CentOS7原有磁盘扩容实战记录(LVM非LVM)【针对GPT分区】

一、环境 二、命令及含义 fdisk ‌ ‌ fdisk‌是一个较老的分区表创建和管理工具&#xff0c;主要支持MBR&#xff08;Master Boot Record&#xff09;格式的分区表。MBR分区表支持的硬盘单个分区最大容量为2TB&#xff0c;最多可以有4个主分区。fdisk通过命令行界面进行操…...

如何在终端/命令行中把PDF的每一页转换成图片(PNG)

今天被对象安排了一个任务&#xff1a; 之前自己其实也有这个需要&#xff0c;但是吧&#xff0c;我懒&#xff1a;量少拖拽&#xff0c;量大就放弃。但这次躲不过去了&#xff0c;所以研究了一下有什么工具可以做到这个需求。 本文记录我这次发现的使用 XpdfReader 的方法。…...

【0415】Postgres内核 释放指定 memory context 中所有内存 ④

1. frees all memory (memory context) Postgres内核中由函数 AllocSetReset() 完成该功能。即 “释放给定set中分配的所有内存。” 它应当将所有已分配的chunks标记为已释放,但不一定需要归还set所拥有的全部资源。我们的实际实现是,除了“保留”块(“keeper” block)(…...

2025年Flutter初级工程师技能要求

在2025年&#xff0c;随着移动应用市场的持续增长和跨平台开发需求的不断增加&#xff0c;Flutter已经成为许多公司构建高性能、跨平台应用的首选框架。对于初入职场的Flutter初级工程师来说&#xff0c;掌握以下技能要求是必不可少的。这些技能不仅能够帮助你在工作中快速上手…...

AWS技术助力企业满足GDPR合规要求

GDPR(通用数据保护条例)作为欧盟严格的数据保护法规,给许多企业带来了合规挑战。本文将探讨如何利用AWS(亚马逊云服务)的相关技术来满足GDPR的核心要求,帮助企业实现数据保护合规。 一、GDPR核心要求概览 GDPR的主要目标是保护欧盟公民的个人数据和隐私权。其核心要求包括: 数…...

MVCC:数据库并发控制的利器

在并发环境下&#xff0c;数据库需要处理多个事务同时访问和修改数据的情况。为了保证数据的一致性和隔离性&#xff0c;数据库需要采用一些并发控制机制。MVCC (Multi-Version Concurrency Control&#xff0c;多版本并发控制) 就是一种常用的并发控制技术&#xff0c;它通过维…...

第二章、Isaaclab强化学习包装器(3):SKRL Wrapper

0 前言 官方文档&#xff1a;https://isaac-sim.github.io/IsaacLab/main/source/api/lab_rl/isaaclab_rl.html#module-isaaclab_rl.skrl https://skrl.readthedocs.io/en/latest/intro/getting_started.html 在本节中&#xff0c;您将学习如何使用 skrl 库的各种组件来创建强…...

AI数字人实现原理

随着人工智能与数字技术的快速发展&#xff0c;AI数字人&#xff08;Digital Human&#xff09;作为新一代人机交互媒介&#xff0c;正在多个行业中快速落地。无论是在虚拟主播、在线客服、教育培训&#xff0c;还是在数字代言、元宇宙中&#xff0c;AI数字人都扮演着越来越重要…...

RBTree的模拟实现

1&#xff1a;红黑树的概念 红⿊树是⼀棵⼆叉搜索树&#xff0c;他的每个结点增加⼀个存储位来表⽰结点的颜⾊&#xff0c;可以是红⾊或者⿊⾊。通过对任何⼀条从根到叶⼦的路径上各个结点的颜⾊进⾏约束&#xff0c;红⿊树确保没有⼀条路径会⽐其他路径⻓出2倍&#xff0c;因…...

ssh connect to remote gitlab without authority

ssh connect to remote gitlab without authority 1 this command can produce a ssh key for authority ssh-keygen -t ed25519 -C "your_emailexample.com"2 this command can get the comment about the key cat ~/.ssh/id_ed25519.pubcopy all content !!!...

gitlab提交测试分支的命令和流程

写在前面 先npm run lint:eslint 先走一遍代码校验然后再提交先把检验跑了再add commit push那些注意一下这个问题:git commit规范不对导致报错subject may not be empty[subject-empty]type may not be empty[type-empty]. 配置lint检查后&#xff0c; 使用commitlint之后报…...

序列化和反序列化hadoop实现

### Hadoop 中序列化与反序列化的实现机制 Hadoop 提供了自己的轻量级序列化接口 Writable&#xff0c;用于高效地在网络中传输数据或将其存储到磁盘。以下是关于其核心概念和实现方式的详细介绍&#xff1a; --- #### 1. **Hadoop 序列化的核心原理** Hadoop 的序列化是一…...

[操作系统] 策略模式进行日志模块设计

文章目录 [toc]一、什么是设计模式&#xff1f;二、日志系统的基本构成三、策略模式在日志系统中的落地实现✦ 1. 策略基类 LogStrategy✦ 2. 具体策略类▸ 控制台输出&#xff1a;ConsoleLogStrategy▸ 文件输出&#xff1a;FileLogStrategy 四、日志等级枚举与转换函数五、日…...

LeetCode 每日一题 3341. 到达最后一个房间的最少时间 I + II

3341. 到达最后一个房间的最少时间 I II 有一个地窖&#xff0c;地窖中有 n x m 个房间&#xff0c;它们呈网格状排布。 给你一个大小为 n x m 的二维数组 moveTime &#xff0c;其中 moveTime[i][j] 表示在这个时刻 以后 你才可以 开始 往这个房间 移动 。你在时刻 t 0 时从…...

《Python星球日记》 第68天:BERT 与预训练模型

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、BERT模型基础1. 什么是BERT?2. BERT 的结构3.预训练和微调对比二、BERT 的预训练任务1. 掩码语言模型 (MLM)2. 下一句预测 (NSP)三、微调 …...

Angular 知识框架

一、Angular 基础 1. Angular 简介 Angular 是什么&#xff1f; 基于 TypeScript 的前端框架&#xff08;Google 维护&#xff09;。 适用于构建单页应用&#xff08;SPA&#xff09;。 核心特性 组件化架构 双向数据绑定 依赖注入&#xff08;DI&#xff09; 模块化设计…...

python三方库sqlalchemy

SQLAlchemy 是 Python 中最强大、最受欢迎的 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它允许你使用 Python 对象来操作数据库&#xff0c;而不需要直接编写 SQL 语句。同时&#xff0c;它也提供了对底层 SQL 的完全控制能力&#xff0c;适用于从简单脚本到大型企…...

【SSL部署与优化​】​​如何为网站启用HTTPS:从Let‘s Encrypt免费证书到Nginx配置​​

网站启用HTTPS 的完整实战指南&#xff0c;涵盖从 Let’s Encrypt 免费证书申请到 Nginx 配置的详细步骤&#xff0c;包括重定向、HSTS 设置及常见问题排查&#xff1a; 一、准备工作 1. 确保域名解析正确 • 在 DNS 管理后台&#xff0c;将域名&#xff08;如 example.com&…...

Kubernetes控制平面组件:Kubelet详解(四):gRPC 与 CRI gRPC实现

云原生学习路线导航页&#xff08;持续更新中&#xff09; kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计&#xff08;一&#xff09;Kubernetes架构原则和对象设计&#xff08;二&#xff09;Kubernetes架构原则和对象设计&#xff08;三&#xff09;Kubernetes控…...

电商平台自动化

为什么要进行独立站自动化 纯人工测试人力成本高&#xff0c;相对效率低 回归测试在通用模块重复进行人工测试&#xff0c;测试效率低 前期调研备选自动化框架&#xff08;工具&#xff09;&#xff1a; Katalon Applitools Testim 阿里云EMAS Playwright Appium Cypress 相关…...

【kafka】kafka概念,使用技巧go示例

1. Kafka基础概念 1.1 什么是Kafka&#xff1f; Kafka是一个分布式流处理平台&#xff0c;用于构建实时数据管道和流式应用。核心特点&#xff1a; 高吞吐量&#xff1a;每秒可处理百万级消息持久化存储&#xff1a;消息按Topic分区存储在磁盘分布式架构&#xff1a;支持水平…...

计算机系统结构——Cache性能分析

一、实验目的 加深对Cache的基本概念、基本组织结构以及基本工作原理的理解。掌握Cache容量、相联度、块大小对Cache性能的影响。掌握降低Cache不命中率的各种方法以及这些方法对提高Cache性能的好处。理解LRU与随机法的基本思想以及它们对Cache性能的影响。 二、实验平台 实…...