2025年7.Java笔记:网络编程,TCP通信协议;函数式接口,函数式编程,stream流;单元测试,注解,反射

7.Java笔记:网络编程,TCP通信协议;函数式接口,函数式编程,stream流;单元测试,注解,反射parter1 网络编程 1 网络编程入门 软件结构 client serve browser serve 网络编程 一定协议下 两台计算机通信 网络四层结构 物理层 数据链路层 gt 网络层 gt 传输层 gt 应用层 网络通信分类 UDP 协议

大家好,我是讯享网,很高兴认识大家。

parter1 网络编程

1.网络编程入门

软件结构:client/serve browser/serve

网络编程:一定协议下,两台计算机通信。

网络四层结构:物理层/数据链路层 --> 网络层 --> 传输层 --> 应用层

网络通信分类:

  • UDP协议:无连接,不能保证数据完整,耗资小,视频会议。 数据限制在64kb以内,
  • TCP协议:面向连接,先建立链接,再传输数据。三次握手。保证数据安全,文件下载上传,网页浏览。

网络编程三要素:

  1. 协议
  2. IP地址
    cmd --> ipconfig ip配置信息 ping ip地址 ping通可以互发信息;ping失败,不可以 ping 127.0.0.1 本地ip地址 ping localhost 本地服务器ip地址 

    讯享网
  3. 端口号
    讯享网网络软件一打开,操作系统回味网络软件分配一个随机的端口号 端口号两个字节组成:0-65535 1024之前的端口号不能使用,已经被系统分配给已知软件 网络软件端口号不能重复使用 常用端口号: 1. 80端口,网络端口 2. 数据库端口号,mysql:3306 oracle:15213. Tomcat服务器:8080 

2. TCP通信程序

客户端: ip:端口号 Socket类 ① OutputStream:发送“你好服务器” ④InputStream 连接通路:IO流对象 服务器端: ip:端口号 ServeSocket类 ②InputStream:读取 “你好服务器” ③outputStream:回复 (c/s交互一次需要四个流对象) 实际情况: 1.多个客户端和服务器进行交互,服务器必须明确和哪个客户端进行交互 在服务器端有一个方法,叫accept客户端获取到请求的客户端对象。 2.多个客户端同时和服务器进行交互,就需要使用多个IO流对象 服务器是没有IO流的,服务器可以获取到请求的客户端对象Socket 使用每个客户端Socket提供的IO流和客户端进行交互。 Socket s1 = serve.accept(); Socket s2 = serve.accept(); 一言概之:服务器使用客户端的流和客户端交互。 
  1. socket
    讯享网TCP通信客户端:向服务器发送连接请求,给服务器发送数据,读取写回数据。 表示客户端的类:Java.net.Socket,此类实现客户端“套接字”。套接字是两台机器间通信的端点。 套接字:包含了IP地址和端口号的网络单位。 构造方法: Socket(String host, int port):服务器主机名称/服务器的IP地址 服务器的端口号 成员方法: OutputStream getOutputStream():返回此套接字的输出流。 InputStream getInputStream():返回此套接字的输入流。 void close();关闭此套接字。 使用步骤: 1.创建一个客户端对象Socket,构造方法中绑定服务器的IP地址和端口号。 2.使用Socket对象的方法getOutputStream获取网络字节输出流对象OutputStream。 3.使用网络字节输出流OuStream中的方法write,给服务器发送数据。 4.使用Socket对象的方法getInputStream()获取网络字节输入流InputStream对象 5.使用网络字节输入流的方法read,读取服务器写回的数据。 6.释放资源(socket) 注意事项: 1.客户端和服务器端进行交互必须使用socket中提供的网络流,不能使用自己创建的流对象。 2.创建客户端对象Socket的时候,就回去请求服务器,进行三次握手,建立连接通路。 如果服务器没有启动:会抛出异常。 如果服务器启动了:可以正常建立连接。 
    TCP服务器端:接收客户端请求,读取客户端数据,回写给客户端数据。 表示服务器的类:java.net.ServeSocket 此类实现服务器套接字。 构造方法: ServeSocket(int port) 创建绑定到特定端口的服务器套接字。 指定端口号。 服务器端必须明确,是那个客户端请求的服务器,所以可以用accept方法获取到客户端。 成员方法: Socket accept() 展厅并接受到此套接字的连接。 服务器实现步骤: 1.创建服务器对象 ServeSocket,和系统要指定端口号。 2.使用ServeSocket对象中的方法accept,获取到请求的客户端对象Socket。 3.使用Socket对象的方法getInputStream获取网络字节输入流对象InputStream。 3.使用网络字节输出流InputStream中的方法read,读取客户端发送的数据。 4.使用Socket对象的方法getOutputStream()获取网络字节输出流OutputStream对象 5.使用网络字节输出流的方法write,服务器向客户端写回数据。 6.释放资源(Socket, ServeSocket) 

3. 综合案例😞

TCP通信文件上传原理

读取本地文件上传到服务器,服务器把上传的文件保存到服务器的硬盘上。

    1. 客户端使用网络字节输出流,把读取到的文件上传到服务器上。
    2. 服务器使用网络字节输入流,读取客户端上传的文件
    3. 服务器使用本地字节输出流,把读取到的文件保存到服务器硬盘上,
    4. 服务器使用网络字节输入流,给客户端写一个“上传成功”。
    5. 客户端使用网络字节输入流,读取服务器写回的数据。
    6. 释放资源。

      注意:客户端和服务器对本地硬盘读写,需要使用自己创建的字节流对象(本地流)。

      客户端和服务器之间进行读写,必须使用Socket中提供的字节流对象(网络流)。

      文件上传即文件复制:需要明确 : 数据源+数据目的地。

    客户端使用本地字节输入流,读取要上传的文件。
  • 模拟BS服务器

    创建BS版本TCP服务器

    1. 创建一个服务器对象ServeSocket,和系统要指定的端口号。
    2. 使用accept方法获取到请求的客户端对象(浏览器),获取scoket。
    3. 使用socket对象中大的方法getInputStream对象中的方法read读取客户端请求信息。
    4. 使用网络字节流InputStream对象中的方法read读取客户端的请求信息。

parter2 函数式接口

1. 函数式接口

  1. 概念:有且只有一个抽象方法的接口。函数式接口就是适用于函数式编程场景的接口。

    Java中函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。

    只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利进行推导。 但是可以包含其他的(默认,静态,私有)方法。

  2. 格式
    讯享网修饰符 interface 接口名称{ 
          public abstract 返回值类型 方法名称;//抽象方法的 public abstract可以省略 //其他非抽象方法内容 } 
  3. @FunctionalInterface注解

    @FunctionalInterface用来检测是否是一个函数式接口。

  4. 自定义函数式接口

    函数式接口使用:一般可以作为方法的参数和返回值类型。

    • 可以作为方法的传递参数。(可以使用匿名内部类方式;可以使用Lambdda表达式)
    • 做传递参数时,传递的是接口,不是实现类!!!
    • Lambda不是匿名内部类的语法糖,二者原理不一样。Lambda效率更高!

2. 函数式编程

2.1 Lambda的延迟执行

  1. 浪费的日志案例。(有些代码不会执行,会产生性能浪费。)
  2. 体验lambda的更优写法。

    lambda特点:延迟加载。

    使用前提:必须存在函数式接口。

    简言之:只有满足条件了,才会执行Lambda表达式方法体内容!

  3. 证明lambda的延迟

2.2使用Lambda作为参数和返回值

  1. 使用lambda表达式作为方法的参数。要求参数是函数式接口,lambda在此负责实现接口方法。(可以使用匿名内部类)
  2. 函数式接口做方法的返回值类型。

3. 常用函数式接口

jdk提供的函数式接口都放在java.util.function包中 

3.1 Supplier接口

讯享网java.util.function.Supplier<T> 接口仅包含一个无参的方法,:T get() .用来获取一个泛型参数指定类型的对象数据。 Supplier<T> 接口称之为生产型接口,指定接口泛型。特有方法:T get();方法产生什么类型数据。 使用lambda表达式。 求int数组最大值。 在函数式接口中写出主要函数体。 

3.2Consumer接口

java.util.function.Consumer<T> 接口与supplier接口相反,消费一个数据。 特有抽象方法:void accept(T t) 消费一个指定类型的数据。 使用:使用lambda方式实现主要函数体。 默认方法:andThen 作用:需要两个consumer接口,可以把两个consumer接口组合到一起,在对数据进行消费。 例如:consumer<String> con1; consumer<String> con1; String s = "hello"; con1.accept(s); con2.accept(s); 可以使用lambda表达式方法来写,写lambda表达式时需要写两个。。 使用andThen方法: con1.andThen(con2).acccept(s); 谁写前面,谁先消费。可以使用lambda表达式方法来写,写lambda表达式时需要写两个。 

练习:格式化打印信息。

​ 将字符串数组的信息分隔开,再拼接打出。

讯享网原始数组信息 string[] arr = {"古力娜扎,25","迪丽热巴,23","马儿扎哈,29"}; 分割以后按照格式 姓名:name;年龄:age. 打印输出。 【注意区分原始数组中的 逗号 是中文输入还是英文输入。】 

3.3Predicate接口

java.util.function.Predicate<T>接口。 用来对数据类型进行判断,得到一个boolean值。 抽象方法:boolean test(T t);用来对指定数据类型及逆行判断。真truefalse。 对传递参数进行判断。 默认方法:and 表示并且关系,也可以用于连接两个判断条件。&&等价 默认方法:or 表示或关系。等价||。 默认方法:negate 表示取反关系。等价!。 

练习:集合信息筛选。

数组中有多条“姓名+性别”信息,通过predicator接口的拼装条件将符合要求的字符串选到集合AeeayList中,需要同时满足两个条件:必须为女生;姓名为四个字。

4 Function接口

讯享网java.util.function.Function<T,R> 接口用来根据一个类型的数据的到另一个类型的数据, 前者称为前置条件,后者称为后置条件。 抽象方法:R apply(T t) 根据类型T的参数获取类型R的结果。 使用场景:例如将String类型转换为Integer类型。 使用步骤: 1.定义一个方法,方法参数传递一个字符串类型的整数; 2.方法参数传递一个Function接口,泛型使用<String,Integer> 3.使用Function接口中的方法apply,把字符串类型的整数转换为Integer类型的整数。 默认方法:andThen 用来进行组合操作。 案例要求:把string类型转换为Integer类型,转换后的结果+10; 把增加之后的数据转换为String类型。 第一次:string->Integer 第二次:Integer->String 在这里就可以使用andThen方法,把两次转换组合在一起使用。fun1.apply完成第一次转换;fun2.apply完成第二次转换。 

练习:自定义函数模型拼接。

使用Function进行函数模型的拼接,按照顺序需要执行的多个函数操作为:

String str = “古丽娜,20”;

  1. 将字符串截取数字年龄部分,得到字符串。
  2. 将上不一步的字符串转换为int类型的数字。
  3. 将上一步的int数字+10,转换为字符串。

parter 3 stream流

  • IO流主要用来读写,Stream流主要对集合和数组进行简化操作。
  • 用stream流中的方法对集合和数组进行操作,用来解决集合和数组中现有的一些弊端。
  • 遍历的弊端:循环不是遍历的唯一方法。

1 流思想

  • jdk1.8之后出现的

    使用stream流,遍历集合,对集合中的数据进行过滤。

    list.stream().filter(predicate).filter().....forEach(lambda表达式); 
    • 过滤 --> 映射 --> 跳过 —> 计数 -->
    • 先建立模型,等到所有步骤解析完以后才会执行;都得益于lambda表达式的延迟执行。Java中的sttream不会存储元素,而是按需计算。
    • 数据的来源:数组,集合。
  • 与collection操作不同,Stream操作还有两个基本特征:
    • Pipelining:中间操作都返回流本身;构成管道。
    • 内部地迭代:增强for外部迭代,Stream提供了内部迭代的方法。
  • 使用流时通常包括三个步骤:获取一个操作数据源 → 数据转换 → 执行操作获取想要的结果,每次原有的stream对象不变,返回一个新的stream对象(可以有多次转换),流就像链条一样,变成一个管道。

2 获取流

讯享网java.util.stream.Stream<T>时java8新加入的常用的个流接口。(这不是一个函数式接口,有许多抽象方法。) 

获取一个流的方式:

  1. 所有的collection集合都可以通过Stream默认方法获取流。


    讯享网

    只有collection(list set)集合中有此方法,map集合中没有。 stream<E> stream(); Stream stream1 = list.stream(); Stream stream2 = set.stream(); Set keySet = map.keySet(); //对于map集合,先获取key值的set集合,再获取流 Stream stream3 = keySet.stream(); Collection<String> values = map.values(); //对于map集合,先获取values值的collection集合,再获取流 Stream stream4 = values.stream(); Set<Map.Entry<String,String>> entries = map.entrySet(); //获取键值对(鉴于值得映射关系 entrySet) Stream<Map.Entry<String,String>> stream5 = entries.stream(); 
  2. stream接口的静态方法of可以获取对应数组的流。
    讯享网//把数组转换为流 Stream<Integer> stram1 = Stream.of(1,2,3,4,5); Integer[] arr = { 
         1,2,3,4,5}; Stream<Integer> stram2 = Stream.of(arr); 

3.常用方法

  • 延迟方法:返回值类型依旧是本身,支持链式调用。
  • 终结方法:返回值类型不再是本身,不在支持链式调用。本小节中包括方法countforEach
  • 属于管道流,只能被使用一次。第一个stream调用完毕即关闭,数据就会流转到下一个流。
    1. 逐一处理:forEach void forEach(Consumer<T> con) 方法接受一个Consumer接口函数,会将每一个流元素交给该函数进行处理。 consumer接口是一个消费型的函数式接口,可以传递lambda表达式,消费数据。 概言之:用来遍历流中数据,是一个终结方法,遍历之后不能继续调用stream流中的其他方法。 2. 过滤:filter Stream filter(Predicate<T> pre); predicate用于判断的接口,有一个方法boolean test(T t); 3. 映射:map 将流中的元素映射到另外一个流中,需要使用map映射方法 Stream map(Function<T> fun); F接口中有一个方法:R apply(T t). 这种转换就称之为映射。 4. 统计个数:count 如同collection集合当中的size方法一样,流提供count方法来数一数其中的元素个数。 long count(); 终结方法,不能再调用其他stream方法。 5. 取用前几个:limit limit方法对流进行截取,只截取前几个。延迟方法,只是对流中元素进行截取,返回新流,可以继续调用其他方法。 集合当前长度较小时不进行操作。 Stream limit(long MaxSize); 6. 跳过前几个:skip Stream skip(long n); //跳过前n个,从第n+1个元素开始。 7. 组合:concat 把两个流组合为一个流。 Stream concat(Stream s1,Stream s2) 返回一个新流,原来两个流的拼接。 

4 练习:集合元素处理

讯享网题目:现在有两个ArrayList集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)依次进行以下若干操作步骤︰ 1.第一个队伍只要名字为3个字的成员姓名﹔存储到一个新集合中。 2.第一个队伍筛选之后只要前3个人;存储到一个新集合中。 3.第二个队伍只要姓张的成员姓名;存储到一个新集合中。 4.第二个队伍筛选之后不要前2个人;存储到一个新集合中。 5.将两个队伍合并为一个队伍;存储到一个新集合中。 6.根据姓名创建Person对象﹔存储到一个新集合中。 7.打印整个队伍的Person对象信息。 

parter4 第十章方法引用😞

  1. 冗余的 lambda
  2. 方法引用改进代码
  3. 方法引用符:::是引用运算符,它所在的表达式称为方法引用。如果lambda表达式要表达的函数已经存在某个方法的视线中,那么可以通过引用双冒号来引用该方法作为lambda的替代者。
    lanbda表达式写法:s -> System.out.println(s); 语义:拿到参数经lambda之手,继而传递给System.out.println方法去处理。 方法引用写法:System.out::println; 语义:直接让system.out类中的println方法来取代Lambda。 【注意】:lambda中传递的参数一定是方法引用中那个方法可以接受的类型,否则会抛异常, 
  4. 通过对象名引用成员方法

    使用前提:对象名是已经存在的,成员方法也是已经存在的。就可以使用对象名来引用成员方法。

  5. 通过类名称引用静态成员方法。

    使用前提:类已经存在;静态成员方法也已经存在。就可以使用类名称引用静态成员方法。

  6. 通过super引用成员方法。

    存在继承关系,当lambda表达式中需要super调用时,也可以使用方法引用进行替代。

    使用super引用父类的成员方法。

    super已经存在(子父类继承关系存在);父类成员方法已经存在。

  7. 通过this引用成员方法。

    this已经存在;本类的成员方法已经存在。

    this::本类成员方法。

  8. 类的构造器使用。

    构造方法的引用。

    构造器名称与类名称完全一样,并不固定。构造器的引用使用类名称::new的格式表示。

    构造方法已知;创建对象已知 new。就可以使用person引用new创建对象。

  9. 数组的构造器使用。

    数组的长度已知;已知创建的数组类型;

int[]::new方法引用。

parter5 基础加强

1. 单元测试Junit

  • 测试分类:
    • 黑盒测试:input --> 黑盒子 -->output。不需要写代码,给输入值,观察输出值。
    • 白盒测试:input --> 白盒子 -->output。需要写代码,关注具体写流程。
  • Junit白盒测试

    使用步骤:

    1. 定义一个测试类。(测试用例)

      这个类所在的包和被测试程序包平行;

      测试类名:xxxxTest

      测试包名:xx.xx.test

    2. 定义测试方法,可以独立运行。

      方法名:test测试的方法名 testAdd

      返回值:void

      参数列表:空参。

    3. 给方法前加上@Test。
    4. 导入Junit环境。
    5. 判定结果:

      Assert.assertEquals(期望结果,实际结果); 红色失败;绿色成功。

  • @Before

    一般用于资源申请。

    所有方法执行前都会执行此方法。一般命名public void init(){...}

  • @After

    一般用于资源释放。

    所有方法执行后比执行此方法。一般命名public void close(){...}

2.反射😞

  • 框架:半成品软件。在框架基础上开发软件,简化代码。
  • 反射:将类的各个组成部分封装成为其他对象,这就是反射机制。
    • 好处:可以在程序运行中操作这些对象。
    • 可以解耦,提高程序可扩展性。
讯享网Java程序的三个阶段: Source 源代码阶段 Class 类对象阶段 Runtime 运行时阶段 获取class对象的三种方式: 1.class.forName("全类名"):第一个阶段。将字节码文件加载进内,返回class对象。 2.类名.class:通过类名的属性class获取。 3.对象.getClass():getClass()方法在Object类中定义。所有的额对象都可以调用此方法。 class对象功能: 1.获取功能 获取成员变量们 Field getField(String name) //只能获取 指定名称的public修饰的成员变量 Field[] getFields() //只能获取public修饰的成员变量 Field getDeclaredField(String name) // 获取指定名称的成员变量,不考虑修饰符 Field[] getDeclaredFields() // 获取所有的成员变量,不考虑修饰符 获取到成员变量以后,成员变量可以进行的操作有 set() //设置成员变量的值 get() //获取成员变量的值 setAccessible(true) //忽略访问权限修饰符的安全检查。暴力反射。 //【所有的获取方法中都包含暴力反射方法】暴力反射方法一般都跟随declared方法后面使用,会涉及到安全修饰符问题。 获取构造方法们 Constructor<T> getConstructor(Class<?>... parameterTypes) Constructor<?>[] getConstructors() Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) Constructor<?>[] getDeclaredConstructors() 获取到构造方法后,可以创建对象: 创建对象: T newInstance(Object... initargs) 空参构造时,可以直接调用personClass.Instance()。得到一个空参构造。空参构造都是用这种方法。 setAccessible(true) //也包含暴力发射方法。 获取成员方法们 Method getMethod(String name, Class<?>... parameterTypes) // 获取指定名称和参数的方法 Method[] getMethods() //获取所有方法,包括object类中的方法 Method getDeclaredMethod(String name, Class<?>... parameterTypes) Method[] getDeclaredMethods() 获取到方法以后:一件事,执行方法。 方法名.invoke(类名);执行方法。 获取类名 String getName() Package getPackage() 

反射案例:

需求:写一个“框架”,可以帮我们创建任意类的对象,并且执行其中任意方法。 实现:1.配置文件 2.反射 步骤: 1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中。 2.在程序中加载读取配置文件。 3.使用反射技术来加载类文件进内存。 4.创建对象。 5.执行方法。 

3.注解

  • 注释:三种注释,单行,多行和文档。用文字描述程序,方便阅读。
  • 注解:说明程序,给计算机看的。Annotation,元数据。jdk1.5之后引入的。

    与类,接口,枚举在同一个层次。它可以声明在包,类,字段,方法,局部变量,方法参数等前面,用来对这些元素进行说明,注释。

    使用注解:@注解名称。

  • 注解的三种功能
    1. 编写文档:通过代码里的元数据[注解]生成文档【生成doc文档】。
    2. 代码分析:通过代码里标识的元数据[注解]对代码进行分析【使用反射】。
    3. 编译检查:通过代码里标识的元数据[注解]让编译器能够实现基本的额编译检查【override】。
  • 主要学习:
    • JDK预定义的一些注解
    • 自定义注解
    • 在程序中使用(解析)注解
小讯
上一篇 2025-01-16 20:03
下一篇 2025-02-11 15:18

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/122342.html