java入门笔记基础语法篇(4)
变量
int days;
double salary;
long earthPopulation;
boolean done;
- 在Java中,每个声明以分号结束。
- 变量名必须是一个以字母开头并由字母或数字构成的序列。
- 需要注意,与大多数程序设计语言相比,Java中“字母”和“数字”的范围更大。
- 字母包括'A'~'Z'、'a'~'z'、'_'、'$'或在某种语言中表示字母的任何Unicode字符。
- 如果想要知道哪些Unicode字符属于Java中的“字母”,可以使用Character类的isJavaIdentifierStart和isJavaIdentifierPart方法来检查。
- 尽管$是一个合法的Java字符,但不要在你自己的代码中使用这个字符。 它只用在Java编译器或其他工具生成的名字中。
- 另外,不能使用Java保留字作为变量名。
初始化变量
声明一个变量之后,必须使用赋值语句对变量进行初始化,我们最好不要用未初始化的变量。否则java编译器会认为是未定义行为。
public class UninitializedVariableError {public static void main(String[] args) {int num;// 下面这行会报错,因为num未初始化System.out.println(num); }
}
在 IntelliJ IDEA 中,当你编写这段代码时,IDE 会在代码编辑区域直接给出提示。鼠标悬停在有问题的代码行上,会弹出提示框,显示类似 “Variable 'num' might not have been initialized” 的信息,同时在代码行号旁边会有红色波浪线标记。在编译运行时,运行窗口会显示编译错误信息,通常也会提示变量
num
未初始化。
下面我们来看一段正确的示例,在代码中我已经给出了所有类型初始化的示例:
public class VariableInitialization {public static void main(String[] args) {// 初始化byte类型变量byte byteVar = 120;System.out.println("byte类型变量的值: " + byteVar);// 初始化short类型变量short shortVar = 3000;System.out.println("short类型变量的值: " + shortVar);// 初始化int类型变量int intVar = 2024;System.out.println("int类型变量的值: " + intVar);// 初始化long类型变量,需要在数字后面加L或llong longVar = 10000000000L;System.out.println("long类型变量的值: " + longVar);// 初始化float类型变量,需要在数字后面加F或ffloat floatVar = 3.14f;System.out.println("float类型变量的值: " + floatVar);// 初始化double类型变量double doubleVar = 3.1415926;System.out.println("double类型变量的值: " + doubleVar);// 初始化char类型变量char charVar = 'A';System.out.println("char类型变量的值: " + charVar);// 初始化boolean类型变量boolean booleanVar = true;System.out.println("boolean类型变量的值: " + booleanVar);}
}
- 在java中,我们对一个已经声明过的变量进行赋值,就需要将变量名放在等号(=)左侧,相应取值的java表达式放在等号的右侧。我们可以将声明放在代码中的任何地方。
- 但在Java中,变量的声明尽可能地靠近变量第一次使用的地方,这是一种良好的程序编写风格。
常量
public class BasicConstantExample {public static void main(String[] args) {// 使用 final 关键字声明一个 int 类型的常量final int DAYS_IN_WEEK = 7;// 下面这行代码会编译错误,因为常量的值不能被修改// DAYS_IN_WEEK = 8; System.out.println("一周的天数是: " + DAYS_IN_WEEK);// 声明一个 double 类型的常量final double PI = 3.14159;System.out.println("圆周率的值是: " + PI);}
}
在上述代码中,DAYS_IN_WEEK
和 PI
被 final
修饰,分别代表一周的天数和圆周率。当尝试修改这些常量的值时,编译器会报错,从而保证了常量值的不可变性。
- 在java中,关键字final表示这个变量只能被赋值一次,一旦被赋值之后,就不能够再更改了。习惯上,常量名使用全大写。
- 在Java中,经常希望某个常量可以在一个类中的多个方法中使用,通常将这些常量 称为类常量。可以使用关键字static final设置一个类常量。
一个简单的数学常量示例:
public class MathConstants {// 定义圆周率常量,使用 public static final 修饰public static final double PI = 3.1415926;// 定义自然对数的底数常量public static final double E = 2.71828;public static void main(String[] args) {// 可以直接通过类名访问类常量System.out.println("圆周率的值是: " + MathConstants.PI);System.out.println("自然对数的底数的值是: " + MathConstants.E);// 计算半径为 5 的圆的面积double radius = 5;double area = MathConstants.PI * radius * radius;System.out.println("半径为 " + radius + " 的圆的面积是: " + area);}
}
运算符
- 在Java中,使用算术运算符+、-、*、/表示加、减、乘、除运算。
- 当参与/运算的 两个操作数都是整数时,表示整数除法;否则,表示浮点除法。
- 整数的求余操作 (有时称为取模)用%表示。
- 例如,15/2等于7,15%2等于1,15.0/2等于7.5。
- 需要注意,整数被0除将会产生一个异常,而浮点数被0除将会得到无穷大或NaN结果。
算术运算符
用于执行基本的数学运算,包括加、减、乘、除、取模、自增和自减。
运算符 | 描述 | 示例 |
+ | 加法,用于两个数相加 | int a = 5 + 3; // a 的值为 8 |
- | 减法,用于两个数相减 | int b = 7 - 2; // b 的值为 5 |
* | 乘法,用于两个数相乘 | int c = 4 * 6; // c 的值为 24 |
/ | 除法,用于两个数相除。如果是整数相除,结果会舍去小数部分 |
|
% | 取模(求余数),用于求两个数相除的余数 | int e = 10 % 3; // e 的值为 1 |
++ | 自增运算符,分为前置自增(++i )和后置自增(i++ )。前置自增先将变量的值加 1,再使用变量;后置自增先使用变量,再将变量的值加1 | int i = 5; int j = ++i; // i 为 6,j 为 6 int m = 5; int n = m++; // m 为 6,n 为 5 |
-- | 自减运算符,分为前置自减(--i )和后置自减(i-- )。原理与自增运算符类似 | int x = 5; int y = --x; // x 为 4,y 为 4 int p = 5; int q = p--; // p 为 4,q 为 5 |
代码示例:
//算术运算符
public class ArithmeticOperatorExample {public static void main(String[] args) {int a = 10;int b = 3;System.out.println("a + b = " + (a + b));System.out.println("a - b = " + (a - b));System.out.println("a * b = " + (a * b));System.out.println("a / b = " + (a / b));System.out.println("a % b = " + (a % b));int c = a++;System.out.println("a++ 后,a 的值是:" + a + ",c 的值是:" + c);c = ++a;System.out.println("++a 后,a 的值是:" + a + ",c 的值是:" + c);}
}
注:当然,程序员都知道加1、减1是数值变量最常见的操作。在Java中,借鉴了C和C++的做法,也提供了自增、自减运算符:n++将变量n的当前值加1,n--则将n的值减1。
赋值运算符
用于将一个值赋给变量,还可以结合算术运算符进行复合赋值。
运算符 | 描述 | 示例 |
= | 基本赋值运算符,将右边的值赋给左边的变量 | int x = 10; |
+= | 加等于,先将变量与右边的值相加,再将结果赋给变量 | int a = 5; a += 3; // 相当于 a = a + 3,a 的值 |
-= | 减等于,先将变量与右边的值相减,再将结果赋给变量 | int b = 7; b -= 2; // 相当于 b = b - 2,b 的值为 5 |
*= | 乘等于,先将变量与右边的值相乘,再将结果赋给变量 | int c = 4; c *= 6; // 相当于 c = c * 6,c 的值为 24 |
/= | 除等于,先将变量与右边的值相除,再将结果赋给变量 | int d = 10; d /= 2; // 相当于 d = d / 2,d 的值为 5 |
%= | 取模等于,先将变量与右边的值取模,再将结果赋给变量 | int e = 10; e %= 3; // 等价于 e = e % 3,e 的值变为 1 |
代码示例:
// 赋值运算符int num3 = 5;num3 += 2;System.out.println("使用 += 后 num3 的值: " + num3);num3 -= 1;System.out.println("使用 -= 后 num3 的值: " + num3);num3 *= 3;System.out.println("使用 *= 后 num3 的值: " + num3);num3 /= 2;System.out.println("使用 /= 后 num3 的值: " + num3);num3 %= 3;System.out.println("使用 %= 后 num3 的值: " + num3);
- 可以在赋值中使用二元运算符,这是一种很方便的简写形式。例如:
- x +=4; 等价与x = x+4;
- (一般的,我们把运算符放在 = 号的左边,如 *=或%= )。
比较运算符
比较运算符用于比较两个值的大小关系,结果为布尔类型(true
或 false
),以下是详细介绍及示例:
运算符 | 描述 | 示例 |
== | 等于,判断两个值是否相等 | int x = 5; int y = 5; boolean isEqual = (x == y); // 结果为 t |
!= | 不等于,判断两个值是否不相等 | int m = 3; int n = 4; boolean isNotEqual = (m != n); // 结果为 true |
> | 大于,判断左边的值是否大于右边的值 | int a = 7; int b = 5; boolean isGreater = (a > b); // 结果为 true |
< | 小于,判断左边的值是否小于右边的值 | int c = 2; int d = 4; boolean isLess = (c < d); // 结果为 true |
>= | 大于等于,判断左边的值是否大于或等于右边的值 | int e = 5; int f = 5; boolean isGreaterOrEqual = (e >= f); // 结果为 true |
<= | 小于等于,判断左边的值是否小于或等于右边的值 | int g = 3; int h = 4; boolean isLessOrEqual = (g <= h); // 结果为 true |
代码示例:
// 比较运算符boolean isEqual = num1 == num2;System.out.println("num1 是否等于 num2: " + isEqual);boolean isNotEqual = num1 != num2;System.out.println("num1 是否不等于 num2: " + isNotEqual);boolean isGreater = num1 > num2;System.out.println("num1 是否大于 num2: " + isGreater);boolean isLess = num1 < num2;System.out.println("num1 是否小于 num2: " + isLess);boolean isGreaterOrEqual = num1 >= num2;System.out.println("num1 是否大于等于 num2: " + isGreaterOrEqual);boolean isLessOrEqual = num1 <= num2;System.out.println("num1 是否小于等于 num2: " + isLessOrEqual);
逻辑运算符
逻辑运算符用于对布尔值进行逻辑操作,以下是常见的逻辑运算符及示例:
运算符 | 描述 | 示例 |
&& | 逻辑与,只有当两个操作数都为 true 时,结果才为 true | boolean a = true; boolean b = false; boolean result = a && b; // 结果为 false |
|| | 逻辑或,只要两个操作数中有一个为 true ,结果就为 true | boolean m = true; boolean n = false; boolean res = m||n; // 结果为 true` |
! | 逻辑非,对操作数的布尔值取反 | boolean p = true; boolean q =!p; // 结果为 false |
代码示例:
// 逻辑运算符boolean bool1 = true;boolean bool2 = false;boolean logicalAnd = bool1 && bool2;System.out.println("逻辑与结果: " + logicalAnd);boolean logicalOr = bool1 || bool2;System.out.println("逻辑或结果: " + logicalOr);boolean logicalNot =!bool1;System.out.println("逻辑非结果: " + logicalNot);
- Java沿用了C++的做法,使用&&表示逻辑“与”运算符,使用||表示逻辑“或”运算符。从!=运算符可以想到,感叹号!就是逻辑非运算符。
- &&和||运算符是按照“短路”方式来求值的:如果第一个操作数已经能够确定表达式的值,第二个操作数就不必计算了。
- 用&&运算符合并两个表达式,计算得到第一个表达式的真值为false,结果就不可能为true。
- 因此,第二个表达式就不必计算了。可以利用这一点来避免错误。
位运算符
位运算符用于对整数类型的二进制位进行操作,以下是常见的位运算符及示例:
运算符 | 描述 | 示例 |
& | 按位与,对两个操作数的对应二进制位进行与操作,只有当对应位都为 1 时,结果位才为 1 | int x = 5; // 二进制 0101 int y = 3; // 二进制 0011 int result = x & y; // 结果为 1,二进制 0001 |
| | 按位或,只要两个操作数中有一个为 true ,结果就为 true | `int a = 5; // 二进制 0101 int b = 3; // 二进制 0011 int orResult = a|b; // 结果为 7,二进制 0111` |
<< | 左移运算符,将操作数的二进制位向左移动指定的位数,右边空出的位用 0 填充。左移 n 位相当于将操作数乘以 2 的 n 次方 | int num = 5; int result = num << 2; |
>> | 有符号右移运算符,将操作数的二进制位向右移动指定的位数,左边空出的位用原符号位填充(正数补 0,负数补 1)。有符号右移 n 位相当于将操作数除以 2 的 n 次方并向下取整 | int positive = 20; int posResult = positive >> 2; int negative = -20; int negResult = negative >> 2; |
>>> | 无符号右移运算符,将操作数的二进制位向右移动指定的位数,左边空出的位始终用 0 填充,不考虑符号位 | int negative = -20; int result = negative >>> 2; // -20 的二进制(补码)1111 1111 1111 1111 1111 1111 1110 1100 无符号右移 2 位后 0011 1111 1111 1111 1111 1111 1111 1011,结果为 1073741819 |
^ | 按位异或,对两个操作数的对应二进制位进行异或操作,当两个对应位不同时结果位为 1,相同时结果位为 0 | int m = 5; // 二进制 0101 int n = 3; // 二进制 0011 int xorResult = m ^ n; // 结果为 6,二进制 0110 |
代码示例:
// 5. 位运算符int bitNum1 = 5; // 二进制: 0101int bitNum2 = 3; // 二进制: 0011int bitwiseAnd = bitNum1 & bitNum2;System.out.println("按位与结果: " + bitwiseAnd);int bitwiseOr = bitNum1 | bitNum2;System.out.println("按位或结果: " + bitwiseOr);int bitwiseXor = bitNum1 ^ bitNum2;System.out.println("按位异或结果: " + bitwiseXor);int bitwiseNot = ~bitNum1;System.out.println("按位取反结果: " + bitwiseNot);int leftShift = bitNum1 << 2;System.out.println("左移 2 位结果: " + leftShift);int rightShift = bitNum1 >> 1;System.out.println("右移 1 位结果: " + rightShift);int unsignedRightShift = bitNum1 >>> 1;System.out.println("无符号右移 1 位结果: " + unsignedRightShift);
三目运算符
布尔表达式 ? 表达式1 : 表达式2;
//在此表达式中,会返回x和y中较小的一个。
x<y?x:y
运算符优先级
运算符 | 结合性 |
[] . () (方法调用) | 从左向右 |
! ~ ++ -- + (一元运算) - (一元运算) () (强制类型转换)new | 从右向左 |
* / % | 从左向右 |
+ - | 从左向右 |
<< >> >>> | 从左向右 |
< <= > >= instanceof | 从左向右 |
== != | 从左向右 |
& | 从左向右 |
^ | 从左向右 |
&& | 从左向右 |
| | 从左向右 |
? : | 从右向左 |
= += -= *= /= %= &= = ^= <<= >>= >>>= | 从右向左 |
枚举类型
枚举类型是一种强类型,编译器会确保使用的是预先定义好的枚举常量,避免了错误的字符串或其他非法值的使用。
enum
关键字来定义枚举类型,例如: enum Season {SPRING, SUMMER, AUTUMN, WINTER
}
上述代码定义了一个名为Season
的枚举类型,包含了SPRING
(春天)、SUMMER
(夏天)、AUTUMN
(秋天)、WINTER
(冬天)四个枚举常量。
字符串
public class StringExample {public static void main(String[] args) {// 定义一个普通字符串String normalString = "Hello, World!";System.out.println("普通字符串: " + normalString);// 定义一个包含Unicode字符的字符串String unicodeString = "Java\u2122";System.out.println("包含Unicode字符的字符串: " + unicodeString);// 字符串是String类的实例,可以调用String类的方法int length = normalString.length();System.out.println("普通字符串的长度: " + length);boolean isEqual = normalString.equals("Hello, World!");System.out.println("普通字符串与指定内容是否相等: " + isEqual);}
}
在上述代码中:
- 定义了一个普通字符串
normalString
,它是String
类的一个实例。通过System.out.println
输出该字符串。- 定义了包含 Unicode 字符(
\u2122
代表商标符号™)的字符串unicodeString
,同样输出该字符串。- 利用
String
类的length
方法获取normalString
的长度,并输出。- 使用
String
类的equals
方法比较normalString
与指定字符串内容是否相等,并输出结果。
子串
- String类的substring方法可以从一个较大的字符串提取出一个子串。
- 在 Java 中,
String
类的substring
方法用于从一个较大的字符串中提取子串,它有两种重载形式,下面分别举例说明:
1. substring(int beginIndex)
该方法用于从指定的索引位置 beginIndex
开始截取字符串,一直到原字符串的末尾。
public class SubstringExample1 {public static void main(String[] args) {String originalString = "Hello, World!";// 从索引 7 开始截取字符串String subString = originalString.substring(7);System.out.println("原字符串: " + originalString);System.out.println("截取后的子串: " + subString);}
}
代码解释:
originalString
是原始的字符串"Hello, World!"
。originalString.substring(7)
表示从索引为 7 的字符(索引从 0 开始计数)开始截取,即字符W
,一直到字符串末尾,所以截取后的子串是"World!"
。
2. substring(int beginIndex, int endIndex)
该方法用于从指定的起始索引 beginIndex
开始截取字符串,直到指定的结束索引 endIndex
之前的位置(不包括 endIndex
位置的字符)。
public class SubstringExample2 {public static void main(String[] args) {String originalString = "Java Programming";// 从索引 0 开始,到索引 4 之前结束(不包括索引 4 的字符)String subString = originalString.substring(0, 4);System.out.println("原字符串: " + originalString);System.out.println("截取后的子串: " + subString);}
}
代码解释:
originalString
是原始的字符串"Java Programming"
。originalString.substring(0, 4)
表示从索引为 0 的字符(即字符J
)开始截取,到索引为 4 的字符(即字符P
)之前结束,所以截取后的子串是"Java"
。
注:
- 索引值必须在有效范围内,即
0
到字符串长度 - 1
之间,否则会抛出StringIndexOutofBoundsException异常。- 当
beginIndex
等于endIndex
时,截取的子串为空字符串。 substring的工作方式有一个优点:容易计算子串的长度。 字符串 s.substring(a,b)的长度为b-a。
拼接
- 与绝大多数的程序设计语言一样,Java语言允许使用+号连接(拼接)两个字符串。
- 这是最直观、最简单的字符串拼接方式,适用于少量字符串的拼接。
public class StringConcatenationExample {public static void main(String[] args) {String str1 = "Hello";String str2 = "World";String result = str1 + " " + str2;System.out.println(result);}
}
代码解释:
+
是 Java 中的字符串拼接运算符。当+
用于连接两个字符串时,会将它们连接成一个新的字符串。- 这里先将
str1
的值"Hello"
与空格字符串" "
拼接,得到"Hello "
,然后再将这个结果与str2
的值"World"
拼接,最终得到"Hello World"
。result
是一个新的字符串变量,用于存储拼接后的结果。
原理:
在编译时,Java 编译器会将使用+
运算符拼接字符串的代码转化为StringBuilder
类的操作。对于简单的拼接,这种方式很方便,但如果在循环中使用,会导致性能问题,因为每次拼接都会创建新的StringBuilder
对象。
不可变字符串
- String类没有提供用于修改字符串的方法。在 Java 中,
String
类代表不可变字符串,即字符串一旦创建,其内容就不能被改变。- 由于不能修改Java字符串中的字符,所以在Java文档中将String类对象称为不可变字符串。
- 不可变字符串有一个优点:编译器可以让字符串共享。
- 具体的工作方式,可以想象将各种字符串存放在公共的存储池中。字符串变量指向存储池中相应的位置。如果复制一个字符串变量,原始字符串与复制的字符串共享相同的字符。
字符串常量池:Java 为了提高性能和减少内存开销,维护了一个字符串常量池。当创建字符串常量时,如
String s = "abc";
,JVM 首先会在字符串常量池中查找是否存在"abc"
这个字符串。如果存在,直接返回常量池中该字符串的引用;如果不存在,则在常量池中创建该字符串,然后返回引用。这使得相同内容的字符串常量在内存中只有一份实例,进一步体现了String
的不可变性。
代码示例:
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {private final char value[];
}
String
类内部使用一个private final char[]
数组来存储字符串内容,final
关键字确保了该数组一旦初始化,就不能再指向其他数组,从底层实现上保证了字符串的不可变性。- 由于
value
数组是private
的,外部代码无法直接访问和修改该数组,同时final
修饰符保证了数组引用的不可更改性。
总而言之,Java的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率。查看一下程序会发现:很少需要修改字符串,而是往往需要对字符串进行比较。有一种例外情况,将来自于文件或键盘的单个字符或较短的字符串汇集成字符串。为此,Java提供了一个独立的类,这在之后会介绍。
检测字符串是否相等
1. 使用 equals
方法
equals
方法用于比较两个字符串的内容是否相等。它是String
类重写自Object
类的方法,用于专门比较字符串的实际字符序列。
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");boolean isEqual1 = str1.equals(str2);
boolean isEqual2 = str1.equals(str3); System.out.println(isEqual1);
System.out.println(isEqual2);
在上述代码中,
str1
和str2
都指向字符串常量池中的同一个"Hello"
字符串,str3
通过new
关键字创建了一个新的String
对象,但内容同样是"Hello"
。equals
方法比较的是字符串的内容,所以isEqual1
和isEqual2
都为true
。
2. 使用 equalsIgnoreCase
方法
equalsIgnoreCase
方法与equals
方法类似,也是用于比较字符串内容,但它忽略大小写。
注:请注意!请一定不要用`==`检测字符串是否相等,它只判断内存地址是否相同,即便内容一样,不同位置的字符串拷贝也会使判断出错。
只有字符串常量在虚拟机中是共享的,
+
或substring
等操作生成的字符串不共享。所以千万不要使用==
判断字符串相等,否则极易出现类似随机间歇性错误的严重 bug。
public class StringEqualityIgnoreCase {public static void main(String[] args) {String str1 = "Hello";String str2 = "hello";// 比较 str1 和 str2,忽略大小写boolean result = str1.equalsIgnoreCase(str2);System.out.println("str1.equalsIgnoreCase(str2) 的结果: " + result); }
}
代码解释:在比较
str1
和str2
时,equalsIgnoreCase
方法不考虑字母的大小写,因此即使str1
中的H
是大写,str2
中的h
是小写,该方法仍会返回true
空串与Null串
在 Java 中,空串(Empty String)和 Null
串是两个不同的概念。
空串
空串是长度为 0 的字符串,它是 String
类的一个有效实例,在内存中是实际存在的对象,只不过该对象不包含任何字符。可以通过两种方式创建空串:
// 方式一:直接使用双引号赋值
String emptyStr1 = "";
// 方式二:使用 String 类的构造函数
String emptyStr2 = new String();
判断方式
判断一个字符串是否为空串,通常可以使用 length()
方法或者 isEmpty()
方法:
String str = "";
// 使用 length() 方法判断
if (str.length() == 0) {System.out.println("字符串为空串");
}
// 使用 isEmpty() 方法判断
if (str.isEmpty()) {System.out.println("字符串为空串");
}
使用场景
- 初始化变量:在某些情况下,需要将字符串变量初始化为空串,以便后续根据业务逻辑进行赋值操作。
String result = "";
// 根据条件进行赋值
if (condition) {result = "Some value";
}
- 作为方法返回值:当方法没有合适的字符串结果需要返回时,可以返回空串。
public String getResult() {// 某些条件下没有结果return "";
}
Null 串
Null
串表示一个字符串变量没有引用任何对象,即该变量不指向任何有效的 String
实例。null
是 String变量中存放的一个特殊值,它表示目前没有任何对象与该变量关联。
String nullStr = null;
判断方式
判断一个字符串是否为 null
,需要使用 ==
运算符:
String str = null;
if (str == null) {System.out.println("字符串为 null");
}
需要注意的是,在使用 null
字符串调用方法时会抛出 NullPointerException
异常,例如:
String nullStr = null;
// 下面这行代码会抛出 NullPointerException 异常
// System.out.println(nullStr.length());
使用场景
- 表示对象未初始化:当一个字符串变量在声明时还不确定具体的值,或者在某些条件下没有合适的字符串对象可以引用时,可以将其初始化为
null
。
String userInput;
// 假设在某个方法中获取用户输入
userInput = getUserInput();
if (userInput == null) {System.out.println("未获取到用户输入");
}
- 方法参数传递:在方法调用时,如果某个字符串参数没有合适的值可以传递,可以传递
null
表示该参数未提供。
public void processString(String str) {if (str == null) {System.out.println("传入的字符串为 null");} else {// 处理字符串}
}
注意事项
在实际开发中,经常需要同时判断字符串是否为 null
或空串,可以结合 null
判断和空串判断:
String str = null;
if (str == null || str.isEmpty()) {System.out.println("字符串为 null 或空串");
}
需要注意判断顺序,先判断
null
再判断空串,避免对null
字符串调用isEmpty()
方法导致NullPointerException
异常。
码点与代码单元
- Java字符串由char值序列组成。
- char数据类型是一个采用UTF-16编码表示Unicode码点的代码单元。大多数的常用Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。
Unicode 简介
Unicode 是一种字符编码标准,它为世界上几乎所有的字符都分配了一个唯一的数字,这个数字被称为码点。Unicode 码点的范围从
U+0000
到U+10FFFF
,可以表示超过一百万个字符。
码点(Code Point)
- 定义:码点是指 Unicode 编码中的一个数值,它唯一标识一个字符。例如,字符
'A'
的 Unicode 码点是U+0041
,字符'中'
的 Unicode 码点是U+4E2D
。在 Java 中,码点用int
类型表示,因为它的取值范围超出了char
类型所能表示的范围。- 获取码点:可以使用
String
类的codePointAt(int index)
方法来获取字符串中指定位置的码点。示例代码如下:
public class CodePointExample {public static void main(String[] args) {String str = "A中";// 获取第一个字符的码点int codePoint1 = str.codePointAt(0); // 获取第二个字符的码点int codePoint2 = str.codePointAt(1); System.out.println("字符 'A' 的码点: " + Integer.toHexString(codePoint1)); System.out.println("字符 '中' 的码点: " + Integer.toHexString(codePoint2)); }
}
遍历码点:可以使用
String
类的codePoints()
方法来遍历字符串中的所有码点。示例代码如下:
public class CodePointTraversal {public static void main(String[] args) {String str = "A中";str.codePoints().forEach(codePoint -> {System.out.println("码点: " + Integer.toHexString(codePoint));});}
}
代码单元(Code Unit)
- 定义:代码单元是字符串存储和处理的基本单位。在 Java 中,
String
类内部使用 UTF - 16 编码来存储字符,UTF - 16 编码使用 16 位(即 2 个字节)作为一个代码单元。对于 Unicode 码点在U+0000
到U+FFFF
范围内的字符(称为 BMP,基本多文种平面字符),可以用一个代码单元来表示;而对于码点在U+10000
到U+10FFFF
范围内的字符(称为补充字符),则需要用两个代码单元(即一个代理对)来表示。- 获取代码单元:可以使用
charAt(int index)
方法来获取字符串中指定位置的代码单元。示例代码如下:
public class CodeUnitExample {public static void main(String[] args) {String str = "A中";// 获取第一个代码单元char codeUnit1 = str.charAt(0); // 获取第二个代码单元char codeUnit2 = str.charAt(1); System.out.println("第一个代码单元: " + codeUnit1); System.out.println("第二个代码单元: " + codeUnit2); }
}
- 代码单元数量:可以使用
length()
方法来获取字符串中的代码单元数量。需要注意的是,对于包含补充字符的字符串,length()
方法返回的是代码单元的数量,而不是字符的实际数量。示例代码如下:
public class CodeUnitLength {public static void main(String[] args) {// 包含补充字符的字符串String str = "\uD83D\uDE00"; System.out.println("代码单元数量: " + str.length()); System.out.println("实际字符数量: " + str.codePoints().count()); }
}
码点与代码单元的关系
- 对于 BMP 字符,一个码点对应一个代码单元。
- 对于补充字符,一个码点对应两个代码单元。在处理包含补充字符的字符串时,需要特别注意,不能简单地使用
charAt()
和length()
方法,而应该使用与码点相关的方法,如codePointAt()
和codePoints()
方法。
输入输出
在 Java 中,输入输出(I/O)操作是非常重要的部分,它允许程序与外部环境进行数据交互,比如从键盘读取用户输入、将数据写入文件、从网络接收数据等。Java 的 I/O 操作主要分为标准输入输出、文件输入输出和网络输入输出。
格式化输出
输出整数
public class IntegerOutputExample {public static void main(String[] args) {int number = 12345;// 使用 System.out.print 输出整数System.out.print("整数输出结果: ");System.out.print(number);}
}
代码解释:
- 首先定义了一个
int
类型的变量number
并赋值为12345
。- 第一行
System.out.print
输出提示信息"整数输出结果: "
。- 第二行
System.out.print
输出变量number
的值。
沿用C库函数
- Java SE 沿用了 C 语言库函数中的
printf
方法风格。 - 在 C 语言里,
printf
函数是一个非常常用的输出函数,可按指定格式输出各种类型的数据。 - 而 Java 在
java.io.PrintStream
类中也提供了printf
方法,其功能和使用方式与 C 语言的printf
函数有相似之处,都是支持格式化输出。 - 代码示例:
public class PrintfExample {public static void main(String[] args) {int num = 10;double pi = 3.14159;String name = "John";// 输出整数System.out.printf("整数: %d\n", num);// 输出浮点数,保留两位小数System.out.printf("浮点数: %.2f\n", pi);// 输出字符串System.out.printf("字符串: %s\n", name);// 组合输出System.out.printf("%s 的幸运数字是 %d,他喜欢的圆周率近似值是 %.2f。\n", name, num, pi);}
}
与 C 语言 printf 的区别
注意:虽然 Java 的
printf
方法借鉴了 C 语言printf
函数的格式化输出方式,但 Java 是面向对象的语言,printf
是PrintStream
类的一个实例方法,并且 Java 有自己严格的类型检查机制,这和 C 语言有所不同。例如在 C 语言里,可能需要更手动地管理类型转换和内存,而 Java 会在编译阶段进行类型检查,保证代码的类型安全性。
用于printf的转换符
转换符 | 类型 | 举例 |
d | 十进制整数 | 159 |
x | 十六进制整数 | 9f |
o | 八进制整数 | 237 |
f | 定点浮点数 | 15.9 |
e | 指数浮点数 | 1.59e+01 |
g | 通用浮点数 | — |
a | 十六进制浮点数 | 0x1.fccdp3 |
s | 字符串 | Hello |
c | 字符 | H |
b | 布尔 | True |
h | 散列码 | 42628b2 |
tx 或 Tx(T 强制大写) | 日期时间(已经过时,应当改为使用 java.time 类) | - |
% | 百分号 | % |
n | 与平台有关的行分隔符 | — |
代码示例:
public class FormatConversionExample {public static void main(String[] args) {// 整数相关转换符int intValue = 159;System.out.printf("十进制整数(d): %d\n", intValue);System.out.printf("十六进制整数(x): %x\n", intValue);System.out.printf("八进制整数(o): %o\n", intValue);// 浮点数相关转换符double doubleValue = 15.9;System.out.printf("定点浮点数(f): %.1f\n", doubleValue);System.out.printf("指数浮点数(e): %e\n", doubleValue);System.out.printf("通用浮点数(g): %g\n", doubleValue);System.out.printf("十六进制浮点数(a): %a\n", doubleValue);// 字符串、字符、布尔、散列码相关转换符String strValue = "Hello";char charValue = 'H';boolean boolValue = true;Object obj = new Object();System.out.printf("字符串(s): %s\n", strValue);System.out.printf("字符(c): %c\n", charValue);System.out.printf("布尔(b): %b\n", boolValue);System.out.printf("散列码(h): %h\n", obj);// 百分号和行分隔符转换符System.out.printf("百分号(%%): %% \n");System.out.printf("与平台有关的行分隔符(n): 第一行%n第二行");}
}
运行结果:
十进制整数(d): 159
十六进制整数(x): 9f
八进制整数(o): 237
定点浮点数(f): 15.9
指数浮点数(e): 1.590000e+01
通用浮点数(g): 15.9
十六进制浮点数(a): 0x1.fccdp3
字符串(s): Hello
字符(c): H
布尔(b): true
散列码(h): 7852e922
百分号(%): %
与平台有关的行分隔符(n): 第一行
第二行
用于printf的转换符
public class PrintfFlagsExample {public static void main(String[] args) {double number = 3333.33;int intNumber = 159;// + 标志:打印正数和负数的符号System.out.printf("+ 标志示例:%+f\n", number);// 空格 标志:在正数之前添加空格System.out.printf("空格 标志示例:% f\n", number);// 0 标志:数字前面补0System.out.printf("0 标志示例:%010.2f\n", number);// - 标志:左对齐System.out.printf("- 标志示例:%-10.2f\n", number);// ( 标志:将负数括在括号内double negativeNumber = -3333.33;System.out.printf("( 标志示例:%(f\n", negativeNumber);//, 标志:添加分组分隔符System.out.printf(", 标志示例:%,f\n", number);// #(对于f格式)标志:包含小数点System.out.printf("#(对于f格式)标志示例:%,#.0f\n", number);// #(对于x或o格式)标志:添加前缀0x或0System.out.printf("#(对于x格式)标志示例:%#x\n", intNumber);// $ 标志:指定要格式化的参数索引System.out.printf("$ 标志示例:%1$d %1$x\n", intNumber);// < 标志:格式化前面说明的数值System.out.printf("< 标志示例:%d%<x\n", intNumber);}
}
运行结果
+ 标志示例:+3333.330000
空格 标志示例: 3333.330000
0 标志示例:003333.33
- 标志示例:3333.33
( 标志示例:(3333.33)
, 标志示例:3,333.330000
#(对于f格式)标志示例:3,333.
#(对于x格式)标志示例:0x9f
$ 标志示例:159 9f
< 标志示例:159 9f
标志 | 目的 | 示例代码中的效果 |
+ | 打印正数和负数的符号 | 输出+3333.330000 |
空格 | 在正数之前添加空格 | 输出 3333.330000 |
0 | 数字前面补 0 | 输出003333.33 |
- | 左对齐 | 输出3333.33 |
( | 将负数括在括号内 | 输出(3333.33) |
, | 添加分组分隔符 | 输出3,333.330000 |
#(对于 f 格式) | 包含小数点 | 输出3,333. |
#(对于 x 或 o 格式) | 添加前缀 0x 或 0 | 输出0x9f |
$ | 指定要格式化的参数索引 | 输出159 9f |
< | 格式化前面说明的数值 | 输出159 9f |
日期和时间转换符
import java.util.Calendar;public class DateTimeConversionExample {public static void main(String[] args) {Calendar calendar = Calendar.getInstance();System.out.println("完整的日期和时间 (c): " + String.format("%tc", calendar));System.out.println("ISO 8601日期 (F): " + String.format("%tF", calendar));System.out.println("美国格式的日期 (月/日/年) (D): " + String.format("%tD", calendar));System.out.println("24小时时间 (T): " + String.format("%tT", calendar));System.out.println("12小时时间 (r): " + String.format("%tr", calendar));System.out.println("24小时时间,没有秒 (R): " + String.format("%tR", calendar));System.out.println("4位数字的年(前面补0) (Y): " + String.format("%tY", calendar));System.out.println("年的后两位数字(前面补0) (y): " + String.format("%ty", calendar));System.out.println("年的前两位数字(前面补0) (C): " + String.format("%tC", calendar));System.out.println("月的完整拼写 (B): " + String.format("%tB", calendar));System.out.println("月的缩写 (b或h): " + String.format("%tb", calendar));System.out.println("两位数字的月(前面补0) (m): " + String.format("%tm", calendar));System.out.println("两位数字的日(前面补0) (d): " + String.format("%td", calendar));System.out.println("两位数字的日(前面不补0) (e): " + String.format("%te", calendar));System.out.println("星期几的完整拼写 (A): " + String.format("%tA", calendar));System.out.println("星期几的缩写 (a): " + String.format("%ta", calendar));System.out.println("三位数的年中第几天(前面补0),在001到366之间 (j): " + String.format("%tj", calendar));System.out.println("两位数字的小时(前面补0),在0到23之间 (H): " + String.format("%tH", calendar));System.out.println("两位数字的小时(前面不补0),在0到23之间 (k): " + String.format("%tk", calendar));System.out.println("两位数字的小时(前面补0),在01到12之间 (I): " + String.format("%tI", calendar));System.out.println("两位数字的小时(前面不补0),在1到12之间 (l): " + String.format("%tl", calendar));System.out.println("两位数字的分钟(前面补0) (M): " + String.format("%tM", calendar));System.out.println("两位数字的秒(前面补0) (S): " + String.format("%tS", calendar));System.out.println("三位数字的毫秒(前面补0) (L): " + String.format("%tL", calendar));System.out.println("九位数字的毫秒(前面补0) (N): " + String.format("%tN", calendar));System.out.println("上午或下午的标志 (p): " + String.format("%tp", calendar));System.out.println("从GMT起,RFC 822数字位移 (z): " + String.format("%tz", calendar));System.out.println("时区 (Z): " + String.format("%tZ", calendar));System.out.println("从格林尼治时间1970-01-01 00:00:00起的秒数 (s): " + String.format("%ts", calendar));System.out.println("从格林尼治时间1970-01-01 00:00:00起的毫秒数 (Q): " + String.format("%tQ", calendar));}
}
转换符 | 类型 | 示例 |
c | 完整的日期和时间 | Sun Jan 26 14:53:00 CST 2025 |
F | ISO 8601 日期 | 2025-01-26 |
D | 美国格式的日期 (月 / 日 / 年) | 01/26/25 |
T | 24 小时时间 | 14:53:00 |
r | 12 小时时间 | 02:53:00 pm |
R | 24 小时时间,没有秒 | 14:53 |
Y | 4 位数字的年(前面补 0) | 2025 |
y | 年的后两位数字(前面补 0) | 25 |
C | 年的前两位数字(前面补 0) | 20 |
B | 月的完整拼写 | January |
b 或 h | 月的缩写 | Jan |
m | 两位数字的月(前面补 0) | 01 |
d | 两位数字的日(前面补 0) | 26 |
e | 两位数字的日(前面不补 0) | 26 |
A | 星期几的完整拼写 | Sunday |
a | 星期几的缩写 | Sun |
j | 三位数的年中第几天(前面补 0),在 001 到 366 之间 | 026 |
H | 两位数字的小时(前面补 0),在 0 到 23 之间 | 14 |
k | 两位数字的小时(前面不补 0),在 0 到 23 之间 | 14 |
I | 两位数字的小时(前面补 0),在 01 到 12 之间 | 02 |
l | 两位数字的小时(前面不补 0),在 1 到 12 之间 | 2 |
M | 两位数字的分钟(前面补 0) | 53 |
S | 两位数字的秒(前面补 0) | 00 |
L | 三位数字的毫秒(前面补 0) | 123 |
N | 九位数字的毫秒(前面补 0) | 123000000 |
p | 上午或下午的标志 | pm |
z | 从 GMT 起,RFC 822 数字位移 | +0800 |
Z | 时区 | CST |
s | 从格林尼治时间 1970-01-01 00:00:00 起的秒数 | 1738009980 |
Q | 从格林尼治时间 1970-01-01 00:00:00 起的毫秒数 | 1738009980123 |
相关文章:
java入门笔记基础语法篇(4)
变量 在Java中,每个变量都有一个类型(type)。在声明变量时,变量的类型位于变量 名之前。例如: int days; double salary; long earthPopulation; boolean done; 在Java中,每个声明以分号结束。变量名必须…...
【RocketMQ 存储】- broker 端存储单条消息的逻辑
文章目录 1. 前言2. DefaultMessageStore#asyncPutMessage 添加单条消息2.1 DefaultMessageStore#checkStoreStatus 检查存储服务的状态2.2 DefaultMessageStore#checkMessage 校验消息长度是否合法2.3 CommitLog#asyncPutMessage 核心存储逻辑2.4 MappedFile#appendMessage2.5…...
爬虫基础(四)线程 和 进程 及相关知识点
目录 一、线程和进程 (1)进程 (2)线程 (3)区别 二、串行、并发、并行 (1)串行 (2)并行 (3)并发 三、爬虫中的线程和进程 &am…...
29. C语言 可变参数详解
本章目录: 前言可变参数的基本概念可变参数的工作原理如何使用可变参数 示例:计算多个整数的平均值解析: 更复杂的可变参数示例:打印可变数量的字符串解析: 总结 前言 在C语言中,函数参数的数量通常是固定的ÿ…...
Java CAS操作
通过前面的学习认识到了CPU缓存,Java内存模型,以及线程安全的原子、可见、顺序三大特性。本文则重点认识CAS操作,这是Java并发编程常见的一个操作,AbstractQueuedSynchronizer基于此操作提供了丰富的同步器和各种锁。 CAS&#x…...
KNIME:开源 AI 数据科学
KNIME(Konstanz Information Miner)是一款开源且功能强大的数据科学平台,由德国康斯坦茨大学的软件工程师团队开发,自2004年推出以来,广泛应用于数据分析、数据挖掘、机器学习和可视化等领域。以下是对KNIME的深度介绍…...
超级强大的压缩和解压工具,免费解压
软件介绍 今天要给大家分享一款超厉害的软件 ——ZArchiver,在我心中,它堪称安卓平台目前最为强大的解压软件。 之前,我一直使用 MT 管理器来解压文件。然而,MT 管理器存在一些局限性。比如在处理解压分卷文件时,它有时…...
代码随想录_栈与队列
栈与队列 232.用栈实现队列 232. 用栈实现队列 使用栈实现队列的下列操作: push(x) – 将一个元素放入队列的尾部。 pop() – 从队列首部移除元素。 peek() – 返回队列首部的元素。 empty() – 返回队列是否为空。 思路: 定义两个栈: 入队栈, 出队栈, 控制出入…...
基于STM32的智能停车场管理系统设计
目录 引言系统设计 硬件设计软件设计 系统功能模块 车辆识别与进出管理模块车位检测与引导模块计费与支付模块数据存储与查询模块远程监控与异常报警模块 控制算法 车牌识别与车辆进出管理算法车位检测与引导算法计费与支付处理算法数据存储与远程反馈算法 代码实现 车辆检测与…...
告别重启!Vue CLI 动态代理配置实战:实现热更新与灵活配置
在前端开发中,代理配置是解决跨域问题的常见手段。尤其是在使用 Vue CLI 进行开发时,我们经常需要通过 devServer.proxy 来配置代理。然而,传统的代理配置通常是静态的,修改后需要重启开发服务器,这在频繁调整代理配置…...
Cocos Creator 3.8 2D 游戏开发知识点整理
目录 Cocos Creator 3.8 2D 游戏开发知识点整理 1. Cocos Creator 3.8 概述 2. 2D 游戏核心组件 (1) 节点(Node)与组件(Component) (2) 渲染组件 (3) UI 组件 3. 动画系统 (1) 传统帧动画 (2) 动画编辑器 (3) Spine 和 …...
【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.28 存储之道:跨平台数据持久化方案
好的,我将按照您的要求生成一篇高质量的Python NumPy文章。以下是第28篇《存储之道:跨平台数据持久化方案》的完整内容,包括目录、正文和参考文献。 1.28 存储之道:跨平台数据持久化方案 目录 #mermaid-svg-n1z37AP8obEgptkD {f…...
chrome源码剖析—UI架构消息机制
Chrome 浏览器的 UI 架构是高度模块化且基于现代图形技术和用户界面设计理念构建的。它的 UI 架构涵盖了窗口、标签页、控件、通知、菜单等组件的管理和交互。Chrome 的 UI 基本上是通过 views 框架和 Aura(Chrome 自己的 UI 层)构建的,后者又…...
面试经典150题——图的广度优先搜索
文章目录 1、蛇梯棋1.1 题目链接1.2 题目描述1.3 解题代码1.4 解题思路 2、最小基因变化2.1 题目链接2.2 题目描述2.3 解题代码2.4 解题思路 3、单词接龙3.1 题目链接3.2 题目描述3.3 解题代码3.4 解题思路 1、蛇梯棋 1.1 题目链接 点击跳转到题目位置 1.2 题目描述 给你一…...
Day30-【AI思考】-错题分类进阶体系——12维错误定位模型
文章目录 错题分类进阶体系——12维错误定位模型**一、认知层错误(根源性缺陷)****二、操作层错误(执行过程偏差)****三、心理层错误(元认知障碍)****四、进阶错误(专业级陷阱)** 错…...
利用Edu邮箱解锁Notion Pro,提升学习与工作效率
摘要: 本文将详细介绍如何通过Edu教育邮箱申请教育订阅,从而免费获得Notion Pro版的所有高级功能。此外,我们还将简要提及Edu邮箱的其他福利,如申请Azure 100免费VPS和OpenAI。通过对比Notion免费版和Pro版的差异,你将…...
剑指 Offer II 010. 和为 k 的子数组
comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20010.%20%E5%92%8C%E4%B8%BA%20k%20%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84/README.md 剑指 Offer II 010. 和为 k 的子数组 题目描述 给定一个正整数数组和一个…...
【外文原版书阅读】《机器学习前置知识》2.用看电影推荐的例子带你深入了解向量点积在机器学习的作用
目录 3.3 Where Are You Looking, Vector? The Dot Product 个人主页:Icomi 大家好,我是Icomi,本专栏是我阅读外文原版书《Before Machine Learning》对于文章中我认为能够增进线性代数与机器学习之间的理解的内容的一个输出,希望…...
Vue.js组件开发-实现全屏平滑移动、自适应图片全屏滑动切换
使用Vue实现全屏平滑移动、自适应图片全屏滑动切换的功能。使用Vue 3和Vue Router,并结合一些CSS样式来完成这个效果。 步骤 创建Vue项目:使用Vue CLI创建一个新的Vue项目。准备图片:将需要展示的图片放在项目的public目录下。创建组件&…...
openRv1126 AI算法部署实战之——ONNX模型部署实战
在RV1126开发板上部署ONNX算法,实时目标检测RTSP传输。视频演示地址 rv1126 yolov5 实时目标检测 rtsp传输_哔哩哔哩_bilibili 一、准备工作 1.从官网下载YOLOv5-v7.0工程(YOLOv5的第7个版本) 手动在线下载: Releases ultraly…...
实验作业管理系统的设计与实现
标题:实验作业管理系统的设计与实现 内容:1.摘要 本系统旨在解决当前实验作业管理中存在的问题,提高管理效率和质量。通过对现有系统的调研和分析,我们确定了系统的功能需求和性能要求,并采用了先进的技术和架构进行设计和实现。系统实现了实…...
【愚公系列】《循序渐进Vue.js 3.x前端开发实践》032-组件的Teleport功能
标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主&…...
leetcode——二叉树的最大深度(java)
给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:3 示例 2: 输入:root [1,null,2] 输…...
【PyTorch】3.张量类型转换
个人主页:Icomi 在深度学习蓬勃发展的当下,PyTorch 是不可或缺的工具。它作为强大的深度学习框架,为构建和训练神经网络提供了高效且灵活的平台。神经网络作为人工智能的核心技术,能够处理复杂的数据模式。通过 PyTorch࿰…...
自制一个入门STM32 四足机器人具体开发顺序
0 前期准备 1. 知识储备 学习 STM32 微控制器的基础知识,包括 GPIO、定时器、串口通信等外设的使用,可通过官方文档、教程和视频课程进行学习。了解舵机控制原理,因为四足机器人通常使用舵机来实现关节运动。掌握基本的机械结构设计知识&am…...
SpringCloud基础二(完结)
HTTP客户端Feign 在SpringCloud基础一中,我们利用RestTemplate结合服务注册与发现来发起远程调用的代码如下: String url "http://userservice/user/" order.getUserId(); User user restTemplate.getForObject(url, User.class);以上代码就…...
云原生时代,如何构建高效分布式监控系统
文章目录 一.监控现状二.Thanos原理分析SidecarQuerierStoreCompactor 三.Sidecar or ReceiverThanos Receiver工作原理 四.分布式运维架构 一.监控现状 Prometheus是CNCF基金会管理的一个开源监控项目,由于其良好的架构设计和完善的生态,迅速成为了监控…...
WordPress使用(1)
1. 概述 WordPress是一个开源博客框架,配合不同主题,可以有多种展现方式,博客、企业官网、CMS系统等,都可以很好的实现。 官网:博客工具、发布平台和内容管理系统 – WordPress.org China 简体中文,这里可…...
小白爬虫冒险之反“反爬”:无限debugger、禁用开发者工具、干扰控制台...(持续更新)
背景浅谈 小白踏足JS逆向领域也有一年了,对于逆向这个需求呢主要要求就是让我们去破解**“反爬机制”**,即反“反爬”,脚本处理层面一般都是decipher网站对request设置的cipher,比如破解一个DES/AES加密拿到key。这篇文章先不去谈…...
Time Constant | RC、RL 和 RLC 电路中的时间常数
注:本文为 “Time Constant” 相关文章合辑。 机翻,未校。 How To Find The Time Constant in RC and RL Circuits June 8, 2024 💡 Key learnings: 关键学习点: Time Constant Definition: The time constant (τ) is define…...
Python爬虫学习第三弹 —— Xpath 页面解析 实现无广百·度
早上好啊,大佬们。上回使用 Beautiful Soup 进行页面解析的内容是不是已经理解得十分透彻了~ 这回我们再来尝试使用另外一种页面解析,来重构上一期里写的那些代码。 讲完Xpath之后,小白兔会带大家解决上期里百度搜索的代码编写,保…...
JS 正则表达式 -- 分组【详解】含普通分组、命名分组、反向引用
普通分组 使用圆括号 () 来创建分组捕获匹配的内容,通过正则表达式匹配结果的数组来访问这些捕获的内容。 const str "Hello, World!"; const regex /(Hello), (World)!$/; const match str.match(regex);if (match) {console.log("完整匹配结果…...
Leetcode刷题-不定长滑动窗口
分享丨【题单】滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环) - 力扣(LeetCode) 3090 class Solution:def maximumLengthSubstring(self, s: str) -> int:c Counter()res 0rk -1for i in range(len(s)):i…...
【Rust自学】15.6. RefCell与内部可变性:“摆脱”安全性限制
题外话,这篇文章一共4050字,是截止到目前为止最长的文章,如果你能坚持读完并理解,那真的很强! 喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以…...
护眼好帮手:Windows显示器调节工具
在长时间使用电脑的过程中,显示器的亮度和色温对眼睛的舒适度有着重要影响。传统的显示器调节方式不仅操作繁琐,而且在低亮度下容易导致色彩失真。因此,今天我想为大家介绍一款适用于Windows系统的护眼工具,它可以帮助你轻松调节显…...
使用 OpenResty 构建高效的动态图片水印代理服务20250127
使用 OpenResty 构建高效的动态图片水印代理服务 在当今数字化的时代,图片在各种业务场景中广泛应用。为了保护版权、统一品牌形象,动态图片水印功能显得尤为重要。然而,直接在后端服务中集成水印功能,往往会带来代码复杂度增加、…...
36、【OS】【Nuttx】OSTest分析(2):环境变量测试
背景 2025.1.29 蛇年快乐! 接之前wiki 35、【OS】【Nuttx】OSTest分析(1):stdio测试(五) 已经分析完了第一个测试项,输入输出端口测试,接下来分析下环境变量测试,也比较…...
C++并发编程指南04
文章目录 共享数据的问题3.1.1 条件竞争双链表的例子条件竞争示例恶性条件竞争的特点 3.1.2 避免恶性条件竞争1. 使用互斥量保护共享数据结构2. 无锁编程3. 软件事务内存(STM) 总结互斥量与共享数据保护3.2.1 互斥量使用互斥量保护共享数据示例代码&…...
Java实现LRU缓存策略实战
实现LRU模型选择LRU缓存回收算法集成Google Guava(LRU缓存策略)插件Google Guava(LRU策略)缓存示例总结LRU(Least Recently Used,最近最少使用)缓存是一种常见的缓存淘汰策略。它的基本思想是优先保留最近被访问过的数据,淘汰最久未被访问的数据。这种策略的目的是为了…...
三个不推荐使用的线程池
线程池的种类 其实看似这么多的线程池,都离不开ThreadPoolExecutor去创建,只不过他们是简化一些参数 newFixedThreadPool 里面全是核心线程 有资源耗尽的风险,任务队列最大长度为Integer.MAX_VALUE,可能会堆积大量的请求ÿ…...
Golang 并发机制-1:Golang并发特性概述
并发是现代软件开发中的一个基本概念,它使程序能够同时执行多个任务,从而提高效率和响应能力。在本文中,我们将探讨并发性在现代软件开发中的重要性,并深入研究Go处理并发任务的独特方法。 并发的重要性 增强性能 并发在提高软…...
Flink中的时间和窗口
在批处理统计中,我们可以等待一批数据都到齐后,统一处理。但是在实时处理统计中,我们是来一条就得处理一条,那么我们怎么统计最近一段时间内的数据呢?引入“窗口”。 所谓的“窗口”,一般就是划定的一段时…...
Alfresco Content Services dockerCompose自动化部署详尽操作
Alfresco Content Services docker社区部署文档 Alfresco Content Services简介 官方说明书 https://support.hyland.com/r/Alfresco/Alfresco-Content-Services-Community-Edition/23.4/Alfresco-Content-Services-Community-Edition/Using/Content/Folder-rules/Defining-…...
吴恩达深度学习——深层神经网络
来自https://www.bilibili.com/video/BV1FT4y1E74V,仅为本人学习所用。 符号约定 对于该深层网络,有四层,包含三个隐藏层和一个输出层。 隐藏层中,第一层有五个单元、第二层有五个单元,第三层有三个单元。标记 l l l…...
【算法设计与分析】实验1:字符串匹配问题的算法设计与求解
目录 一、实验目的 二、实验环境 三、实验内容 四、核心代码 五、记录与处理 六、思考与总结 七、完整报告和成果文件提取链接 一、实验目的 给定一个文本,在该文本中查找并定位任意给定字符串。 1、深刻理解并掌握蛮力法的设计思想; 2、提高应用…...
C语言二级题解:查找字母以及其他字符个数、数字字符串转双精度值、二维数组上下三角区域数据对调
目录 一、程序填空题 --- 查找字母以及其他字符个数 题目 分析 二、程序修改 --- 数字字符串转双精度值 题目 分析 小数位字符串转数字 三、程序设计 --- 二维数组上下三角区域数据对调 题目 分析 前言 本文来讲解: 查找字母以及其他字符个数、数字字符串…...
Git进阶之旅:Git 配置信息 Config
Git 配置级别: 仓库级别:local [ 优先级最高 ]用户级别:global [ 优先级次之 ]系统级别:system [ 优先级最低 ] 配置文件位置: git 仓库级别对应的配置文件是当前仓库下的 .git/configgit 用户级别对应的配置文件时用…...
Qwen2-VL:在任何分辨率下增强视觉语言模型对世界的感知 (大型视觉模型 核心技术 分享)
摘要 我们推出了Qwen2-VL系列,这是对之前Qwen-VL模型的高级升级,重新定义了视觉处理中的常规预设分辨率方法。Qwen2-VL引入了Naive Dynamic Resolution机制,使模型能够动态地将不同分辨率的图像转换为不同的视觉令牌数量。这种方法允许模型生成更高效和准确的视觉表示,紧密…...
【C语言】在Windows上为可执行文件.exe添加自定义图标
本文详细介绍了在 Windows 环境下,如何为使用 GCC 编译器编译的 C程序 添加自定义图标,从而生成带有图标的 .exe 可执行文件。通过本文的指导,读者可以了解到所需的条件以及具体的操作步骤,使生成的程序更具专业性和个性化。 目录 1. 准备条件2. 具体步骤步骤 1: 准备资源文…...
记录 | Docker的windows版安装
目录 前言一、1.1 打开“启用或关闭Windows功能”1.2 安装“WSL”方式1:命令行下载方式2:离线包下载 二、Docker Desktop更新时间 前言 参考文章:Windows Subsystem for Linux——解决WSL更新速度慢的方案 参考视频:一个视频解决D…...