Day-11笔记 :
UDP: User Datagram Protocol, 用户数据报协议 特点: 1. 无连接的不可靠协议 2. 数据按包发送, 64K一个包 3. 速度快效率高, 容易丢包 用于视频直播, 网络电话
TCP: Transmission Control Protocol, 传输控制协议 特点: 1. 需要建立连接的可靠协议 电话 2. 数据传输无大小限制 3. 速度慢效率低 重发机制 用于文件下载, 浏览网页 TCP通信的三次握手: TCP协议中, 在发送数据的准备阶段, 客户端与服务器之间的三次交互, 以保证连接的可靠 1. 客户端向服务端发送验证信息, 等待服务器确认 2. 服务端收到验证信息后, 回复客户端验证信息, 同时发送自己的一条验证信息
3. 客户端收到服务端回复的信息, 确认自己之前发的信息无误, 并再次向服务器发回服务端的验证信息API:
java.net.ServerSocket类: TCP服务端 // 构造方法 ServerSocket(int port): 创建一个TCP服务端, 并监听指定端口 // 成员方法 Socket accept(): 监听数据, 会阻塞. 收到数据后返回Socket对象 void close(): 关闭服务端ServerSocket
java.net.Socket类: TCP客户端 // 构造方法 Socket(String ip, int port): 创建TCP客户端对象 // 成员方法 OutputStream getOutputStream(): 获取输出流对象, 用于发送数据 InputStream getInputStream(): 获取输入流, 用于接收数据 void shutdownOutput(): 关闭输出流, 告知服务端数据发送完毕 void close(): 关闭客户端Socket
Day-12 函数型接口自定义函数式接口 @FunctionalInterface 注解Lambda表达式: Lambda表达式的"延迟执行"的特点 函数式接口作为方法的"参数"和"返回值类型"常用函数式接口 Supplier: 生产型函数式接口 获取值 Consumer: 消费型函数式接口 使用值 Predicate: 条件判断型函数式接口 判断值 Function: 转换型函数式接口 转换值
函数式接口: JDK 8 新特性 有且仅有一个抽象方法的接口, 适用于函数式编程场景的接口 (默认方法, 静态方法, 私有方法, 与 java.lang.Object 类中定义相同的抽象方法, 都不算作抽象方法)
自定义函数式接口: 接口中有且只有一个抽象方法
@FunctionalInterface的作用: 在接口上使用, 检测当前的接口是否为函数式接口
函数式接口的使用: 作为方法的参数类型, 传递Lambda表达式, 代替匿名内部类方式
java.util.function.Supplier<T>函数式接口: 生产型函数式接口 // 抽象方法 T get(): 用于获取一个对象或值. 至于获取什么值, 怎么获取, 需要我们根据应用场景编写Lambda来实现 java.util.function.Consumer<T>函数式接口: 消费型函数式接口 // 抽象方法 void accept(T t): 用于消费(使用)一个对象或值. 至于怎么消费, 需要我们根据应用场景编写Lambda来实现 // 默认方法 default Consumer<T> andThen(Consumer<? super T> after): 拼接两个Consumer接口的Lambda对象实现连续操作. 谁写前面, 谁先消费 java.util.function.Predicate<T>函数式接口: 条件接口, 用于判断 // 抽象方法 boolean test(T t): 判断参数传递的对象. 至于怎么判断, 要判断什么, 需要我们编写Lambda表达式来实现 // 默认方法 (用于连接多个判断条件) default Predicate<T> and(Predicate<? super T> other): 与 default Predicate<T> or(Predicate<? super T> other): 或 default Predicate<T> negate(): 非, 取相反结果 java.util.function.Function<T,R>: 根据一个T类型的数据得到另一个R类型的数据 T称为前置条件, 也就是输入(input)的类型 R称为后置条件, 也就是返回结果(result)的类型 有进有出, 所以称为"函数Function" // 抽象方法 R apply(T t): 将T转换为R // 默认方法 default <V> Function<T, V> andThen(Function<? super R, ? extends V> after): 拼接多个Function转换
Day-13函数Stream流、方法引用java.util.Collection<E>接口: // 默认方法 default Stream<E> stream(): 将"集合"转换为Stream对象 java.util.stream.Stream<T>接口: 管道接口, 泛型为流中元素的类型 // 静态方法 static<T> Stream<T> of(T... values): 将"数组"转换为Stream对象 static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): 合并两个流为新流 // 抽象方法 void?forEach(Consumer<??super?T>?action): 遍历流中的元素进行逐一消费 (终结方法) long count(): 获取流中的元素个数 (终结方法) Stream<T>?filter(Predicate<??super?T>?predicate): 过滤符合条件的结果. 返回过滤后的流 <R>?Stream<R>?map(Function<??super?T,???extends?R>?mapper): 将T元素转换为R元素, 返回新的流 Stream<T> limit(long maxSize): 从流中获取前maxSize个 Stream<T>?skip(long?n): 从流中跳过n个元素, 获取后面的元素
方法引用能简化以下场景: (方法名后不要写小括号) 1. 通过对象名引用成员方法 对象名::成员方法名 2. 通过类名引用静态方法 类名::静态方法名 3. 通过super引用父类成员方法 super::父类方法名 4. 通过this引用本类成员方法 this::本类方法名
5. 引用某个类的构造方法 类名::new获取Stream流对象的2种方式: 1. 利用"Collection接口"中的默认方法 default Stream<E> stream() 方法: 集合转Stream对象
2. 利用"Stream接口"中的静态方法 static <T> Stream<T> of(T... values): 数组转Stream对象延迟方法: (具有延迟执行的特性) 返回值类型"是Stream"类型的方法, 支持链式调用 Stream filter(): 过滤 Stream map(): 映射/转换 Stream limit(): 截取 Stream skip(): 跳过终结方法: 返回值类型"不是Stream"类型的方法, 不支持链式调用 void forEach(): 遍历 long count(): 统计
方法引用能简化以下场景: (方法名后不要写小括号) 场景 格式 简化之前的Lambda 方法引用简化后 1. 通过对象名引用成员方法 对象名::成员方法名 ()->person.eat() person::eat 2. 通过类名引用静态方法 类名::静态方法名 i -> Math.abs(i) Math::abs 3. 通过super引用父类成员方法 super::父类方法名 ()->super.eat(); super::eat 4. 通过this引用本类成员方法 this::本类方法名 ()->this.eat(); this::eat 5. 引用某个类的构造方法 类名::new name->new Person(name) Person::new 6. 引用创建数组的方法 数据类型[]::new length->new int[length]; int[]::new
Day-14 测试、注解、反射
JUnit使用步骤: 1. 定义一个测试类(也叫测试用例) 包名:xxx.xxx.xx.test 被测试的类名: Calculator 对应的测试类名: CalculatorTest 2. 定义测试方法:可以独立运行 被测试的方法名: add() 对应的测试方法名: testAdd() 建议测试方法的返回值是void, 参数列表是空参 3. 在方法上加 @Test 注解 4. 在 @Test 注解上按 Alt+Enter, 选择 "Add 'JUnit4' to Classpath" 导入JUnit依赖环境 5. 在方法名上右键, 选择 "Run '方法名()'" 判定结果: 红色:失败 绿色:成功.(测试通过) 断言: Assert 使用断言操作来判断结果是否符合预期:
Assert.assertEquals(期望的结果, 运算的结果);
如果 期望的结果 和 运算的结果 相等, 则认为测试通过, 否则测试失败测试失败的原因提示: java.lang.AssertionError: Expected :1 (表示我期望得到的是1) Actual :-1 (但是实际得到的是-1)
Java代码在计算机中的3个阶段: SOURCE: 源代码阶段 CLASS: 类对象阶段 RUNTIME: 运行时阶段
获取一个类的字节码对象的3种方式: 1. Class.forName("全类名") 2. 类名.class . 3. 对象.getClass()
java.lang.Class<T>类: 表示一个类的字节码对象, 其中包含该类中定义的内容// 获取功能// 1. 获取成员变量们 Field[] getFields(): 获取所有 public 的成员变量 Field getField(String name): 获取指定名称的 public 的成员变量 Field[] getDeclaredFields(): 获取所有的成员变量, 不考虑权限修饰符 Field getDeclaredField(String name): 获取指定名称的成员变量, 不考虑权限修饰符// 2. 获取构造方法们 Constructor<?>[] getConstructors(): 获取所有 public 的构造方法 Constructor<T> getConstructor(Class<?>... parameterTypes): 获取指定的 public 构造方法 Constructor<?>[] getDeclaredConstructors(): 获取所有的构造方法, 不考虑权限修饰符 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): 获取指定的构造方法, 不考虑权限修饰符// 3. 获取成员方法们: Method[] getMethods(): 获取所有 public 的成员方法 Method getMethod(String name, Class<?>... parameterTypes) : 获取指定的 public 成员方法 Method[] getDeclaredMethods(): 获取所有的成员方法, 不考虑权限修饰符 Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取指定的成员方法, 不考虑权限修饰符// 4. 获取Class对象代表的类的全类名 String getName(): 获取当前Class对象代表的类的全类名// 其他 T newInstance(): 使用当前类的空参构造创建一个对象 A getAnnotation(Class<A> annotationClass): 获取当前类的注解对象 ClassLoader getClassLoader(): 返回该类的类加载器 java.lang.reflect.Field: 表示一个成员变量 // 成员方法 void set(Object obj, Object value): 设置指定对象的成员变量的值 Object get(Object obj): 获取指定对象的成员变量的值 void setAccessible(boolean flag): 传true时忽略访问权限修饰符的安全检查. 暴力反射 java.lang.reflect.Constructor<T>: 表示一个构造方法 // 成员方法 T newInstance(Object... initargs): 使用当前构造方法传入参数, 创建对象 void setAccessible(boolean flag): 注意: 构造方法不能利用此方法忽略权限, 会抛异常 java.lang.reflect.Method类: 表示一个成员方法 // 成员方法 Object invoke(Object obj, Object... args): 使用指定对象和指定参数值调用此方法 String getName(): 获取方法名 void setAccessible(boolean flag): 传true时忽略访问权限修饰符的安全检查. 暴力反射 java.lang.ClassLoader: 类加载器 // 成员方法 InputStream getResourceAsStream(String name): 读取相对于bin目录中的文件, 返回一个字节流 常用元注解: @Target: 描述注解能够作用的位置 ElementType枚举的常用取值: TYPE:可以作用于类上 METHOD:可以作用于方法上 FIELD:可以作用于成员变量上 示例: @Target(value = {ElementType.TYPE, ElementType.METHOD}) @Retention: 描述注解被保留的阶段 RetentionPolicy枚举的取值: SOURCE: 保留到源代码阶段 CLASS: 保留到类对象阶段 RUNTIME: 保留到运行时阶段 示例: @Retention(RetentionPolicy.RUNTIME):保留注解到class字节码文件中并被JVM读取到 @Documented: 加上后, 当前注解会被抽取到api文档中 @Inherited: 加上后, 当前注解会被子类继承
java.lang.Class<T> // 成员方法 ClassLoader getClassLoader(): 返回该类的类加载器 java.lang.ClassLoader: 类加载器 加载.class文件到内存的方法区中, 其他类型文件.properties // 成员方法 InputStream getResourceAsStream(String name): 读取相对于 out/production/模块名 目录中的文件, 返回一个字节流
使用类加载器加载配置文件 // 随便获取一个类的字节码对象 Class clazz = 类名.class; // 用字节码对象获取类加载器, 可加载bin目录中编译的文件 ClassLoader classLoader = clazz.getClassLoader(); // 使用类加载器加载一个文件, 返回一个字节流 InputStream is = classLoader.getResourceAsStream("相对于src目录的相对路径"); // 有了字节流, 就可以使用Properties的load(InputStream in)方法读取配置 Properties p = new Properties(); p.load(is); String value = p.getProperty("key");
自定义注解格式:关键字 @interface
元注解
public @interface 注解名称 {
属性; (接口中的抽象方法)
属性;
属性;
...
}@注解名称
元注解: 用于描述注解的注解 常用元注解: @Target: 描述注解能够作用的位置 ElementType枚举的常用取值: TYPE:可以作用于类上 METHOD:可以作用于方法上 FIELD:可以作用于成员变量上 示例: @Target(value = {ElementType.TYPE, ElementType.METHOD}) @Retention: 描述注解被保留的阶段 RetentionPolicy枚举的取值: SOURCE: 保留到源代码阶段 CLASS: 保留到类对象阶段 RUNTIME: 保留到运行时阶段 示例: @Retention(RetentionPolicy.RUNTIME):保留注解到class字节码文件中并被JVM读取到 @Documented: 加上后, 当前注解会被抽取到api文档中 @Inherited: 加上后, 当前注解会被子类继承