Fivk博客 - Java
type: channel
link: https://blog.fivk.cn/category/Java/
description: 学java，赚大钱。
items: 【Java】动态代理
items: 【Java】深入理解CompletableFuture：Java中强大的异步编程工具
items: 【开发技巧】Java根据详细地址获取对应经纬度
items: 【开发技巧】Mybatis官方推荐的批量插入方法
items: 【Java】注解
items: 【Java】反射
items: 【Java】JUnit单元测试
items: 【Java】函数式接口
items: 【Java】网络编程
items: 【Java】IO流

【Java】动态代理
type: item
date: 2024-01-18T11:14:47+08:00
description: [scode type="share" size="simple"]在Java中，动态代理是一种机制，允许在运行时创建代理对象来代替原始对象。代理对象可以拦截并处理原始对象的方法调用，以实现额外的逻辑或行为。[/scode]动态代理主要依赖于Java的反射机制。通过动态代理，我们可以在不修改原始对象的情况下，对其方法进行增强或拦截。这对于实现横切关注点（cross-cutting concerns）非常有用，如日志记录、性能监控、事务管理等。在Java中，动态代理通常涉及两个主要角色：接口（Interface）：定义了原始对象和代理对象之间的公共方法。InvocationHandler接口：定义了代理对象的调用处理程序。它包含一个invoke()方法，该方法在代理对象上调用方法时被调用。在invoke()方法中，可以实现对原始方法的增强逻辑。使用动态代理时，我们需要以下步骤：定义接口：定义原始对象和代理对象之间的公共方法。创建InvocationHandler实现类：实现InvocationHandler接口，并在invoke()方法中编写对原始方法的增强逻辑。使用Proxy类创建代理对象：使用Proxy类的静态方法newProxyInstance()，传入ClassLoader、接口数组和InvocationHandler对象，来创建代理对象。调用代理对象的方法：通过代理对象调用方法时，将会触发InvocationHandler的invoke()方法，从而执行增强逻辑。动态代理在Java中被广泛应用于AOP（面向切面编程）等场景，它提供了一种灵活的方式来实现横切关注点的功能。下面是一个简单的案例来演示Java中的动态代理：假设我们有一个接口 Calculator，定义了一个计算器的基本功能，包括加法、减法、乘法和除法：public interface Calculator { int add(int a, int b); int subtract(int a, int b); int multiply(int a, int b); int divide(int a, int b); }现在，我们希望在每次调用这些方法时记录日志。我们可以使用动态代理来实现这个功能。首先，我们创建一个实现 InvocationHandler 接口的类 CalculatorInvocationHandler：import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class CalculatorInvocationHandler implements InvocationHandler { private Calculator target; public CalculatorInvocationHandler(Calculator target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用方法：" + method.getName()); Object result = method.invoke(target, args); System.out.println("方法调用结果：" + result); return result; } }然后，我们使用 Proxy 类的 newProxyInstance() 方法来创建代理对象：import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { Calculator calculator = new BasicCalculator(); CalculatorInvocationHandler invocationHandler = new CalculatorInvocationHandler(calculator); Calculator proxy = (Calculator) Proxy.newProxyInstance( calculator.getClass().getClassLoader(), calculator.getClass().getInterfaces(), invocationHandler); // 使用代理对象调用方法 int sum = proxy.add(2, 3); int differen…

【Java】深入理解CompletableFuture：Java中强大的异步编程工具
type: item
date: 2024-01-17T15:27:00+08:00
description: [scode type="share" size="simple"]摘要：CompletableFuture是Java中用于处理异步操作的强大工具，它提供了丰富的API方法和灵活的功能，可以简化并发编程的复杂性。本文将介绍CompletableFuture的API文档、用途、案例和详细说明，帮助读者深入理解和灵活运用CompletableFuture。[/scode]1. CompletableFuture的API文档CompletableFuture类提供了许多API方法来处理异步任务。以下是CompletableFuture类的一些常用API方法：创建CompletableFuture对象的静态方法：static CompletableFuture<Void> runAsync(Runnable runnable)static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)static CompletableFuture supplyAsync(Supplier supplier)static CompletableFuture supplyAsync(Supplier supplier, Executor executor)异步任务完成时的处理方法：CompletableFuture<T> thenApply(Function<? super T, ? extends U> fn)CompletableFuture<Void> thenAccept(Consumer<? super T> action)CompletableFuture<Void> thenRun(Runnable action)组合多个CompletableFuture对象的方法：CompletableFuture thenCompose(Function<? super T, ? extends CompletionStage> fn)CompletableFuture<Void> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn)异常处理方法：CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)CompletableFuture<T> handle(BiFunction<? super T, Throwable, ? extends U> fn)并行执行多个CompletableFuture对象的方法：static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)2. CompletableFuture的用途CompletableFuture在异步编程中有广泛的应用，它可以帮助开发人员处理异步操作的完成、组合和转换。下面是CompletableFuture的一些常见用途：异步任务的执行和结果获取：通过CompletableFuture的静态方法supplyAsync和runAsync，可以创建异步任务并获取其执行结果。异步任务完成时的处理：使用thenApply、thenAccept和thenRun等方法，可以在异步任务完成时对结果进行转换、消费或执行指定的操作。多个异步任务的组合：通过thenCompose和thenCombine等方法，可以将多个CompletableFuture对象进行组合，实现任务的串行或并行执行，并对结果进行处理。异常处理：使用exceptionally和handle等方法，可以对异步任务发生的异常进行处理，并返回默认值或进行其他操作。并行执行多个异步任务：通过allOf和anyOf等方法，可以并行执行多个CompletableFuture对象，并在它们全部完成或任意一个完成时进行相应的操作。3. CompletableFuture的案例和说明下面是几个使用CompletableFuture的案例和详细说明：3.1 异步任务的执行和结果获取import java.util.concurrent.CompletableFuture; public class CompletableFutureExample { public static void main(String[] args) { // 创建C…

【开发技巧】Java根据详细地址获取对应经纬度
type: item
date: 2024-01-10T09:45:00+08:00
description: [scode type="blue" size="simple"]Q：稳不稳定？A：稳不稳定我不知道，不过我永远相信gov.cn后缀域名网站的稳定性！[/scode]获取密钥去天地图注册开发者账号：http://lbs.tianditu.gov.cn/我测试在代码中新建的项目需要选择服务端新建之后复制密钥在Java中的代码首先导入Maven坐标<dependency> <groupId>org.snmp4j</groupId> <artifactId>snmp4j</artifactId> <version>2.8.18</version> </dependency>需要用到的工具类import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import java.io.*; import java.net.URI; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @Slf4j public class HttpClientUtil { /** * 封装HTTP POST方法 * * @param * @param * @return * @throws ClientProtocolException * @throws IOException */ public static String post(String url, Map<String, String> paramMap) throws ClientProtocolException, IOException { HttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(url); //设置请求和传输超时时间 RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(60000).setConnectTimeout(60000).build(); httpPost.setConfig(requestConfig); List<NameValuePair> formParams = setHttpParams(paramMap); UrlEncodedFormEntity param = new UrlEncodedFormEntity(formParams, "UTF-8"); httpPost.setEntity(param); HttpResponse response = httpClient.execute(httpPost); log.info("************{}", response); String httpEntityContent = getHttpEnti…

【开发技巧】Mybatis官方推荐的批量插入方法
type: item
date: 2023-12-20T16:33:00+08:00
description: 1.背景介绍在写crud时使用mybatis写批量插入用的foreach标签，报错 Packet for query is too large (9601829 > 4194304).当遇到比较多的数据时，就会出现这个错误，比如excel导入时。2.推荐方法在官网中：https://mybatis.org/mybatis-dynamic-sql/docs/insert.html查阅了资料发现：官网推荐的批量方法如下try(SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class); List<SimpleTableRecord> records = getRecordsToInsert(); // not shown BatchInsert<SimpleTableRecord> batchInsert = insert(records) .into(simpleTable) .map(id).toProperty("id") .map(firstName).toProperty("firstName") .map(lastName).toProperty("lastName") .map(birthDate).toProperty("birthDate") .map(employed).toProperty("employed") .map(occupation).toProperty("occupation") .build() .render(RenderingStrategies.MYBATIS3); batchInsert.insertStatements().forEach(mapper::insert); session.commit(); }对应的SpringBoot方式如下注意如果SimpleTableMapper方法继承了Mapper，不要写insert方法，不然冲突了，Mapper已经存在insert方法。@Mapper public interface SimpleTableMapper { void insert(SimpleTableRecord record); }@Service public class SimpleTableService { @Autowired private SimpleTableMapper mapper; @Autowired private SqlSessionFactory sqlSessionFactory; public void insertRecords(List<SimpleTableRecord> records) { try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { for (SimpleTableRecord record : records) { mapper.insert(record); } session.commit(); } }3.优势使用批量插入相比于逐条插入的方式，具有以下优势：提高插入效率：批量插入可以减少与数据库的通信次数，一次性将多条记录发送给数据库，从而有效提高插入的效率。减少事务开销：在批量插入中，可以将多个插入操作合并为一个事务，减少了事务的开销。相比于逐条插入需要每条数据都开启和关闭事务，批量插入可以显著降低事务管理的开销。降低系统负载：由于批量插入减少了与数据库的交互次数，减轻了系统的负担和网络传输的压力，有助于提高整个系统的性能和响应速度。简化代码逻辑：通过批量插入，可以将多个插入操作合并到一起，简化了代码逻辑。不再需要手动遍历进行逐条插入，降低了代码的复杂性和维护成本。综上所述，批量插入在大规模数据插入时具有明显的性能优势，并且可以降低系统负载和简化代码逻辑。对于需要频繁插入大量数据的场景，使用批量插入是一个更加高效和可靠的选择。

【Java】注解
type: item
date: 2021-10-06T12:12:00+08:00
description: 1、概述注解：注解（Annotation），即元数据。是代码级别的说明。JDK1.5及以后版本引入了该特性，与类、接口、枚举属于同一级别。它可以声明在包、类、字段、方法、局部变量、方法参数上，以对这些元素进行说明。使用方式：@注解名称[scode type="blue" size="simple"]可以在编译时选择注解是否只存在于源码中，或者是保留在字节码(.class)文件中或者是出现在运行中。[/scode][scode type="green" size="simple"]注释是给程序员看的注解是给程序看的注解是元数据[/scode]2、作用编写文档：通过注解生成文档代码分析：通过注解对代码进行分析【反射中使用】编译检查：通过注解让编译器实现基本的编译检查【Override】3、JDK中预定义的注解@Override ：检测该方法是否是覆盖自父类(接口)的@Deprecated ：表示该部分内容已过时@SuppressWarnings ：压制警告一般传递参数all @SuppressWarnings("all")4、自定义注解4.1、格式元注解 public @interface 注解名称{ // 属性列表（抽象方法） }4.2、本质注解本质上是一个接口，该接口默认继承Annotation接口 java.lang.annotation.Annotation4.3、属性属性就是接口中的抽象方法。要求属性的返回值类型有下列取值基本数据类型String枚举注解以上类型的数组定义了属性，在使用时需要给属性赋值如果定义属性时，使用default关键字给属性默认初始化值，则使用注解时，可以不进行属性的赋值。如果只有一个属性需要赋值，并且属性的名称是value，则value可以省略，直接定义值即可。数组赋值时，值使用{}包裹。如果数组中只有一个值，则{}可以省略。4.4、元注解元注解是用于描述注解的注解。@Target ：描述注解能够作用的位置ElementType取值：TYPE：可以作用于类上METHOD：可以作用于方法上FIELD：可以作用于成员变量上@Retention ：描述注解被保留的阶段@Retention(RetentionPolicy.RUNTIME) ：当前被描述的注解，会保留到class字节码文件中，并被JVM读取到@Documented ：描述注解是否被抽取到api文档中@Inherited ：描述注解是否被子类继承5、在程序中使用注解的属性值获取注解定义的位置的对象 （Class，Method,Field）获取指定的注解 getAnnotation(Class)自动在内存中生成了一个该注解接口的子类实现对象调用注解中的抽象方法获取配置的属性值public class Person { public void eat() { System.out.println("eat..."); } }public class Student { public void study() { System.out.println("study..."); } }/** * 自定义注解 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Pro { String className(); String methodName(); }@Pro(className = "com.junlong.reflect.Person", methodName = "eat") public class ReflectPro { // 不改变该类的任何代码，就可以创建任意对象，并执行其任意方法 public static void main(String[] args) throws Exception { // 1. 解析注解 // 1.1 获取该类的字节码文件对象 Class<ReflectPro> reflectClass = ReflectPro.class; // 1.2 获取指定注解 Pro annotation = reflectClass.getAnnotation(Pro.class); // 1.3 调用注解中的抽象方法，获取属性 String className = annotation.className(); String methodName = annotation.methodName(); // 2. 反射 // 2.1 加载类的字节码文件进内存 Class<?> aClass = Class.forName(className); // 2.2 创建对象 Object o = aClass.new…

【Java】反射
type: item
date: 2021-10-06T12:10:57+08:00
description: Java的反射（reflection）机制是指在程序的运行状态中，可以构造任意一个类的对象，可以了解任意一个对象所属的类，可以了解任意一个类的成员变量和方法，可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。1、获取Class对象的方法Class.forName(“全类名”)：将字节码文件加载进内存，返回Class对象多用于配置文件，将类名定义在配置文件中。读取文件，加载类类名.class：通过类名的属性class获取多用于参数的传递对象.getClass()：getClass()方法在Object类中定义着多用于对象的获取字节码的方式【注意】同一个字节码文件(*.class)在一次程序运行过程中，只会被加载一次，不论通过哪一种方式获取的Class对象都是同一个。2、Class对象功能2.1、获取成员变量Field[] getFields() ：获取所有public修饰的成员变量Field getField(String name) ：获取指定名称的 public修饰的成员变量Field[] getDeclaredFields() ：获取所有的成员变量，不考虑修饰符Field getDeclaredField(String name) ：获取指定名称的成员变量，不考虑修饰符2.2、获取构造方法Constructor<?>[] getConstructors()Constructor<?> getConstructor(Class<?>... parameterTypes)Constructor<?>[] getDeclaredConstructors()Constructor<?> getDeclaredConstructor(Class<?>... parameterTypes)2.3、获取成员方法Method[] getMethods()Method getMethod(String name, Class<?>... parameterTypes)Method[] getDeclaredMethods()Method getDeclaredMethod(String name, Class<?>... parameterTypes)2.4、获取全类名String getName()3、Field：成员变量对象设置值void set(Object obj, Object value)获取值get(Object obj)忽略访问权限修饰符的安全检查setAccessible(true) ：暴力反射4、Constructor：构造方法对象创建对象T newInstance(Object... initargs)【注意】如果使用空参数构造方法创建对象，操作可以简化：使用Class对象的newInstance方法5、Method：方法对象执行方法Object invoke(Object obj, Object... args)获取方法名String getName()6、示例编写一个类（该类是一个框架），在不改变该类的任何代码的前提下，使用该类创建任意对象，并执行对象的任意方法。public class Person { public void eat() { System.out.println("eat..."); } }public class Student { public void study() { System.out.println("study..."); } }#pro.properties className=com.junlong.reflect.Student methodName=studypublic class Reflect { // 不改变该类的任何代码，就可以创建任意对象，并执行其任意方法 public static void main(String[] args) throws Exception { // 1. 加载配置文件 // 1.1 获取类加载器 ClassLoader classLoader = Reflect.class.getClassLoader(); // 1.2 获取配置文件 InputStream is = classLoader.getResourceAsStream("pro.properties"); // 1.3 创建Properties对象 Properties pro = new Properties(); pro.load(is); String className = pro.getProperty("className"); String methodName = pro…

【Java】JUnit单元测试
type: item
date: 2021-10-06T12:09:46+08:00
description: JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建立，逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个。 JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架（regression testing framework）。Junit测试是程序员测试，即所谓白盒测试，因为程序员知道被测试的软件如何（How）完成功能和完成什么样（What）的功能。Junit是一套框架，继承TestCase类，就可以用Junit进行自动测试了。1、测试分类黑盒测试：不需要写代码，给输入值，看程序是否能够输出期望的值。白盒测试：需要写代码的。关注程序具体的执行流程。2、Junit使用2.1、使用步骤定义一个测试类(测试用例)【建议】 1. 测试类名：被测试的类名Test 1. 包名：xxx.xxx.xx.test定义测试方法：可以独立运行【建议】 1. 方法名：test测试的方法名 1. 返回值：void 1. 参数列表：空参给方法加@Test注解导入junit依赖环境2.2、判定结果红色：失败绿色：成功一般使用断言操作来处理结果： Assert.assertEquals(期望的结果,运算的结果);2.3、补充@Before：修饰的方法会在测试方法之前被自动执行，一般用于资源申请。@After：饰的方法会在测试方法执行之后自动被执行，一般用于资源释放。2.4、示例public class Calculator { public int add(int a, int b) { return a + b; } public int sub(int a, int b) { // int c = 3 / 0; return a - b; } }public class CalculatorTest { @Before public void init() { System.out.println("init..."); } @After public void close() { System.out.println("close..."); } @Test public void testAdd() { Calculator calculator = new Calculator(); int result = calculator.add(1, 2); System.out.println(result); Assert.assertEquals(3, result); } @Test public void testSub() { Calculator calculator = new Calculator(); int result = calculator.sub(3, 5); System.out.println(result); Assert.assertEquals(-2, result); } }感谢小伙伴们的关注！你的点赞、评论、关注、收藏是对博主的最大鼓励！持续更新JavaSE学习笔记！欢迎订阅专栏！

【Java】函数式接口
type: item
date: 2021-10-06T12:08:37+08:00
description: 1、函数式接口1.1、概念有且仅有一个抽象方法的接口。适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda，所以函数式接口就是可 以适用于Lambda使用的接口。从应用层面来讲，Java中的Lambda可以被当做是匿名内部类的“语法糖”，但是二者在原理上是不同的。1.2、格式只要确保接口中有且仅有一个抽象方法即可，接口中抽象方法的 public abstract 可以省略。修饰符 interface 接口名称 { public abstract 返回值类型 方法名称(可选参数信息); // 其他非抽象方法内容 }1.3、@FunctionalInterface注解该注 解可用于一个接口的定义上。一旦使用该注解来定义接口，编译器将会强制检查该接口是否确实有且仅有一个抽象方法，否则将会报错。【注意】即使不使用该注解，只要满足函数式接口的定义，这仍然是一个函数式接口，使用起来都一样。函数式接口一般用作方法的参数或返回值。2、函数式编程在兼顾面向对象特性的基础上，Java语言通过 Lambda表达式 与 方法引用 等，实现函数式编程。2.1、Lambda的延迟执行Lambda表达式延迟执行，提升性能。实际上使用内部类也可以达到同样的效果，只是将代码操作延迟到了另外一个对象当中通过调用方法 来完成。而是否调用其所在方法是在条件判断之后才执行的。2.2、使用Lambda作为参数和返回值Java中的Lambda表达式可以被当作是匿名内部类的替代品。如果方法的参数是一个函数 式接口类型，那么就可以使用Lambda表达式进行替代。使用Lambda表达式作为方法参数，其实就是使用函数式 接口作为方法参数。如果一个方法的返回值类型是一个函数式接口，那么就可以直接返回一个Lambda表达式。3、常用函数式接口主要在java.util.function包中提供。还有Runnbale接口，Conparator接口。3.1、Supplier接口java.util.function.Supplier：生产数据。抽象方法T get()：用来获取一个泛型参数指定类型的对 象数据。求数组元素的最大值public static void main(String[] args) { int[] arr = {3, 7, 45, 12, 90, 6}; int max = getMax(() -> { int maxNum = arr[0]; for (int value : arr) { if (value > maxNum) { maxNum = value; } } return maxNum; }); System.out.println("最大值是：" + max); } public static int getMax(Supplier<Integer> sup) { return sup.get(); }3.2、Consumer接口java.util.function.Consumer：消费一个数据， 其数据类型由泛型决定。抽象方法void accept(T t)：消费一个指定泛型的数据。默认方法adnThen() ：消费数据的时候，首先做一个操作， 然后再做一个操作，实现组合。格式化打印信息下面的字符串数组当中存有多条信息，请按照格式“ 姓名：XX。性别：XX。 ”的格式将信息打印出来。要求将打印姓 名的动作作为第一个 Consumer 接口的Lambda实例，将打印性别的动作作为第二个 Consumer 接口的Lambda实 例，将两个 Consumer 接口按照顺序“拼接”到一起。public static void main(String[] args) { String[] arr = {"张三,男", "李四,男", "王五,男", "小学妹,男"}; printInfo(info -> System.out.print("姓名：" + info.split(",")[0] + "，"), info -> System.out.println("性别：" + info.split(",")[1] + "。"), arr); } private static void printInfo(Consumer<String> one, Consumer<String> two, String[] arr) { for (String s : arr) { one.andThen(two).accept(s); } }3.3、Predicate接口java.util.function.Predicate：对某种类型的数据进行判断，返回boolean值。抽象方法boolean test(T t)：对指定类型数据进行判断的方法，符合条件…

【Java】网络编程
type: item
date: 2021-10-06T12:07:10+08:00
description: 网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包，在接收端按照规定好的协议把包进行解析，从而提取出对应的信息，达到通信的目的。中间最主要的就是数据包的组装，数据包的过滤，数据包的捕获，数据包的分析，最后再做一些处理，代码、开发工具、数据库、服务器架设和网页设计这5部分都要接触。1、软件结构C/S结构 ：全称为Client/Server结构，是指客户端和服务器结构。常见程序有ＱＱ、迅雷等软件。B/S结构 ：全称为Browser/Server结构，是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。网络编程，就是在一定的协议下，实现两台计算机 的通信的程序。2、网络通信协议网络通信协议：：通信协议是对计算机必须遵守的规则，只有遵守这些规则，计算机之间才能进行通信。协议中对数据的传输格式、传输速率、传输步骤等做了 统一规定，通信双方必须同时遵守，最终完成数据交换。TCP/IP协议：传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol)，是 Internet最基本、最广泛的协议。它定义了计算机如何连入因特网，以及数据如何在它们之间传输的标准。它 的内部包含一系列的用于处理数据通信的协议，并采用了4层的分层模型，每一层都呼叫它的下一层所提供的 协议来完成自己的需求。2.1、通信协议分类（传输层）java.net：包中包含的类和接口，提供低层次的通信细节。可以直接使用这 些类和接口，来专注于网络程序开发，而不用考虑通信的细节。TCP：传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接 的通信协议，即传输数据之前， 在发送端和接收端建立逻辑连接，然后再传输数据，它提供了两台计算机之间可靠无差错的数据传输。TCP协议可 以保证传输数据的安全。应用十分广泛，例如下载文件、浏览网页等。三次握手：TCP协议中，在发送数据的准备阶段，客户端与服务器之间的三次交互，以保证连接的可靠。第一次握手，客户端向服务器端发出连接请求，等待服务器确认；第二次握手，服务器端向客户端回送一个响应，通知客户端收到了连接请求；第三次握手，客户端再次向服务器端发送确认信息，确认连接。UDP：用户数据报协议(User Datagram Protocol)。UDP协议是一个面向无连接 的协议。传输数据时，不需 要建立连接，不管对方端服务是否启动，直接将数据、数据源和目的地都封装在数据包中，直接发送。每个 数据包的大小限制在64k以内。它是不可靠协议，因为无连接，所以传输速度快，但是容易丢失数据。日常应用中,例如视频会议、QQ聊天等3、网络通信三要素通信协议：计算机网络通信必须遵守的规则。IP地址：指互联网协议地址（Internet Protocol Address），俗称IP。IP地址用来给一个网络中的计算机设 备做唯一的编号。端口号：用两个字节表示的整数，它的取值范围是0~65535。可以唯一标识设备中的进程（应用程序）。，0~ 1023之间的端口号用于一些知名的网 络服务和应用。利用 协议 + IP地址 + 端口号 三元组合，就可以标识网络中的进程了，那么进程间的通信就可以利用这个标识与其 它进程进行交互。4、TCP通信程序4.1、概述TCP通信能实现两台计算机之间的数据交互，通信的两端，要严格区分为客户端（Client）与服务端（Server）。两端通信时步骤：服务端程序，需要事先启动，等待客户端的连接。客户端主动连接服务器端，连接成功才能通信。服务端不可以主动连接客户端。在Java中，提供了两个类用于实现TCP通信程序：客户端： java.net.Socket 类表示。创建 Socket 对象，向服务端发出连接请求，服务端响应请求，两者建立连接开始通信。服务端： java.net.ServerSocket 类表示。创建 ServerSocket 对象，相当于开启一个服务，并等待客户端的连接。服务端accept() 接收客户端Socket对象，和客户端进行交互。4.2、Socket类java.net.Socket：该类实现客户端套接字，套接字指的是两台设备之间通讯的端点（包含IP和端口号的网络单位）。4.3、构造方法public Socket(String host, int port) ：创建套接字对象并将其连接到指定主机上的指定端口号。如果指 定的host是null ，则相当于指定地址为回送地址。回送地址(127.x.x.x) 是本机回送地址（Loopback Address），主要用于网络软件测试以及本 地机进程间通信，无论什么程序，一旦使用回送地址发送数据，立即返回，不进行任何网络传输。4.4、成员方法public InputSt…

【Java】IO流
type: item
date: 2021-10-06T12:06:00+08:00
description: 流是一种抽象概念，它代表了数据的无结构化传递。按照流的方式进行输入输出，数据被当成无结构的字节序列或字符序列。从流中取得数据的操作称为提取操作，而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO流。换句话说，IO流就是以流的方式进行输入输出。1、IO概述Java中I/O操作指使用 java.io 包下的类或者接口，进行输入、输出操作。输入即读取数据，输出即写 出数据。1.1、IO分类按数据流的方向：输入流 ：把数据从 其他设备 上读取到 内存 中的流。输出流 ：把数据从 内存 中写出到 其他设备 上的流。按数据的类型：字节流 ：以字节为单位，读写数据的流。字符流 ：以字符为单位，读写数据的流。IO的顶级父类 输入流输出流字节流字节输入流：InputStream字节输出流：OutoutStream字符流字符输入流：Reader字符输出流：Writer2、字节流字节流可以传输任意类型的文件数据。流在传递时底层传递的都是二进制数据。2.1、字节输出流OutputStreamjava.io.OutputStream：抽象类，表示字节输出流的所有类的父类，将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。public void close() ：关闭此输出流并释放与此流相关联的任何系统资源。public void flush() ：刷新此输出流并强制任何缓冲的输出字节被写出。public void write(byte[] b) ：将 b.length字节从指定的字节数组写入此输出流。正数（0-127）：查询ASCII码表；负数：两个字节一组，查系统默认码表（gbk）。public void write(byte[] b, int off, int len) ：：从指定的字节数组写入 len字节，从偏移量 off开始输 出到此输出流。public abstract void write(int b) ：将指定的字节输出流。每次可以写出一个字节数据。【注意】虽然参数为int类型四个字节，但是只会保留一个字节的信息写出。当完成流的操作时，必须调用close()方法，释放系统资源。2.2、FileOutputStreamjava.io.FileOutputStream：类，是文件输出流，用于将数据写出到文件。构造方法public FileOutputStream(File file) ：创建文件输出流以写入由指定的 File对象表示的文件。public FileOutputStream(String name) ：创建文件输出流以指定的名称写入文件。【注意】创建一个流对象时，必须传入一个文件路径。该路径下，如果没有这个文件，会创建该文件。如果有这个文 件，会清空这个文件的数据。public FileOutputStream(File file, boolean append) ：创建文件输出流以写入由指定的 File对象表示的 文件。public FileOutputStream(String name, boolean append) ：创建文件输出流以指定的名称写入文件。【注意】这两个构造方法，参数中都需要传入一个boolean类型的值， true 表示追加数据， false 表示清空原有数据。写出换行回车符 \r 和换行符 \n回车符：回到一行的开头（return）。换行符：下一行（newline）。系统中的换行Windows系统里，每行结尾是 回车+换行 ，即 \r\nUnix系统里，每行结尾只有 换行 ，即 \nMac系统里，每行结尾是 回车 ，即 \r 。从 Mac OS X开始与Linux统一。2.3、字节输入流InputStreamjava.io.InputStream：抽象类是表示字节输入流的所有类的超类，可以读取字节信息到内存中。它定义了字节输入 流的基本共性功能方法。public void close() ：关闭此输入流并释放与此流相关联的任何系统资源。public abstract int read() ：从输入流读取数据的下一个字节。每次可以读取一个字节的数据，提升为int类型，读取到文件末尾，返回 -1。public int read(byte[] b) ：从输入流中读取一些字节数，并将它们存储到字节数组 b中 。每次读取b的长度（一般定义为1024的整数倍）个字节到数组中，返回读取到的有效字节个数，读 取到末尾时，返回 -1 。使用数组读取，每次读取多个字节，减少了系统间的IO操作次数，从而提高了读写的效率，建议开发中使 用。【注意】，当完成流的操作时，必须调用close()方法，释放系统资源。2.4、FileInputStreamjava.io.FileInputStrea…