Java基础——二、数据类型

二、数据类型

基本类型

类型说明
类型单位(Byte)取值范围
byte1[128~127]
short2[-32768~32767]
int4[-2147483648~2147483647]
char2[\u0000~\uFFFF]:注意加’ ’
float4[3.402823e+38 ~ 1.401298e-45]:e+38表示是乘10的38次方
double8[1.797693e+308~ 4.9000000e-324]
long8[-9223372036854774808~9223372036854774807]
boolean1boolean 只有两个值:[true、false],可以使用 1 bit 来存储,但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM 支持 boolean 数组,但是是通过读写 byte 数组来实现的。
  • 整型:其中byte、short、int、long都是表示整数的,只不过他们的取值范围不一样
  • float和double:是表示浮点型的数据类型,他们之间的区别在于他们的精确度不同。double型比float型存储范围更大,精度更高,所以通常的浮点型的数据在不声明的情况下都是double型的,如果要表示一个数据是float型的,可以在数据后面加上“F”。浮点型的数据是不能完全精确的,所以有的时候在计算的时候可能会在小数点最后几位出现浮动,这是正常的。
  • char型:用于存放字符的数据类型,占用2个字节,采用unicode编码,它的前128字节编码与ASCII兼容
默认值
Data TypeDefault Value (for fields)
byte0
short0
int0
long0L
float0.0f
double0.0d
char‘\u0000’
String (or any object)null
booleanfalse
类型转换

将一种类型的值赋值给另一种类型是很常见的。在Java中,boolean 类型与其他7中类型的数据都不能进行转换,这一点很明确。

但对于其他7种数据类型,它们之间都可以进行转换,只是可能**(强制转换)会存在精度损失或其他一些变化**。

转换分为自动转换和强制转换:

  • 自动转换(隐式):无需任何操作。
  • 强制转换(显式):需使用转换操作符(type)。

将6种数据类型按下面顺序排列一下

double > float > long > int > short > byte

扩展

  • 原始数据类型
  • Java® 虚拟机规范

包装类型

Primitive type(原始类型)Wrapper class(包装类)
booleanBoolean
byteByte
charCharacter
floatFloat
intInteger
longLong
shortShort
doubleDouble

java中已经有了八种基本数据类型,为什么要使用包装类呢?

当我们需要在 Java 中使用基本数据类型(如 int、double、boolean 等)时,有时候会遇到一些情况,比如:

  1. 集合框架的限制:Java 中的集合类(如 ArrayList、HashMap 等)只能存储对象,无法直接存储基本数据类型,因为集合中存储的是对象的引用。因此,如果想在集合中存储基本数据类型,就需要使用包装类将基本数据类型转换为对象。
  2. 泛型类型参数:在使用泛型时,泛型类型参数只能是类类型,无法使用基本数据类型。所以如果想要在泛型中使用基本数据类型,同样需要使用包装类。
  3. Null 值表示:有时候需要在对象中表示一个“空”或“不存在”的值,在基本数据类型中无法直接表示这种状态。而包装类可以通过 null 来表示这种状态,因为包装类是对象,可以为 null。
  4. 提供更多功能:包装类提供了一些实用的方法来操作基本数据类型,例如将字符串转换为基本数据类型、比较两个基本数据类型的值、将基本数据类型转换为字符串等。

综上所述,使用包装类可以使基本数据类型具备对象的特性,从而更灵活地应用于 Java 的各种场景中。

自动装箱和拆箱

自动装箱和拆箱让开发人员可以编写更清晰的代码,使其更易于阅读。

什么是自动装箱和拆箱?

自动装箱是Java编译器在基本类型与其相应的对象包装类之间的自动转换

例如,将int转换为Integer,将double转换为Double,等等。如果转换以另一种方式进行,则称为拆箱

基本上有适合的包装类型,就可以进行相互转换,使用自动拆箱装箱完成。

Integer x = 2;     // 装箱 调用了 Integer.valueOf(2)
int y = x;         // 拆箱 调用了 X.intValue()

自动装箱和拆箱使开发人员可以编写更简洁的代码,使其更易于阅读

示例1:自动装箱
List<Integer> list = new ArrayList<>();
for (int i = 1; i < 50; i += 2)list.add(i);

为什么尽管此处将int值作为原始类型(而不是Integer对象)添加到list中,但代码仍然可以编译?

  • 由于List是Integer对象的列表,而不是int值的列表。
  • 所以它从i创建一个Integer对象,并将该对象添加到list,因此编译器在运行时将前面的代码转换为以下代码:
List<Integer> list = new ArrayList<>();
for (int i = 1; i < 50; i += 2)list.add(Integer.valueOf(i));

将原始值(例如int) 转换为相应包装类(Integer)的对象称为自动装箱。

总结

当原始值是以下情况时,Java编译器会应用自动装箱:

  • 作为参数传递给需要相应包装类方法的对象方法时。
  • 分配给相应包装类的变量时。
示例二:自动拆箱

将包装类型Integer的对象转换为其相应的原始 int 值称为拆箱。当包装类的对象为以下情况时,Java 编译器将应用拆箱:

  • 作为参数传递给需要相应基元类型值的方法。
  • 分配给相应原始类型的变量。
import java.util.ArrayList;
import java.util.List;public class Unboxing {public static void main(String[] args) {Integer i = new Integer(-8);// 1. Unboxing through method invocationint absVal = absoluteValue(i);System.out.println("absolute value of " + i + " = " + absVal);List<Double> ld = new ArrayList<>();ld.add(3.1416);    // Π is autoboxed through method invocation.// 2. Unboxing through assignmentdouble pi = ld.get(0);System.out.println("pi = " + pi);}public static int absoluteValue(int i) {return (i < 0) ? -i : i;}
}

输出如下:

absolute value of -8 = 8
pi = 3.1416
包装类到底有什么作用?

​ Wrapper 类是包含 原始数据类型int、char、short、byte 等)的类。换句话说,包装类提供了一种将原始数据类型(int、char、short、byte 等)用作对象的方法。这些包装类在 java.util 包下。

​ 自动装箱用于将原始数据类型转换为相应的对象

为什么我们需要包装类?
  • Wrapper 类将原始数据类型转换为对象。如果我们希望修改传递给方法的参数,则对象是必需的(因为原始类型是按值传递的)。
  • java.util 包中的类只处理对象,因此包装类 在这种情况下也有帮助。
  • Collection 框架中的数据 结构(例如ArrayList 和 Vector )仅存储对象(引用类型)而不存储 原始类型。
  • 需要该对象来支持多线程中的同步

扩展

  • 自动装箱和拆箱

String

引入:我们都知道String类型最初就被设置成为不可变的。

在Java中String类型为什么要设置成不可变呢?

在Java中,String对象时不可变的,它们可以在多线程环境中安全地共享,而不需要额外的同步措施。如果String是可变的,那么在多线程环境中对同一字符串的修改可能会导致竞态条件或不一致行为。

竞态条件或不一致行为 = 在多线程环境中,多个线程同时试图修改同一个可变的字符串 竞态条件或不一致行为 = 在多线程环境中,多个线程同时试图修改同一个可变的字符串 竞态条件或不一致行为=在多线程环境中,多个线程同时试图修改同一个可变的字符串

  1. 线程安全性:由于String对象是不可变的,它们可以在多线程环境中安全的共享,而不需要额外的同步措施。如果String是可变的,那么在多线程环境中对同一字符串的修改可能会导致竞态条件或不一致的行为。
  2. 缓存HashCodeString类被广泛用作HashMap的key。由于String是不可变的,它们的哈希码(HashCode)在创建时就可以确定,并且在整个生命周期内保持不变,这样就可以提高HashMap在搜索和插入操作时的性能。
  3. 安全性不可变的字符串可以确保其值不会在不应该改变的情况下被修改这在安全性敏感的场景下是非常重要的,比如在网络通信、加密等方面。
  4. 性能优化:由于字符串是不可变的,可以进行一些优化举措,比如字符串的常量池(String Pool)可以缓存常用的字符串,避免重复创建相同的字符串对象,从而节省内存和和提高性能。
  5. 简化设计:不可变性,简化了字符串的设计和使用,使得代码更加清晰和易于理解。

综上所述:将String设计成不可变的类型有助于提高程序的性能、安全性和可维护性

概览

String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承

在 Java 8 中,String 内部使用 char 数组存储数据

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];
}

在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 coder 来标识使用了哪种编码。

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final byte[] value;/** The identifier of the encoding used to encode the bytes in {@code value}. */private final byte coder;
}

value 数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变

不可变的好处

1. 可以缓存 hash 值

因为 String 的 hash 值经常被使用,例如 :

​ String 用做 HashMapkey。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算

2. String Pool 的需要

如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool

image-20220609215306627

3. 安全性

String 经常作为参数,String 不可变性可以保证参数不可变。例如:

​ 在作为网络连接参数的情况下:

  1. 如果 String 是可变的,那么在网络连接过程中,String 被改变
  2. 改变 String 的那一方以为现在连接的是其它主机,而实际情况却不一定是。

4. 线程安全

String 不可变性天生具备线程安全,可以在多个线程中安全地使用

Program Creek : Why String is immutable in Java?

String,Buffer,Builder

1. 可变性

  • String 不可变
  • StringBuffer 和 StringBuilder 可变

2. 线程安全

  • String 不可变,因此是线程安全的
  • StringBuilder 不是线程安全的
  • StringBuffer 是线程安全的,内部使用 synchronized 进行同步

StackOverflow : String, StringBuffer, and StringBuilder

String Pool

字符串常量池(String Pool)保存着所有字符串字面量(literal strings)

​ 这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程将字符串添加到 String Pool 中。

当一个字符串调用 intern() 方法时:

  1. 如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;
  2. 否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用

下面示例中

  1. s1 和 s2 采用 new String() 的方式新建了两个不同字符串
  2. 而 s3 和 s4 是通过 s1.intern() 和 s2.intern() 方法取得同一个字符串引用。
  3. intern() 首先把 “aaa” 放到 String Pool 中,然后返回这个字符串引用,因此 s3 和 s4 引用的是同一个字符串。
String s1 = new String("aaa");
String s2 = new String("aaa");
System.out.println(s1 == s2);           // false
String s3 = s1.intern();
String s4 = s2.intern();
System.out.println(s3 == s4);           // true

如果是采用 “bbb” 这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。

String s5 = "bbb";
String s6 = "bbb";
System.out.println(s5 == s6);  // true

关于String中的Intern()源码(jdk8)

/**
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.
All literal strings and string-valued constant expressions are interned. String literals are defined in section 3.10.5 of the The Java™ Language Specification.
Returns:
a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.
*/
public native String intern();

扩展

在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。

  • StackOverflow : What is String interning?
  • 深入解析 String#intern
new String(“abc”)

使用这种方式一共会创建两个字符串对象(前提是 String Pool 中还没有 “abc” 字符串对象)。

  • “abc” 属于字符串字面量,因此编译时期会在 String Pool 中创建一个字符串对象,指向这个 “abc” 字符串字面量;
  • 而使用 new 的方式会在堆中创建一个字符串对象

创建一个测试类,其 main 方法中使用这种方式来创建字符串对象。

public class NewStringTest {public static void main(String[] args) {String s = new String("abc");}
}

使用 javap -verbose 进行反编译,得到以下内容:

// ...
Constant pool:
// ...#2 = Class              #18            // java/lang/String#3 = String             #19            // abc
// ...#18 = Utf8               java/lang/String#19 = Utf8               abc
// ...public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=3, locals=2, args_size=10: new           #2                  // class java/lang/String3: dup4: ldc           #3                  // String abc6: invokespecial #4                  // Method java/lang/String."<init>":(Ljava/lang/String;)V9: astore_1
// ...

Constant Pool中:

  • #19 存储这字符串字面量 “abc”
  • #3 是 String Pool 的字符串对象,它指向 #19 这个字符串字面量。
  • 在 main 方法中,0: 行使用 new #2 在堆中创建一个字符串对象,并且使用 ldc #3 将 String Pool 中的字符串对象作为 String 构造函数的参数。

​ 以下是 String 构造函数的源码,可以看到,在将一个字符串对象作为另一个字符串对象的构造函数参数时,并不会完全复制 value 数组内容,而是都会指向同一个 value 数组。

public String(String original) {this.value = original.value;this.hash = original.hash;
}

缓存池

引入

想象以下,你有一个池子,里面装满了水。当你需要水时,你不必每次都去打开水龙头,而是直接从池子里面取水,这样不就可以节省时间和资源吗?

在编程中,缓存池通常用于存储一些频繁使用的对象,例如数据库连接、线程、图片资源等。当程序需要使用这些对象时,它可以从缓存池中获取,而不是每次都创建一个新的对象。这样可以避免频繁的创建和销毁对象,提高了程序的性能和相应速度。

什么是缓存池?

缓存池是一个用于存储和重复利用对象的容器,通常用于减少对象的创建和销毁次数,从而提高系统的性能和效率。

new Integer(123)Integer.valueOf(123) 的区别在于?

  • new Integer(123) 每次都会新建一个对象
  • Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用
//每次新建对象
Integer x = new Integer(123);
Integer y = new Integer(123);
System.out.println(x == y);    // false//取得同一个对象的引用
Integer z = Integer.valueOf(123);
Integer k = Integer.valueOf(123);
System.out.println(z == k);   // true

valueOf() 方法的实现比较简单

  1. 就是先判断值是否在缓存池中
  2. 如果在的话就直接返回缓存池的内容
  3. 如果不在就直接创建新的对象

论证如果不在线程池范围,就创建新的对象

Integer x = Integer.valueOf("123");
Integer y = Integer.valueOf("123");
//true:论证了观点是从缓存池中的同一个引用
System.out.println(x == y);//127是int类型的边界值,用128来测试
Integer x1 = Integer.valueOf("128");
Integer y1 = Integer.valueOf("128");
//false:说明了是超过缓存池的保存范围就重新创建对象
System.out.println(x1 == y1);

源码:论证如果在的话,就直接返回缓存池的内容。

public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}

在 Java 8 中,Integer 缓存池的大小默认为 -128~127。

static final int low = -128;
static final int high;
static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;
}

编译器会在自动装箱过程调用 valueOf() 方法,因此多个值相同且值在缓存池范围内的 Integer 实例使用自动装箱来创建,那么就会引用相同的对象

Integer m = 123;
Integer n = 123;
System.out.println(m == n); // true

基本类型对应的缓冲池如下:

  • boolean values true and false
  • all byte values
  • short values between -128 and 127
  • int values between -128 and 127
  • char in the range \u0000 to \u007F

在使用这些基本类型对应的包装类型时,如果该数值范围在缓冲池范围内,就可以直接使用缓冲池中的对象。

​ 在 jdk 1.8 所有的数值类缓冲池中,Integer 的缓冲池 IntegerCache 很特殊,这个缓冲池的下界是 - 128,上界默认是 127。

​ 但是这个上界是可调的,在启动 jvm的时候,通过 -XX:AutoBoxCacheMax=<size>指定这个缓冲池的大小,该选项在 JVM 初始化的时候会设定一个名为 java.lang.IntegerCache.high 系统属性,然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界

StackOverflow : Differences between new Integer(123), Integer.valueOf(123) and just 123

你觉得设计缓存池最需要考虑的是什么?

缓存池的设计主要需要考虑到哪几个方面?

  1. 对象的生命周期管理:需要确保缓存中的对象在不再需要时能够被正确释放,以免造成内存泄露和资源浪费。
  2. 线程安全性:如果多个线程同时访问缓存池,需要考虑如何保证对象的安全获取和释放,以避免竞态条件和数据不一致性。
  3. 缓存淘汰策略:当缓存池达到一定大小限制时,需要考虑如何决定哪些对象应该被淘汰除去,以便为了新的对象腾出空间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/298686.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

macbook(m1) ubuntu下载,复制粘贴和国内镜像源配置

ubuntu下载使用 官网下载Ubuntu 22.04.4 LTS (Jammy Jellyfish) Daily Build 打开后根据电脑的架构选择安装包&#xff0c;想要下载其他版本也可在官网中自行搜索。 我安装时舍友说他安装的是22.04这个版本&#xff0c;我也就跟着他安装了 注意&#xff1a;下载的版本最好有…

详解 Redis 在 Ubuntu 系统上的安装

在 Ubuntu 20.04 安装 Redis 1. 先切换到 root 用户 在 Ubuntu 20.04 中&#xff0c;可以通过以下步骤切换到 root 用户&#xff1a; 输入以下命令&#xff0c;以 root 用户身份登录&#xff1a; sudo su -按回车键&#xff0c;并输入当前用户的密码&#xff08;即具有 sudo…

Python爬虫-懂车帝新能源汽车近一年销量榜

前言 本文是该专栏的第24篇,后面会持续分享python爬虫干货知识,记得关注。 笔者在本专栏之前,有详细介绍以“懂车帝平台的新能源汽车销量榜单”为例,获取各车型的销量排行榜单数据。而本文,笔者将单独详细来介绍如何获取“近一年的新能源汽车销量榜单”数据。 具体实现思…

Python如何解决“滑动拼图”验证码(8)

前言 本文是该专栏的第67篇,后面会持续分享python爬虫干货知识,记得关注。 做过爬虫项目的同学,或多或少都会接触到一些需要解决验证码才能正常获取数据的平台。 在本专栏之前的文章中,笔者有详细介绍通过python来解决多种“验证码”(点选验证,图文验证,滑块验证,滑块…

【c++】类和对象(七)

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章来到类和对象的最后一部分 目录 1.static成员1.1特性 2.友元2.1引入&#xff1a;<<和>>的重载2.2友元函数2.3友元类 3.内部类4.匿名对象5.拷…

flink源码编译-job提交

1、启动standalone集群的taskmanager standalone集群中的taskmanager启动类为 TaskManagerRunner 2 打开master启动类 通过 ctrln快捷键&#xff0c;找到、并打开类&#xff1a; org.apache.flink.runtime.taskexecutor.TaskManagerRunner 3 修改运⾏配置 基本完全按照mas…

【网站项目】三省学堂-学习辅助系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

C#实现Word文档转Markdown格式(Doc、Docx、RTF、XML、WPS等)

文档格式的多样性丰富了我们的信息交流手段&#xff0c;其中Word文档因其强大的功能性而广受欢迎。然而&#xff0c;在网络分享、版本控制、代码阅读及编写等方面&#xff0c;Markdown因其简洁、易于阅读和编辑的特性而展现出独特的优势。将Word文档转换为Markdown格式&#xf…

SpringMVC --- 老杜

1、什么是SpringMVC&#xff1f; SpringMVC是一个基于Java实现了MVC设计模式的请求驱动类型的轻量级Web框架&#xff0c;通过把Model&#xff0c;View&#xff0c;Controller分离&#xff0c;将web层进行职责解耦&#xff0c;把复杂的web应用分成逻辑清晰的及部分&#xff0c;…

Aurora8b10b(1)IP核介绍并基于IP核进行设计

文章目录 前言一、IP核设置二、基于IP核进行设计2.1、设计框图2.2、aurora_8b10b_0模块2.3、aurora_8b10b_0_CLOCK_MODULE2.4、aurora_8b10b_0_SUPPORT_RESET_LOGIC2.5、aurora8b10b_channel模块2.6、IBUFDS_GTE2模块2.7、aurora_8b10b_0_gt_common_wrapper模块2.8、aurora8b10…

Meta Pixel:助你实现高效地Facebook广告追踪

Meta Pixel 像素代码是用來衡量Facebook广告效果的一个官方数据工具&#xff0c;只要商家有在Facebook上投放广告就需要串联Meta Pixel 像素代码来查看相关数据。 它本质上是一段 JavaScript 代码&#xff0c;安装后可以让用户在自己网站上查看到访客活动。它的工作原理是加载…

Leetcode 64. 最小路径和

心路历程&#xff1a; 第一反应像是一个回溯问题&#xff0c;但是看到题目中要求最值&#xff0c;大概率是一道DP问题。并且这里面的递推关系也很明显。 这里面边界条件可以有多种处理方法。 解法&#xff1a;动态规划 class Solution:def minPathSum(self, grid: List[List…

axios 封装 http 请求详解

前言 Axios 是一个基于 Promise 的 HTTP 库&#xff0c;它的概念及使用方法本文不过多赘述&#xff0c;请参考&#xff1a;axios传送门 本文重点讲述下在项目中是如何利用 axios 封装 http 请求。 一、预设全局变量 在 /const/preset.js 中配置预先设置一些全局变量 window.…

【蓝桥杯嵌入式】13届程序题刷题记录及反思

一、题目分析 考察内容&#xff1a; led按键&#xff08;短按&#xff09;PWM输出&#xff08;PA1&#xff09;串口接收lcd显示 根据PWM输出占空比调节&#xff0c;高频与低频切换 串口接收&#xff08;指令解析&#xff09;【中断接收】 2个显示界面 led灯闪烁定时器 二…

Web大并发集群部署之集群介绍

一、传统web访问模型 传统web访问模型完成一次请求的步骤 1&#xff09;用户发起请求 2&#xff09;服务器接受请求 3&#xff09;服务器处理请求&#xff08;压力最大&#xff09; 4&#xff09;服务器响应请求 传统模型缺点 单点故障&#xff1b; 单台服务器资源有限&…

如何将普通应用更改为 OTA APP

1. 引言 客户在基于 BlueNRG-LP 设计产品时&#xff0c;code base 用的是 SDK 中某些不带 OTA 升级功能的参考示例&#xff0c;当客户完成其基本设计功能后&#xff0c;想要添加 OTA 的软件升级功能。在这个过程中往往会碰到一些问题。基于上述考虑&#xff0c;本文尝试阐述在…

《Java面试自救指南》(专题二)计算机网络

文章目录 力推的计网神课get请求和post请求的区别在浏览器网址输入一个url后直到浏览器显示页面的过程常用状态码session 和 cookie的区别TCP的三次握手和四次挥手七层OSI模型&#xff08;TCP/IP协议模型&#xff09;各种io模型的知识http协议和tcp协议的区别https和http的区别…

SpringBoot配置文件加载的优先级顺序

SpringBoot配置文件加载的优先级顺序 1.按文件类型2.按路径比较3.按命令行参数设置 1.按文件类型 SpringBoot的配置文件可以分为.properties .yml .yaml 在同一路径下&#xff08;比如都在classpath下&#xff09;三者的优先级顺序是.properties> .yml> .yaml 2.按路径…

【Vscode】无法将“python,pip,node,npm等”识别为cmdlet...问题

问题出现场景 新换个电脑&#xff0c;然后重新安装了软件&#xff0c;又复现一次又一次“老生常谈”的问题。 解决方法 网络答案吧五花八门&#xff0c;我采取一个我的场景解决可行的方案&#xff0c; 首先我的场景是&#xff0c;环境变量&#xff0c;配置路径都是没有问题…

idea开发 java web 配电室后台管理系统bootstrap框架web结构java编程计算机网页

一、源码特点 java 配电室后台管理系统是一套完善的完整信息系统&#xff0c;结合java web开发和bootstrap UI框架完成本系统 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主 要采用B/S模式开发。 前段主要技术 cs…