Java核心技术--Java的基本程序设计结构

81 阅读34分钟

1.一个简单的Java应用程序

/**  
* @Author 烔  
* @date 2024/10/5  
* @Description ${description}  
*/  
public class Main {  
    public static void main(String[] args) {  
        System.out.println("We will not use 'Hello, World'!");  
    }  
}

图片.png

  • Java区分大小写;如果出现了大小写拼写错误,程序将无法运行
  • 关键字public称为访问修饰符(access modifier),这些修饰符用于控制程序的其他部分对这段代码的访问级别
  • 关键字class表明Java程序中的全部内容都包含在类中,
  • 关键字class后面紧跟类名,Java中定义类名的规则很宽松,名字必须以字母开头,后面可以跟字母和数字的任意组合.长度基本上没有限制,但是不能使用Java保留字作为类名
  • 类名是以大写字母开头的名词,如果名字由多个单词组成,每个单词的第一个字母都应该大写(这种在一个单词中间使用大写字母的方式称为骆驼命名法(camel case))

根据Java语言规范,main方法必须声明为public

Java语言规范:

docs.oracle.com/javase/spec…

需要注意源代码中的大括号{},在C/C++中,用大括号划分程序的各个部分(通常称为).Java中任何方法的代码都用"{"开始,"}"结束

总结: 每个Java应用程序都必须有一个main方法,其声明格式如下所示:

public class ClassName{
    public static void main(String[] args){
        program statements
    }
}

System.out.println("We will not use 'Hello, World'!");
  • 在Java中,每个句子必须用分号结束,
  • 回车不是语句的结束标志,如果需要可以将一条语句写在多行上
  • 上面这条语句的功能是将一个文本行输出到控制台上
  • 在这里,使用System.out对象并调用了它的println方法.注意:点好( . )用于调用方法
  • Java使用的通用语法是object.method(parameters),等价于函数调用
  • println方法将传递给它的字符串参数显示在控制台上,然后,终止这个输出行,使得每次调用println都会在新的一行上显示输出
  • 与其他程序设计语言中的函数一样,Java中的方法可以没有参数,也可以有一个或多个参数.即使一个方法没有参数,也需要使用空括号

2. 注释

在Java中,有三种标记注释的方法:

  1. // 注释内容
  2. /* 注释内容 */
  3. /** 注释内容 */ 这种注释可以用来自动地生成文档
public class Main {  
    /**  
    * @Description 主函数  
    * @param args  
    */  
    public static void main(String[] args) {  
        // 定义一个字符串数组 单行注释  
        System.out.println("We will not use 'Hello, World'!");  
        /*  
            这是一段注释  
            多行注释  
        */  
    }  
}

3. 数据类型

Java是一种强类型语言.这就意味着必须为每一个变量声明一种类型.

在Java中,一共有 8 种基本类型(primitive type).其中有4种整型,2种浮点型,1种字符类型char和一种用于表示真值的boolean类型

Java中有一个能够表示任意精度的算术包,通常称为"大数"(big nummber).虽然被称为大数,但它并不是一种基本Java类型,而是一个Java对象

3.1 整型

整型用于表示没有小数部分的数值,允许是负数.

图片.png

  • 在通常情况下,int类型是最常用的,但如果想要表示整个地球的居住人口,就需要使用 long类型
  • byte和short类型主要用于特定的应用场合,eg:底层的文件处理或者存储空间很宝贵时的大数组
  • 在Java中,整型的范围与运行Java代码的机器无关,这就解决了软件从一个平台移植到另一个平台,或者在同一个平台中的不同操作系统之间进行移植给程序猿带来的诸多问题
  • 由于Java程序必须保证在所有机器上都能够得到相同的运行结果,所以各种数据类型的取值范围必须固定
  • 长整型数值友谊个后缀 lL

3.2 浮点类型

浮点类型用于表示有小数部分的数值

图片.png

  • double表示这种类型的数值精度是float类型的两倍
  • float类型的数值有一个后缀Ff(eg: 3.14F).没有后缀F的浮点数值(eg: 3.24)总是默认为double类型,当然,也可以在浮点数值后面添加后缀Dd(eg:3.14D)
  • 所有浮点数值计算都遵循IEEE 754规范.具体来说,下面是用于表示溢出和出错情况的三个特殊的浮点数值:
    • 正无穷大
    • 负无穷大
    • NaN(不是一个数字)
  • eg: 一个正整数除以0的结果为正无穷大.计算0/0或者负数的平方根结果为NaN

3.3 char类型

char类型用于表示单个字符或者Unicode字符也可以用一个char值描述.另外一些Unicode字符需要两个char值

char类型的字面量值要用单引号括起来, eg: 'A'

char类型的值也可以表示为十六进制,如特殊字符

图片.png

3.5 boolean类型

boolean(布尔)类型有两个值:false和true,用来判定逻辑条件,整型值和布尔值之间不能进行相互转换

4. 变量与常量

与所有设计语言一样,Java也使用变量来存储值.常量就是值不变的变量.

4.1 声明变量

在声明变量时,先指定变量的类型,,然后是变量名.eg:

double salary;
int vacationDays;
long earthPopulation;
boolean done;
  • 变量名必须是一个以字母开头并有字母或数字构成的序列.
  • 变量名中所有的字符都是有意义的,并且大小写敏感
  • 变量名的长度基本上没有限制
  • 不能使用Java保留字作为变量名 可以在一行中声明多个变量
int i,j;

不提倡使用这种风格,逐一声明每给一个变量可以提高程序的可读性

4.2 变量初始化

声明一个变量之后,必须用赋值语句对变量进行显式初始化,千万不要使用未初始化的变量的值

int vacationDays;
vacationDays = 12;

也可以将变量的声明和初始化放在同一行中,eg:

int vacationDays = 12;

在java中可以将声明放在代码中的任何地方,但是变量的声明尽可能靠近变量第一次使用的地方,这是一种良好的程序编写风格

4.3 常量

在Java中,利用关键字final指示常量

        final double CM_PER_INCH = 2.54;

关键字final表示这个变量只能被赋值一次,一旦被赋值只收,就不能够在更改考虑,习惯上,常量名使用全大写.

在Java中,经常希望某个常量可以在一个类的多个方法中使用,通常将这些常量称为类常量(class constant),可以使用关键字static final设置一个类常量

public static final CM_PER_INCH = 2.54;

注意: 类常量的定义位于main方法的外部,因此在同一个类的其他方法中也可以使用这个常量,而且,如果一个常量被声明为public,那么其他类的方法也可以使用这个常量

4.4 枚举类型

有时候,变量的取值只在一个有限的集合内,例如,销售的服装大小或披萨只有小,中,大和超大这四种尺寸,针对这种情况,可以zidingy8枚举类型.枚举类型包括有限个命名的值,eg:

enum Size {SAMLL, MEDIUM, LARGE, EXTRA_LARGE};

// 枚举类型 定义一个枚举类型的变量 并赋值  
Size size = Size.EXTRA_LARGE;

Size类型的变量只能存储这个类型声明中给定的某个枚举值,或特殊值null,null表示这个变量没有设置任何值

5 运算符

运算符用于连接值

5.1 算术运算符

在Java中,算术运算符用于执行基本的数学运算。以下是Java中的主要算术运算符及其用法:

  1. 加法运算符 (+):

    • 用于数值相加。
    • 也可以用于字符串连接。
    int a = 10;
    int b = 20;
    int sum = a + b; // sum 的值为 30
    
    String str1 = "Hello, ";
    String str2 = "World!";
    String greeting = str1 + str2; // greeting 的值为 "Hello, World!"
    
  2. 减法运算符 (-):

    • 用于数值相减。
    int a = 20;
    int b = 10;
    int difference = a - b; // difference 的值为 10
    
  3. 乘法运算符 (*):

    • 用于数值相乘。
    int a = 5;
    int b = 4;
    int product = a * b; // product 的值为 20
    
  4. 除法运算符 (/):

    • 用于数值相除。
    • 如果两个操作数都是整数,则结果也是整数(舍去小数部分)。
    • 如果有一个或两个操作数是浮点数,则结果是浮点数。
    int a = 10;
    int b = 3;
    int quotient = a / b; // quotient 的值为 3 (因为是整数除法)
    
    double c = 10.0;
    double d = 3.0;
    double quotientDouble = c / d; // quotientDouble 的值为 3.3333333333333335
    
  5. 取模运算符 (%):

    • 用于获取两个数相除后的余数。
    int a = 10;
    int b = 3;
    int remainder = a % b; // remainder 的值为 1
    
  6. 自增运算符 (++):

    • 用于将变量的值增加1。
    • 可以放在变量之前(前缀形式)或之后(后缀形式)。
    • 前缀形式先进行自增,然后使用新的值;后缀形式先使用旧的值,然后再进行自增。
    int a = 5;
    int b = ++a; // a 先自增为 6,然后 b 被赋值为 6
    int c = a++; // c 被赋值为 6,然后 a 自增为 7
    
  7. 自减运算符 (--):

    • 用于将变量的值减少1。
    • 类似于自增运算符,可以放在变量之前(前缀形式)或之后(后缀形式)。
    • 前缀形式先进行自减,然后使用新的值;后缀形式先使用旧的值,然后再进行自减。
    int a = 5;
    int b = --a; // a 先自减为 4,然后 b 被赋值为 4
    int c = a--; // c 被赋值为 4,然后 a 自减为 3
    

这些运算符是Java编程中最常用的运算符之一,它们帮助开发者执行各种数学计算和逻辑处理。需要注意的是,在进行算术运算时要特别注意数据类型,特别是在涉及整数和浮点数混合运算时。

需要注意,整数被0除将会产生一个异常,而浮点数被0除将会得到无穷大或NaN结果

5.2 数学函数与常量

Math类中,包含了各种各样的数学函数,在编写不同类别的程序时,可能需要的函数也不同.

图片.png

Math (Java 2 Platform SE 6)

字段摘要
static doubleE           比任何其他值都更接近 e(即自然对数的底数)的 double 值。
static doublePI           比任何其他值都更接近 pi(即圆的周长与直径之比)的 double 值。

 

方法摘要
static doubleabs(double a)           返回 double 值的绝对值。
static floatabs(float a)           返回 float 值的绝对值。
static intabs(int a)           返回 int 值的绝对值。
static longabs(long a)           返回 long 值的绝对值。
static doubleacos(double a)           返回一个值的反余弦;返回的角度范围在 0.0 到 pi 之间。
static doubleasin(double a)           返回一个值的反正弦;返回的角度范围在 -pi/2 到 pi/2 之间。
static doubleatan(double a)           返回一个值的反正切;返回的角度范围在 -pi/2 到 pi/2 之间。
static doubleatan2(double y, double x)           将矩形坐标 (xy) 转换成极坐标 (r, theta),返回所得角 theta
static doublecbrt(double a)           返回 double 值的立方根。
static doubleceil(double a)           返回最小的(最接近负无穷大)double 值,该值大于等于参数,并等于某个整数。
static doublecopySign(double magnitude, double sign)           返回带有第二个浮点参数符号的第一个浮点参数。
static floatcopySign(float magnitude, float sign)           返回带有第二个浮点参数符号的第一个浮点参数。
static doublecos(double a)           返回角的三角余弦。
static doublecosh(double x)           返回 double 值的双曲线余弦。
static doubleexp(double a)           返回欧拉数 edouble 次幂的值。
static doubleexpm1(double x)           返回 ex -1。
static doublefloor(double a)           返回最大的(最接近正无穷大)double 值,该值小于等于参数,并等于某个整数。
static intgetExponent(double d)           返回 double 表示形式中使用的无偏指数。
static intgetExponent(float f)           返回 float 表示形式中使用的无偏指数。
static doublehypot(double x, double y)           返回 sqrt(x2 +y2),没有中间溢出或下溢。
static doubleIEEEremainder(double f1, double f2)           按照 IEEE 754 标准的规定,对两个参数进行余数运算。
static doublelog(double a)           返回 double 值的自然对数(底数是 e)。
static doublelog10(double a)           返回 double 值的底数为 10 的对数。
static doublelog1p(double x)           返回参数与 1 之和的自然对数。
static doublemax(double a, double b)           返回两个 double 值中较大的一个。
static floatmax(float a, float b)           返回两个 float 值中较大的一个。
static intmax(int a, int b)           返回两个 int 值中较大的一个。
static longmax(long a, long b)           返回两个 long 值中较大的一个。
static doublemin(double a, double b)           返回两个 double 值中较小的一个。
static floatmin(float a, float b)           返回两个 float 值中较小的一个。
static intmin(int a, int b)           返回两个 int 值中较小的一个。
static longmin(long a, long b)           返回两个 long 值中较小的一个。
static doublenextAfter(double start, double direction)           返回第一个参数和第二个参数之间与第一个参数相邻的浮点数。
static floatnextAfter(float start, double direction)           返回第一个参数和第二个参数之间与第一个参数相邻的浮点数。
static doublenextUp(double d)           返回 d 和正无穷大之间与 d 相邻的浮点值。
static floatnextUp(float f)           返回 f 和正无穷大之间与 f 相邻的浮点值。
static doublepow(double a, double b)           返回第一个参数的第二个参数次幂的值。
static doublerandom()           返回带正号的 double 值,该值大于等于 0.0 且小于 1.0
static doublerint(double a)           返回最接近参数并等于某一整数的 double 值。
static longround(double a)           返回最接近参数的 long
static intround(float a)           返回最接近参数的 int
static doublescalb(double d, int scaleFactor)           返回 d × 2scaleFactor,其舍入方式如同将一个正确舍入的浮点值乘以 double 值集合中的一个值。
static floatscalb(float f, int scaleFactor)           返回 f × 2scaleFactor,其舍入方式如同将一个正确舍入的浮点值乘以 float 值集合中的一个值。
static doublesignum(double d)           返回参数的符号函数;如果参数为 0,则返回 0;如果参数大于 0,则返回 1.0;如果参数小于 0,则返回 -1.0。
static floatsignum(float f)           返回参数的符号函数;如果参数为 0,则返回 0;如果参数大于 0,则返回 1.0;如果参数小于 0,则返回 -1.0。
static doublesin(double a)           返回角的三角正弦。
static doublesinh(double x)           返回 double 值的双曲线正弦。
static doublesqrt(double a)           返回正确舍入的 double 值的正平方根。
static doubletan(double a)           返回角的三角正切。
static doubletanh(double x)           返回 double 值的双曲线余弦。
static doubletoDegrees(double angrad)           将用弧度表示的角转换为近似相等的用角度表示的角。
static doubletoRadians(double angdeg)           将用角度表示的角转换为近似相等的用弧度表示的角。
static doubleulp(double d)           返回参数的 ulp 大小。
static floatulp(float f)           返回参数的 ulp 大小。

5.3数值类型之间的转换

图片.png

实现箭头表示无信息丢失的转换,虚线箭头表示可能有精度损失的转换

在Java中,数值类型可以分为两大类:整数类型和浮点数类型。整数类型包括byteshortintlong;浮点数类型则包括floatdouble。这些类型的转换可以是隐式的(自动类型转换)或显式的(强制类型转换)。

自动类型转换

当从一个较小的数据类型转换为一个较大的数据类型时,Java会自动进行类型转换。这种转换也被称为“向上转型”或者“拓宽转换”,因为目标类型能够容纳源类型的所有值而不会丢失信息。例如:

  • byte -> short, int, long, float, double
  • short -> int, long, float, double
  • int -> long, float, double
  • long -> float, double
  • float -> double

示例代码:

int a = 100;
long b = a; // int to long, 自动类型转换

5.4 强制类型转换

如果需要将一个较大的数据类型转换成一个较小的数据类型,就需要使用强制类型转换。这种转换可能造成数据精度的损失。这种转换也被称为“向下转型”或者“窄化转换”。例如:

  • long -> int, short, byte
  • float -> int, long, short, byte
  • double -> int, long, short, byte, float

强制类型转换的语法是在目标类型前面加上括号。例如:

double x = 123.456;
int y = (int) x; // double to int, 可能导致精度丢失

需要注意的是,在执行窄化转换时,可能会发生数据截断,即超出目标类型范围的部分会被舍去。比如,将一个非常大的long值转换为int时,只有低32位被保留,高位部分会被丢弃。

5.5 结合赋值和运算符

可以在赋值中使用二元运算符,这是一种很方便的简写方式.eg:

x += 4; 等价于 x = x + 4;

如果运算符得到一个值,其类型与左侧操作数的类型不同,就会发生强制类型转换

5.6 自增与自减运算符

在Java中,自增(++)和自减(--)运算符用于将变量的值增加1或减少1。这两个运算符都有两种形式:前缀形式和后缀形式,它们之间的区别在于表达式中使用这些运算符时何时更新变量的实际值。

自增运算符 ++

前缀形式
  • 语法: ++variable
  • 功能: 先将变量的值加1,然后返回新的值。
  • 示例:
    int a = 5;
    int b = ++a; // a先变为6, 然后b被赋值为6
    
后缀形式
  • 语法: variable++
  • 功能: 返回当前变量的值,然后将变量的值加1。
  • 示例:
    int a = 5;
    int b = a++; // b先被赋值为5, 然后a变为6
    

自减运算符 --

前缀形式
  • 语法: --variable
  • 功能: 先将变量的值减1,然后返回新的值。
  • 示例:
    int a = 5;
    int b = --a; // a先变为4, 然后b被赋值为4
    
后缀形式
  • 语法: variable--
  • 功能: 返回当前变量的值,然后将变量的值减1。
  • 示例:
    int a = 5;
    int b = a--; // b先被赋值为5, 然后a变为4
    

使用场景

  • 循环控制:通常在for循环或者while循环中用来递增或递减计数器。

    for (int i = 0; i < 10; i++) {
        System.out.println(i);
    }
    
  • 数组索引操作:遍历数组元素时调整索引位置。

    int[] array = {1, 2, 3, 4, 5};
    for (int i = 0; i < array.length; i++) {
        System.out.println(array[i]);
    }
    
  • 算法实现:某些算法可能需要通过逐步改变某个变量的值来达到目的。

注意事项

  • 在复杂的表达式中同时使用前缀和后缀形式时要特别小心,因为这可能导致不易理解的行为,并且可能会有未定义的结果,特别是在不同的编译器上。
  • 应该避免在同一个语句中对同一个变量进行多次自增或自减,以防止不确定的行为。
  • 在多线程环境中,如果多个线程同时访问并修改相同的变量,应该使用同步机制或其他并发工具类来确保操作的原子性。

5.7 关系和boolean运算符

在Java中,关系运算符和布尔(boolean)运算符用于比较操作数并产生一个布尔结果(truefalse)。这些运算符是编程逻辑中的基础部分,对于条件判断、循环控制等都非常重要。

关系运算符

关系运算符用于比较两个值之间的关系。它们返回的结果总是布尔类型(boolean),即要么是true,要么是false。常见的关系运算符包括:

  • 等于 (==):检查两个操作数是否相等。
  • 不等于 (!=):检查两个操作数是否不相等。
  • 大于 (>):检查左边的操作数是否大于右边的操作数。
  • 小于 (<):检查左边的操作数是否小于右边的操作数。
  • 大于或等于 (>=):检查左边的操作数是否大于或等于右边的操作数。
  • 小于或等于 (<=):检查左边的操作数是否小于或等于右边的操作数。

示例:

int a = 5;
int b = 10;

System.out.println(a == b); // 输出 false
System.out.println(a != b); // 输出 true
System.out.println(a > b);  // 输出 false
System.out.println(a < b);  // 输出 true
System.out.println(a >= b); // 输出 false
System.out.println(a <= b); // 输出 true

布尔运算符

布尔运算符用于处理布尔类型的值,并且通常用于组合多个条件表达式。主要的布尔运算符有:

  • 逻辑与 (&&):如果两边的操作数都是true,则结果为true;否则为false。此外,它还支持短路计算,如果左边的操作数为false,那么不会评估右边的操作数。
  • 逻辑或 (||):如果任一操作数为true,则结果为true;只有当两边都为false时,结果才为false。同样地,它也支持短路计算,如果左边的操作数为true,那么不会评估右边的操作数。
  • 逻辑非 (!):反转操作数的布尔值,如果操作数为true,结果为false;反之亦然。
  • 位与 (&):对两个整型数字进行按位与运算。虽然它也可以用作逻辑与,但它不执行短路计算。
  • 位或 (|):对两个整型数字进行按位或运算。虽然它也可以用作逻辑或,但它不执行短路计算。
  • 异或 (^):当且仅当一个操作数为true而另一个为false时,结果为true

示例:

boolean x = true;
boolean y = false;

System.out.println(x && y); // 输出 false
System.out.println(x || y); // 输出 true
System.out.println(!x);     // 输出 false
System.out.println(x & y);  // 输出 false
System.out.println(x | y);  // 输出 true
System.out.println(x ^ y);  // 输出 true

短路特性

  • &&|| 运算符具有短路特性,这意味着如果第一个操作数已经能够决定整个表达式的结果,那么第二个操作数将不会被计算。这可以用来避免不必要的计算,特别是当第二个操作数可能引发异常或者代价较高时。

例如:

int value = 10;
if (value != 0 && 100 / value > 5) {
    System.out.println("Condition met.");
}
// 如果 value 为 0, 则 100 / value 不会被计算,从而避免了除以零的错误。

了解这些运算符及其行为对于编写正确的条件语句至关重要。正确使用它们可以帮助你构建出更加清晰、高效的代码。

5.8 位运算符

Java中的位运算符用于直接对整数类型(如intlong等)的二进制位进行操作。这些运算符对于处理底层数据和优化某些算法非常有用。以下是Java中提供的主要位运算符:

位与(&)

  • 功能:对两个操作数的每一位执行逻辑与操作。如果两个相应的二进制位都为1,则结果位为1;否则为0。
  • 示例
    int a = 5;   // 二进制 0101
    int b = 3;   // 二进制 0011
    int c = a & b; // 结果是 0001, 即十进制的1
    

位或(|)

  • 功能:对两个操作数的每一位执行逻辑或操作。如果两个相应的二进制位至少有一个为1,则结果位为1;否则为0。
  • 示例
    int a = 5;   // 二进制 0101
    int b = 3;   // 二进制 0011
    int c = a | b; // 结果是 0111, 即十进制的7
    

位异或(^)

  • 功能:对两个操作数的每一位执行异或操作。如果两个相应的二进制位不同,则结果位为1;相同则为0。
  • 示例
    int a = 5;   // 二进制 0101
    int b = 3;   // 二进制 0011
    int c = a ^ b; // 结果是 0110, 即十进制的6
    

位非(~)

  • 功能:对操作数的每一位执行取反操作。如果相应位为1,则变为0;反之亦然。
  • 示例
    int a = 5;   // 二进制 0101
    int c = ~a;  // 结果是 ...11111010 (前导位取决于整型大小)
    

左移(<<)

  • 功能:将第一个操作数的所有位向左移动指定的位数,右边空出的位置补0。
  • 示例
    int a = 5;   // 二进制 0101
    int c = a << 2; // 结果是 010100, 即十进制的20
    

右移(>>)

  • 功能:将第一个操作数的所有位向右移动指定的位数,左边空出的位置如果是正数则补0,如果是负数则补1。
  • 示例
    int a = 20;  // 二进制 10100
    int c = a >> 2; // 结果是 0010, 即十进制的5
    

无符号右移(>>>)

  • 功能:无论操作数是正数还是负数,都将左边空出的位置补0。
  • 示例
    int a = -20; // 二进制 ...11101100 (假设是32位系统)
    int c = a >>> 2; // 结果是 00111...11101, 最高位被清零
    

应用场景

  • 标志位设置:在一些情况下,可以使用位运算来设置或者清除特定的标志位。
  • 高效计算:例如,通过左移一位相当于乘以2,右移一位相当于除以2。
  • 数据压缩:利用位运算可以实现更紧凑的数据表示。
  • 权限控制:在安全性和访问控制领域,位运算常用来管理用户权限。

5.9 括号与运算符级别

图片.png

6. 字符串

Java字符串就是Unicode字符序列

Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义类,叫做String

String (Java 2 Platform SE 6)

java.lang 类 String

java.lang.Object
  java.lang.String

  •   public final class String
      extends Object
      implements Serializable, Comparable<String>, CharSequence
    

String 类代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。

字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。例如:

     String str = "abc";
 

等效于:

     char data[] = {'a', 'b', 'c'};
     String str = new String(data);
 

下面给出了一些如何使用字符串的更多示例:

     System.out.println("abc");
     String cde = "cde";
     System.out.println("abc" + cde);
     String c = "abc".substring(2,3);
     String d = cde.substring(1, 2);
 

String 类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。大小写映射基于 Character 类指定的 Unicode 标准版。

Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的,该方法由 Object 类定义,并可被 Java 中的所有类继承。有关字符串串联和转换的更多信息,请参阅 Gosling、Joy 和 Steele 合著的 The Java Language Specification

除非另行说明,否则将 null 参数传递给此类中的构造方法或方法将抛出 NullPointerException

String 表示一个 UTF-16 格式的字符串,其中的增补字符代理项对 表示(有关详细信息,请参阅 Character 类中的 Unicode 字符表示形式)。索引值是指 char 代码单元,因此增补字符在 String 中占用两个位置。

String 类提供处理 Unicode 代码点(即字符)和 Unicode 代码单元(即 char 值)的方法。

6.1 子串

String类的.substring方法可以从一个较大的字符串提取出一个子串.eg: 下面使用JShell进行测试:


jshell> String greeting = "Hello"
greeting ==> "Hello"

jshell> String s = greeting.substring(0,3)
s ==> "Hel"

substring方法的第二个参数是不想复制的第一个位置

图片.png

6.2 拼接

Java语言允许使用 + 号链接(拼接)两个字符串

jshell> String expletive = "Expletive"
expletive ==> "Expletive"

jshell> String PG13 = "deleted"
PG13 ==> "deleted"

jshell> String message = expletive + PG13
message ==> "Expletivedeleted"

当一个字符串与一个非字符串进行拼接时,后者会转换成字符串

jshell> int age = 5;
age ==> 5

jshell> String rating = "PG" + age;
rating ==> "PG5"

若果需要把多个字符串放在一起,用一个界定符分隔,可以使用静态join方法

图片.png

jshell> String all = String.join("/","S","M","L","XL")
all ==> "S/M/L/XL"

6.3 不可变字符串

String类没有提供修改字符串中某个字符的方法,在Java中实现修改字符串可以提取想要保留的子串,再与洗完替换的字符拼接:

jshell> greeting = greeting.substring(0,3) + "p!"
greeting ==> "Help!"

由于不能修改Java字符串中的单个字符,所以在Java文档中将String类对象称为是不可变

6.4 检测字符串是否相等

可以使用equals方法检查两个字符串是否相等

如果字符串相等,则返回true,否则,返回false

jshell> "Hello".equals(greeting)
$11 ==> false

jshell> greeting
greeting ==> "Help!"

要想检测连个字符串是否相等,而不区分大小写,可以使用equalsIgnoreCase方法

jshell> "help!".equalsIgnoreCase(greeting)
$14 ==> true

==这个运算符只能够确定两个字符串是否放在同一个位置

如果虚拟机始终将相同的字符串共享,就可以使用==运算符检测是否相等。但实际上只 有字符串字面量是共享的,而+或substring等操作得到的字符串并不共享。因此,千万不要 使用==运算符测试字符串的相等性,以免在程序中出现这种最糟糕的bug,看起来这种bug 就像随机产生的间歇性错误。

6.5 空串与Null串

在Java中,字符串处理是非常常见的操作。关于空串和null串的概念,它们虽然都表示某种形式的“无内容”,但实际上是两种不同的状态,并且在使用时需要注意区分。

空串(Empty String)

  • 定义:一个空串是指长度为0的字符串,即它没有任何字符。
  • 创建方式
    • 使用双引号括起来的空字符串字面量:""
    • 使用构造函数 new String() 创建一个新的空字符串实例
  • 检查方法
    • 可以通过调用字符串对象的 length() 方法来判断是否为空,如果返回值为0,则说明是空串。
    • 或者使用 isEmpty() 方法,该方法从Java 6开始引入,直接返回布尔值指示字符串是否为空。
  • 示例
    String emptyString = "";
    if (emptyString.isEmpty()) {
        System.out.println("The string is empty.");
    }
    

Null串(Null String)

  • 定义null是一个特殊的引用值,表示没有指向任何对象。当一个字符串变量被赋值为null时,意味着这个变量当前并没有引用任何实际的字符串对象。
  • 创建方式:直接将变量赋值为null
  • 检查方法
    • 在使用字符串之前,通常需要检查其是否为null,以避免NullPointerException异常。
    • 可以使用 == 运算符来比较一个字符串变量与null
  • 示例
    String nullString = null;
    if (nullString == null) {
        System.out.println("The string is null.");
    }
    

比较

  • 内存占用:空串会占用一定的内存空间(用于存储一个空字符串的对象),而null不占用额外的内存,因为它只是一个特殊值。
  • 使用安全:尝试对null串调用任何方法都会抛出NullPointerException,因此在处理未知或可能为null的字符串时,应该总是进行非空检查。空串则可以安全地调用所有字符串方法。
  • 逻辑含义:在某些业务逻辑中,空串和null可能代表不同的意义。例如,在数据库字段中,空串可能表示用户故意留空,而null可能表示数据未提供或不存在。

最佳实践

  • 在接收外部输入或从其他源获取字符串时,最好同时检查空串和null
  • 在设置默认值时,可以考虑将null转换为空串,这样可以简化后续的处理逻辑。
  • 当设计API或公共方法时,明确文档中应如何处理null和空串,以便使用者能够正确地理解和使用这些方法。

6.6 码点与代码单元

在处理文本数据时,理解码点(Code Points)和代码单元(Code Units)之间的区别是非常重要的,尤其是在使用Unicode标准的现代编程语言中,如Java。这两个术语描述了字符编码的不同方面。

码点 (Code Points)

  • 定义:码点是Unicode标准中用来唯一标识一个字符的整数值。每个Unicode字符都有一个唯一的码点。
  • 范围:Unicode码点从U+0000U+10FFFF,总共可以表示超过1百万个不同的字符。
  • 用途:码点用于确定字符的身份。例如,字母 'A' 的码点是 U+0041,而汉字 '一' 的码点是 U+4E00

代码单元 (Code Units)

  • 定义:代码单元是指存储字符所使用的最小单位。它取决于具体的编码方案。
  • 大小:不同编码方案下的代码单元大小可能不同:
    • 在UTF-8中,一个代码单元通常是8位(1字节),但某些字符需要多个字节来表示。
    • 在UTF-16中,一个代码单元通常是16位(2字节)。大多数常用字符可以用一个代码单元表示,但对于超出基本多文种平面(BMP)的字符(即码点大于 U+FFFF 的字符),需要用两个代码单元(代理对)来表示。
    • 在UTF-32中,一个代码单元是32位(4字节),足以直接表示所有Unicode码点,不需要代理对。

关系

  • UTF-8:一个码点可能对应1到4个代码单元。
  • UTF-16:一个码点可能对应1或2个代码单元(对于BMP之外的字符)。
  • UTF-32:一个码点总是对应1个代码单元。

Java中的应用

在Java中,char类型实际上是一个16位的无符号整数,这使得它能够直接表示UTF-16的一个代码单元。因此,在处理Unicode字符时,需要注意以下几点:

  • 单个字符:如果字符位于基本多文种平面内(BMP),那么它可以被一个char值完全表示。
  • 代理对:如果字符不在BMP内,Java会使用两个char值(代理项)来表示这个字符。这种情况下,一个码点将由两个char组成。
  • String类String类内部使用char[]数组存储字符,这意味着字符串中的每个位置可能只包含半个代理对。为了正确处理这些情况,Java提供了codePointAt(int index)codePointCount()等方法来处理完整的码点。

示例代码:

String s = "A\ud83d\ude00"; // A 和 😄 (笑脸表情)
int length = s.length(); // 返回3,因为有三个char
int codePointCount = s.codePointCount(0, s.length()); // 返回2,因为有两个码点
int codePoint = s.codePointAt(1); // 获取第二个码点,即 😄 的码点
System.out.println("Length: " + length);
System.out.println("Code Point Count: " + codePointCount);
System.out.println("Second Code Point: " + Integer.toHexString(codePoint));

6.7 StringAPI

String (Java 2 Platform SE 6)

方法摘要
 charcharAt(int index)           返回指定索引处的 char 值。
 intcodePointAt(int index)           返回指定索引处的字符(Unicode 代码点)。
 intcodePointBefore(int index)           返回指定索引之前的字符(Unicode 代码点)。
 intcodePointCount(int beginIndex, int endIndex)           返回此 String 的指定文本范围中的 Unicode 代码点数。
 intcompareTo(String anotherString)           按字典顺序比较两个字符串。
 intcompareToIgnoreCase(String str)           按字典顺序比较两个字符串,不考虑大小写。
 Stringconcat(String str)           将指定字符串连接到此字符串的结尾。
 booleancontains(CharSequence s)           当且仅当此字符串包含指定的 char 值序列时,返回 true。
 booleancontentEquals(CharSequence cs)           将此字符串与指定的 CharSequence 比较。
 booleancontentEquals(StringBuffer sb)           将此字符串与指定的 StringBuffer 比较。
static StringcopyValueOf(char[] data)           返回指定数组中表示该字符序列的 String。
static StringcopyValueOf(char[] data, int offset, int count)           返回指定数组中表示该字符序列的 String。
 booleanendsWith(String suffix)           测试此字符串是否以指定的后缀结束。
 booleanequals(Object anObject)           将此字符串与指定的对象比较。
 booleanequalsIgnoreCase(String anotherString)           将此 String 与另一个 String 比较,不考虑大小写。
static Stringformat(Locale l, String format, Object... args)           使用指定的语言环境、格式字符串和参数返回一个格式化字符串。
static Stringformat(String format, Object... args)           使用指定的格式字符串和参数返回一个格式化字符串。
 byte[]getBytes()           使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
 byte[]getBytes(Charset charset)           使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
 voidgetBytes(int srcBegin, int srcEnd, byte[] dst, int dstBegin)           已过时。 该方法无法将字符正确转换为字节。从 JDK 1.1 起,完成该转换的首选方法是通过 getBytes() 方法,该方法使用平台的默认字符集。
 byte[]getBytes(String charsetName)           使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
 voidgetChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)           将字符从此字符串复制到目标字符数组。
 inthashCode()           返回此字符串的哈希码。
 intindexOf(int ch)           返回指定字符在此字符串中第一次出现处的索引。
 intindexOf(int ch, int fromIndex)           返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。
 intindexOf(String str)           返回指定子字符串在此字符串中第一次出现处的索引。
 intindexOf(String str, int fromIndex)           返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
 Stringintern()           返回字符串对象的规范化表示形式。
 booleanisEmpty()           当且仅当 length()0 时返回 true
 intlastIndexOf(int ch)           返回指定字符在此字符串中最后一次出现处的索引。
 intlastIndexOf(int ch, int fromIndex)           返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。
 intlastIndexOf(String str)           返回指定子字符串在此字符串中最右边出现处的索引。
 intlastIndexOf(String str, int fromIndex)           返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
 intlength()           返回此字符串的长度。
 booleanmatches(String regex)           告知此字符串是否匹配给定的正则表达式
 intoffsetByCodePoints(int index, int codePointOffset)           返回此 String 中从给定的 index 处偏移 codePointOffset 个代码点的索引。
 booleanregionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)           测试两个字符串区域是否相等。
 booleanregionMatches(int toffset, String other, int ooffset, int len)           测试两个字符串区域是否相等。
 Stringreplace(char oldChar, char newChar)           返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
 Stringreplace(CharSequence target, CharSequence replacement)           使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
 StringreplaceAll(String regex, String replacement)           使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
 StringreplaceFirst(String regex, String replacement)           使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
 String[]split(String regex)           根据给定正则表达式的匹配拆分此字符串。
 String[]split(String regex, int limit)           根据匹配给定的正则表达式来拆分此字符串。
 booleanstartsWith(String prefix)           测试此字符串是否以指定的前缀开始。
 booleanstartsWith(String prefix, int toffset)           测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
 CharSequencesubSequence(int beginIndex, int endIndex)           返回一个新的字符序列,它是此序列的一个子序列。
 Stringsubstring(int beginIndex)           返回一个新的字符串,它是此字符串的一个子字符串。
 Stringsubstring(int beginIndex, int endIndex)           返回一个新字符串,它是此字符串的一个子字符串。
 char[]toCharArray()           将此字符串转换为一个新的字符数组。
 StringtoLowerCase()           使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
 StringtoLowerCase(Locale locale)           使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。
 StringtoString()           返回此对象本身(它已经是一个字符串!)。
 StringtoUpperCase()           使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
 StringtoUpperCase(Locale locale)           使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。
 Stringtrim()           返回字符串的副本,忽略前导空白和尾部空白。
static StringvalueOf(boolean b)           返回 boolean 参数的字符串表示形式。
static StringvalueOf(char c)           返回 char 参数的字符串表示形式。
static StringvalueOf(char[] data)           返回 char 数组参数的字符串表示形式。
static StringvalueOf(char[] data, int offset, int count)           返回 char 数组参数的特定子数组的字符串表示形式。
static StringvalueOf(double d)           返回 double 参数的字符串表示形式。
static StringvalueOf(float f)           返回 float 参数的字符串表示形式。
static StringvalueOf(int i)           返回 int 参数的字符串表示形式。
static StringvalueOf(long l)           返回 long 参数的字符串表示形式。
static StringvalueOf(Object obj)           返回 Object 参数的字符串表示形式。

6.8 JavaAPI网站

www.runoob.com/manual/jdk1…

图片.png

6.9 构建字符串

有些时候,需要由较短的字符串构建字符串,如果采用字符串拼接的方式来达到这个目的,效率会比较低,每次拼接字符串时,都会构建一个新的String对象,既耗时,又浪费空间,使用StringBuilder类就可以避免这个问题的发生

jshell> StringBuilder stringBuilder = new StringBuilder()
stringBuilder ==>

jshell> stringBuilder.append("Hello,")
$2 ==> Hello,

jshell> stringBuilder.append("Yantong")
$3 ==> Hello,Yantong

7. 输入与输出

7.1 读取输入

Scanner scanner = new Scanner(System.in);

Scanner scanner = new Scanner(System.in);  
System.out.println("What's your name?");  
String name = scanner.nextLine();  
System.out.println("name = " + name); //

nextLine方法是因为在输入行中有可能包含空格 next方法以空白符作为分隔符,可以用来读取一个单词

Scanner (Java 2 Platform SE 6)

java.util 类 Scanner

java.lang.Object
  java.util.Scanner

  •   public final class Scanner
      extends Object
      implements Iterator<String>
    

一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。

Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配。然后可以使用不同的 next 方法将得到的标记转换为不同类型的值。

例如,以下代码使用户能够从 System.in 中读取一个数:

     Scanner sc = new Scanner(System.in);
     int i = sc.nextInt();
 

再看一个例子,以下代码使 long 类型可以通过 myNumbers 文件中的项分配:

      Scanner sc = new Scanner(new File("myNumbers"));
      while (sc.hasNextLong()) {
          long aLong = sc.nextLong();
      }

扫描器还可以使用不同于空白的分隔符。下面是从一个字符串读取若干项的例子:

     String input = "1 fish 2 fish red fish blue fish";
     Scanner s = new Scanner(input).useDelimiter("\s*fish\s*");
     System.out.println(s.nextInt());
     System.out.println(s.nextInt());
     System.out.println(s.next());
     System.out.println(s.next());
     s.close(); 

输出为:

     1
     2
     red
     blue 

以下代码使用正则表达式同时解析所有的 4 个标记,并可以产生与上例相同的输出结果:

     String input = "1 fish 2 fish red fish blue fish";
     Scanner s = new Scanner(input);
     s.findInLine("(\d+) fish (\d+) fish (\w+) fish (\w+)");
     MatchResult result = s.match();
     for (int i=1; i<=result.groupCount(); i++)
         System.out.println(result.group(i));
     s.close(); 

扫描器所使用的默认空白分隔符通过 Character.isWhitespace 来识别。不管以前是否更改,reset() 方法将把扫描器分隔符的值重置为默认空白分隔符。

扫描操作可能被阻塞,而等待信息的输入。

next()hasNext() 方法及其基本类型 companion 方法(如 nextInt()hasNextInt())首先跳过与分隔符模式匹配的输入,然后尝试返回下一个标记。在等待更多输入时 hasNextnext 方法都可能阻塞。hasNext 方法是否阻塞与其相关的 next 方法是否阻塞无关。

findInLine(java.lang.String)findWithinHorizon(java.lang.String, int)skip(java.util.regex.Pattern) 方法的执行与分隔符模式无关。这些方法会尝试匹配与输入中的分隔符无关的指定模式,因此可用于分隔符无关的特殊环境中。在等待更多输入时这些方法可能阻塞。

当某一扫描器抛出 InputMismatchException 时,该扫描器不会传递导致该异常的标记,因此可以通过其他某种方法来获取或跳过它。

对于某些类型的分隔模式,可能返回空标记。例如,"\s+" 模式不会返回空标记,因为它与该分隔符的多个实例匹配。而分隔模式 "\s" 可能返回空标记,因为它一次只传递一个空格。

扫描器可以从实现 Readable 接口的任何对象读取文本。如果对底层 readable 的 Readable.read(java.nio.CharBuffer) 方法的调用抛出 IOException,则扫描器认为已经到达了输入的结尾。底层 readable 最新抛出的 IOException 可以通过 ioException() 方法获取。

如果 Scanner 关闭,且其输入源实现 Closeable 接口,则该输入源也将关闭。

若没有外部同步,则 Scanner 的多线程使用是不安全的。

除非另行说明,否则将一个 null 参数传递到 Scanner 的任何一个方法中都将抛出 NullPointerException

默认情况下扫描器会将数字解释为十进制形式,除非已经使用 useRadix(int) 方法设置了不同的基数。不管以前是否更改,reset() 方法将把扫描器的基数重置为10

本地化数字

此类的一个实例能够以标准格式以及扫描器语言环境的格式扫描数字。扫描器的 初始语言环境 Locale.getDefault() 方法返回的值;它可以通过 useLocale(java.util.Locale) 方法更改。不管以前是否更改,reset() 方法将把扫描器的语言环境重置为初始语言环境。

本地化格式是根据以下参数定义的,对于某一特定语言环境来说,这些参数取自该语言环境的 DecimalFormat 对象 df,及其 DecimalFormatSymbols 对象 dfs

LocalGroupSeparator用于分隔数千个组的字符, dfs.getGroupingSeparator()
LocalDecimalSeparator用于小数点的字符, dfs.getDecimalSeparator()
LocalPositivePrefix出现在正数前的字符串(可以为空), df.getPositivePrefix()
LocalPositiveSuffix出现在正数后的字符串(可以为空), df.getPositiveSuffix()
LocalNegativePrefix出现在负数前的字符串(可以为空), df.getNegativePrefix()
LocalNegativeSuffix出现在负数后的字符串(可以为空), df.getNegativeSuffix()
LocalNaN表示浮点值的非数字的字符串, dfs.getNaN()
LocalInfinity表示浮点值的无穷大的字符串, dfs.getInfinity()
方法摘要
 voidclose()           关闭此扫描器。
 Patterndelimiter()           返回此 Scanner 当前正在用于匹配分隔符的 Pattern
 StringfindInLine(Pattern pattern)           试图在忽略分隔符的情况下查找下一个指定模式。
 StringfindInLine(String pattern)           试图在忽略分隔符的情况下查找下一个从指定字符串构造的模式。
 StringfindWithinHorizon(Pattern pattern, int horizon)           试图查找下一个指定模式。
 StringfindWithinHorizon(String pattern, int horizon)           试图在忽略分隔符的情况下查找下一个从指定字符串构造的模式。
 booleanhasNext()           如果此扫描器的输入中有另一个标记,则返回 true。
 booleanhasNext(Pattern pattern)           如果下一个完整标记与指定模式匹配,则返回 true。
 booleanhasNext(String pattern)           如果下一个标记与从指定字符串构造的模式匹配,则返回 true。
 booleanhasNextBigDecimal()           如果通过使用 nextBigDecimal() 方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 BigDecimal,则返回 true。
 booleanhasNextBigInteger()           如果通过使用 nextBigInteger() 方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 BigInteger 值,则返回 true。
 booleanhasNextBigInteger(int radix)           如果通过使用 nextBigInteger() 方法,此扫描器输入信息中的下一个标记可以解释为指定基数中的一个 BigInteger 值,则返回 true。
 booleanhasNextBoolean()           如果通过使用一个从字符串 "truefalse" 创建的大小写敏感的模式,此扫描器输入信息中的下一个标记可以解释为一个布尔值,则返回 true。
 booleanhasNextByte()           如果通过使用 nextByte() 方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个字节值,则返回 true。
 booleanhasNextByte(int radix)           如果通过使用 nextByte() 方法,此扫描器输入信息中的下一个标记可以解释为指定基数中的一个字节值,则返回 true。
 booleanhasNextDouble()           如果通过使用 nextDouble() 方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 double 值,则返回 true。
 booleanhasNextFloat()           如果通过使用 nextFloat() 方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 float 值,则返回 true。
 booleanhasNextInt()           如果通过使用 nextInt() 方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 int 值,则返回 true。
 booleanhasNextInt(int radix)           如果通过使用 nextInt() 方法,此扫描器输入信息中的下一个标记可以解释为指定基数中的一个 int 值,则返回 true。
 booleanhasNextLine()           如果在此扫描器的输入中存在另一行,则返回 true。
 booleanhasNextLong()           如果通过使用 nextLong() 方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 long 值,则返回 true。
 booleanhasNextLong(int radix)           如果通过使用 nextLong() 方法,此扫描器输入信息中的下一个标记可以解释为指定基数中的一个 long 值,则返回 true。
 booleanhasNextShort()           如果通过使用 nextShort() 方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 short 值,则返回 true。
 booleanhasNextShort(int radix)           如果通过使用 nextShort() 方法,此扫描器输入信息中的下一个标记可以解释为指定基数中的一个 short 值,则返回 true。
 IOExceptionioException()           返回此 Scanner 的底层 Readable 最后抛出的 IOException
 Localelocale()           返回此扫描器的语言环境。
 MatchResultmatch()           返回此扫描器所执行的最后扫描操作的匹配结果。
 Stringnext()           查找并返回来自此扫描器的下一个完整标记。
 Stringnext(Pattern pattern)           如果下一个标记与指定模式匹配,则返回下一个标记。
 Stringnext(String pattern)           如果下一个标记与从指定字符串构造的模式匹配,则返回下一个标记。
 BigDecimalnextBigDecimal()           将输入信息的下一个标记扫描为一个 BigDecimal
 BigIntegernextBigInteger()           将输入信息的下一个标记扫描为一个 BigInteger
 BigIntegernextBigInteger(int radix)           将输入信息的下一个标记扫描为一个 BigInteger
 booleannextBoolean()           扫描解释为一个布尔值的输入标记并返回该值。
 bytenextByte()           将输入信息的下一个标记扫描为一个 byte
 bytenextByte(int radix)           将输入信息的下一个标记扫描为一个 byte
 doublenextDouble()           将输入信息的下一个标记扫描为一个 double
 floatnextFloat()           将输入信息的下一个标记扫描为一个 float
 intnextInt()           将输入信息的下一个标记扫描为一个 int
 intnextInt(int radix)           将输入信息的下一个标记扫描为一个 int
 StringnextLine()           此扫描器执行当前行,并返回跳过的输入信息。
 longnextLong()           将输入信息的下一个标记扫描为一个 long
 longnextLong(int radix)           将输入信息的下一个标记扫描为一个 long
 shortnextShort()           将输入信息的下一个标记扫描为一个 short
 shortnextShort(int radix)           将输入信息的下一个标记扫描为一个 short
 intradix()           返回此扫描器的默认基数。
 voidremove()           Iterator 的这种实现不支持移除操作。
 Scannerreset()           重置此扫描器。
 Scannerskip(Pattern pattern)           在忽略分隔符的情况下跳过与指定模式匹配的输入信息。
 Scannerskip(String pattern)           跳过与从指定字符串构造的模式匹配的输入信息。
 StringtoString()           返回此 Scanner 的字符串表示形式。
 ScanneruseDelimiter(Pattern pattern)           将此扫描器的分隔模式设置为指定模式。
 ScanneruseDelimiter(String pattern)           将此扫描器的分隔模式设置为从指定 String 构造的模式。
 ScanneruseLocale(Locale locale)           将此扫描器的语言环境设置为指定的语言环境。
 ScanneruseRadix(int radix)           将此扫描器的默认基数设置为指定基数。

7.2 格式化输出

System.out.println()可以将内容输出并换行

System.out.printf()可以通过%字符使用相应的参数替换

图片.png

图片.png

图片.png

图片.png

System.out.printf("%tc",new Date()); //周二 10月 08 17:51:12 CST 2024

7.3 文件输入与输出

要想读取一个文件,需要构造一个Scanner对象 eg:

Scanner scanner = new Scanner(Path.of("src\\myfile.txt"), StandardCharsets.UTF_8);  
System.out.println(scanner.nextLine());

要想写入文件,就需要构造一个PrintWriter对象

PrintWriter printWriter = new PrintWriter("src/myfile.txt", StandardCharsets.UTF_8);
printWriter.write("Hello World!");  
printWriter.flush();

如果文件不存在,创建该文件.

8. 控制流程

8.1 块作用域

块:指由若干条Java语句组成的语句,并用一堆大括号括起来

块确定了变量的作用域

一个块可以嵌套在另一个块中

public static void main(String[] args)
{
    int n;
    ...
    {
        int k;
    }
}

8.2 条件语句

在Java中,条件语句用于根据不同的条件执行不同的代码块。主要的条件语句包括 if 语句、if-else 语句和 switch 语句。这些结构允许程序根据特定条件做出决策,并相应地执行不同的逻辑路径。

1. if 语句

if 语句是最基本的条件控制结构,它检查一个布尔表达式的值,如果该表达式为 true,则执行相应的代码块。

int number = 10;

if (number > 5) {
    System.out.println("数字大于5");
}

2. if-else 语句

if-else 语句扩展了 if 语句,提供了一个替代的代码块来处理布尔表达式为 false 的情况。

int number = 3;

if (number > 5) {
    System.out.println("数字大于5");
} else {
    System.out.println("数字不大于5");
}

3. if-else if-else 语句

当需要检查多个条件时,可以使用一系列的 if-else if-else 语句。只有第一个满足条件的 ifelse if 会执行,随后的条件不会被评估。

int number = 3;

if (number > 5) {
    System.out.println("数字大于5");
} else if (number == 5) {
    System.out.println("数字等于5");
} else {
    System.out.println("数字小于5");
}

4. switch 语句

switch 语句用于基于变量的值执行多路分支。它可以代替多个 if-else 语句,使代码更清晰简洁。从 Java 7 开始,switch 语句支持字符串类型;从 Java 12 开始,还支持模式匹配(Pattern Matching)。

int dayOfWeek = 3;  // 假设1代表星期一,2代表星期二等

switch (dayOfWeek) {
    case 1:
        System.out.println("星期一");
        break;
    case 2:
        System.out.println("星期二");
        break;
    case 3:
        System.out.println("星期三");
        break;
    default:
        System.out.println("其他天");
        break;
}
使用字符串的例子:
String dayName = "Monday";

switch (dayName) {
    case "Monday":
        System.out.println("今天是星期一");
        break;
    case "Tuesday":
        System.out.println("今天是星期二");
        break;
    default:
        System.out.println("未知的一天");
        break;
}

注意事项

  • 每个 case 标签后面必须有一个 break 语句,否则将发生“穿透”现象,即后续的 case 也会被执行。
  • default 语句是可选的,用来处理所有未明确指定的情况。
  • switch 语句中的表达式可以是整型(如 byte, short, int, long)、枚举或字符串类型。

示例:综合使用条件语句

下面是一个结合了 if-elseswitch 语句的例子:

public class ConditionalStatementsExample {
    public static void main(String[] args) {
        int score = 85;
        
        if (score >= 90) {
            System.out.println("优秀");
        } else if (score >= 70) {
            System.out.println("良好");
        } else if (score >= 60) {
            System.out.println("及格");
        } else {
            System.out.println("不及格");
        }

        String grade;
        switch (score / 10) {
            case 10:
            case 9:
                grade = "A";
                break;
            case 8:
                grade = "B";
                break;
            case 7:
                grade = "C";
                break;
            case 6:
                grade = "D";
                break;
            default:
                grade = "F";
                break;
        }
        System.out.println("等级: " + grade);
    }
}

8.3 循环

在Java中,循环结构允许你重复执行一段代码,直到满足某个条件为止。Java提供了几种不同类型的循环结构,包括 for 循环、while 循环和 do-while 循环。每种循环都有其特定的用途和适用场景。

1. for 循环

for 循环用于已知迭代次数的情况。它通常包含初始化部分、条件表达式和更新部分。

// 打印0到9
for (int i = 0; i < 10; i++) {
    System.out.println(i);
}
增强型 for 循环(For-Each 循环)

增强型 for 循环是 for 循环的一种简化形式,主要用于遍历数组或集合中的元素。

int[] numbers = {1, 2, 3, 4, 5};

// 遍历数组
for (int number : numbers) {
    System.out.println(number);
}

2. while 循环

while 循环会在每次循环开始前检查条件是否为真。如果条件为真,则执行循环体;否则,退出循环。

int i = 0;
while (i < 10) {
    System.out.println(i);
    i++;
}

3. do-while 循环

do-while 循环与 while 循环类似,但它是先执行一次循环体,然后再检查条件。因此,即使条件一开始就不满足,do-while 循环也会至少执行一次。

int j = 0;
do {
    System.out.println(j);
    j++;
} while (j < 10);

循环控制语句

除了基本的循环结构外,Java还提供了一些控制循环流程的语句:

  • break:立即退出当前循环。
  • continue:跳过当前循环的剩余部分,并继续下一次迭代。
  • 标签(Label):可以用来标记循环,配合 breakcontinue 使用,以跳出多层嵌套循环。
示例:使用 breakcontinue
// 使用 break
for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break;  // 当 i 等于 5 时,退出循环
    }
    System.out.println(i);
}

// 使用 continue
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) {
        continue;  // 跳过偶数
    }
    System.out.println(i);  // 只打印奇数
}
示例:使用标签
outerLoop: for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i == 1 && j == 1) {
            break outerLoop;  // 跳出最外层循环
        }
        System.out.println("i = " + i + ", j = " + j);
    }
}

在这个例子中,当 i 等于 1 且 j 等于 1 时,break outerLoop; 会终止整个 outerLoop 循环。

总结

  • for 循环:适用于已知迭代次数的情况。
  • while 循环:适用于不确定迭代次数,但可以在循环开始前检查条件的情况。
  • do-while 循环:确保至少执行一次循环体,然后在每次循环结束时检查条件。
  • breakcontinue:用于控制循环的流程。
  • 标签:用于更复杂的控制结构,如多重嵌套循环。

9.大数

如果基本的整数和浮点数精度不能够满足需求,那么可以使用java.math包中另个类:BigIntegerBigDecimal.这两个类可以处理包含任意长度数字序列的数值.

  • Biginteger实现任意精度的整数运算,
  • BigDecimal实现任意精度的浮点数运算

使用静态的valueOf方法可以将普通的数值转换为大数:

// 创建一个值为100的 BigInteger 对象  
BigInteger bigInteger = BigInteger.valueOf(100);  
// 打印 bigInteger 的值  
System.out.println("bigInteger = " + bigInteger);  
  
// 对于更大的数,使用字符串参数的构造器来表示  
// 创建一个表示极大整数的 BigInteger 对象  
BigInteger reallBig = new BigInteger("25646541321654651654510534654132151215641321654651654");  
// 打印 reallBig 的值  
System.out.println("reallBig = " + reallBig);

// 常用的常量  
System.out.println(BigInteger.ZERO);  
System.out.println(BigInteger.ONE);  
System.out.println(BigInteger.TEN);  
// Java 9新增的常量  
System.out.println(BigInteger.TWO);

*不能使用算术运算符(+ )处理大数,需要使用addmultiply方法

// 将 bigInteger 和 reallBig 相加,并将结果赋给 add  
BigInteger add = bigInteger.add(reallBig);  
System.out.println("add = " + add);  
  
// 将 add 与 reallBig 加 2 的结果相乘,并将结果赋给 multiply  
BigInteger multiply = add.multiply(reallBig.add(BigInteger.valueOf(2)));  
System.out.println("multiply = " + multiply);

BigInteger (Java 2 Platform SE 6)

方法摘要
 BigIntegerabs()           返回其值是此 BigInteger 的绝对值的 BigInteger。
 BigIntegeradd(BigInteger val)           返回其值为 (this + val) 的 BigInteger。
 BigIntegerand(BigInteger val)           返回其值为 (this & val) 的 BigInteger。
 BigIntegerandNot(BigInteger val)           返回其值为 (this & ~val) 的 BigInteger。
 intbitCount()           返回此 BigInteger 的二进制补码表示形式中与符号不同的位的数量。
 intbitLength()           返回此 BigInteger 的最小的二进制补码表示形式的位数,不包括 符号位。
 BigIntegerclearBit(int n)           返回其值与清除了指定位的此 BigInteger 等效的 BigInteger。
 intcompareTo(BigInteger val)           将此 BigInteger 与指定的 BigInteger 进行比较。
 BigIntegerdivide(BigInteger val)           返回其值为 (this / val) 的 BigInteger。
 BigInteger[]divideAndRemainder(BigInteger val)           返回包含 (this / val) 后跟 (this % val) 的两个 BigInteger 的数组。
 doubledoubleValue()           将此 BigInteger 转换为 double
 booleanequals(Object x)           比较此 BigInteger 与指定的 Object 的相等性。
 BigIntegerflipBit(int n)           返回其值与对此 BigInteger 进行指定位翻转后的值等效的 BigInteger。
 floatfloatValue()           将此 BigInteger 转换为 float
 BigIntegergcd(BigInteger val)           返回一个 BigInteger,其值是 abs(this)abs(val) 的最大公约数。
 intgetLowestSetBit()           返回此 BigInteger 最右端(最低位)1 比特的索引(即从此字节的右端开始到本字节中最右端 1 比特之间的 0 比特的位数)。
 inthashCode()           返回此 BigInteger 的哈希码。
 intintValue()           将此 BigInteger 转换为 int
 booleanisProbablePrime(int certainty)           如果此 BigInteger 可能为素数,则返回 true,如果它一定为合数,则返回 false
 longlongValue()           将此 BigInteger 转换为 long
 BigIntegermax(BigInteger val)           返回此 BigInteger 和 val 的最大值。
 BigIntegermin(BigInteger val)           返回此 BigInteger 和 val 的最小值。
 BigIntegermod(BigInteger m)           返回其值为 (this mod m) 的 BigInteger。
 BigIntegermodInverse(BigInteger m)           返回其值为 (this-1 mod m) 的 BigInteger。
 BigIntegermodPow(BigInteger exponent, BigInteger m)           返回其值为 (thisexponent mod m) 的 BigInteger。
 BigIntegermultiply(BigInteger val)           返回其值为 (this * val) 的 BigInteger。
 BigIntegernegate()           返回其值是 (-this) 的 BigInteger。
 BigIntegernextProbablePrime()           返回大于此 BigInteger 的可能为素数的第一个整数。
 BigIntegernot()           返回其值为 (~this) 的 BigInteger。
 BigIntegeror(BigInteger val)           返回其值为 `(thisval)` 的 BigInteger。
 BigIntegerpow(int exponent)           返回其值为 (thisexponent) 的 BigInteger。
static BigIntegerprobablePrime(int bitLength, Random rnd)           返回有可能是素数的、具有指定长度的正 BigInteger。
 BigIntegerremainder(BigInteger val)           返回其值为 (this % val) 的 BigInteger。
 BigIntegersetBit(int n)           返回其值与设置了指定位的此 BigInteger 等效的 BigInteger。
 BigIntegershiftLeft(int n)           返回其值为 (this << n) 的 BigInteger。
 BigIntegershiftRight(int n)           返回其值为 (this >> n) 的 BigInteger。
 intsignum()           返回此 BigInteger 的正负号函数。
 BigIntegersubtract(BigInteger val)           返回其值为 (this - val) 的 BigInteger。
 booleantestBit(int n)           当且仅当设置了指定的位时,返回 true
 byte[]toByteArray()           返回一个 byte 数组,该数组包含此 BigInteger 的二进制补码表示形式。
 StringtoString()           返回此 BigInteger 的十进制字符串表示形式。
 StringtoString(int radix)           返回此 BigInteger 的给定基数的字符串表示形式。
static BigIntegervalueOf(long val)           返回其值等于指定 long 的值的 BigInteger。
 BigIntegerxor(BigInteger val)           返回其值为 (this ^ val) 的 BigInteger。

BigDecimal (Java 2 Platform SE 6)

java.math 类 BigDecimal

java.lang.Object
  java.lang.Number
      java.math.BigDecimal

  •   public class BigDecimal
      extends Number
      implements Comparable<BigDecimal>
    

不可变的、任意精度的有符号十进制数。BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂。因此,BigDecimal 表示的数值是 (unscaledValue × 10-scale)

BigDecimal 类提供以下操作:算术、标度操作、舍入、比较、哈希算法和格式转换。toString() 方法提供 BigDecimal 的规范表示形式。

BigDecimal 类使用户能完全控制舍入行为。如果未指定舍入模式,并且无法表示准确结果,则抛出一个异常;否则,通过向该操作提供适当的 MathContext 对象,可以对已选择的精度和舍入模式执行计算。在任何情况下,可以为舍入控制提供八种舍入模式。使用此类(例如,ROUND_HALF_UP)中的整数字段来表示舍入模式已过时;应改为使用 RoundingMode enum(例如,RoundingMode.HALF_UP)的枚举值。

当为 MathContext 对象提供 0 的精度设置(例如,MathContext.UNLIMITED)时,算术运算是准确的,它们是不采用任何 MathContext 对象的算术方法。(这是第 5 版之前的版本支持的唯一行为。)为了计算准确结果,不使用附带 0 精度设置的 MathContext 对象的舍入模式设置,因此与该对象无关。在除法中,准确的商可能是一个无限长的十进制扩展;例如,1 除以 3 所得的商。如果商具有无穷的十进制扩展,但是指定了该操作返回准确结果,则抛出 ArithmeticException。否则,像其他操作那样,返回除法运算的准确结果。

当精度设置不为 0 时,BigDecimal 算法的规则完全符合 ANSI X3.274-1996 和 ANSI X3.274-1996/AM 1-2000( 7.4 节)中定义的算法的可选操作模式。与上述标准不同,BigDecimal 包括多种舍入模式,它们对于版本 5 以前的 BigDecimal 版本中的除法是强制性的。这些 ANSI 标准和 BigDecimal 规范之间的任何冲突都按照有利于 BigDecimal 的方式进行解决。

由于同一数值可以有不同的表示形式(具有不同的标度),因此运算和舍入的规则必须同时指定数值结果和结果表示形式中所用的标度。

一般情况下,当准确结果(在除法中,可能有无限多位)比返回的数值具有更多位数时,舍入模式和精度设置确定操作如何返回具有有限位数的结果。 首先,MathContextprecision 设置指定要返回的总位数;这确定了结果的精度。位数计数从准确结果的最左边的非零数字开始。舍入模式确定丢弃的尾部位数如何影响返回的结果。

对于所有算术运算符,运算的执行方式是,首先计算准确的中间结果,然后,使用选择的舍入模式将其舍入为精度设置(如有必要)指定的位数。如果不返回准确结果,则将丢弃准确结果的某些数位。当舍入增加了返回结果的大小时,前导数字“9”的进位传播可能会创建新的数位。例如,将值 999.9 舍入为三位数字,则在数值上等于一千,表示为 100×101。在这种情况下,新的 "1" 是返回结果的前导数位。

除了逻辑的准确结果外,每种算术运算都有一个表示结果的首选标度。下表列出了每个运算的首选标度。

运算结果的首选标度
max(addend.scale(), augend.scale())
max(minuend.scale(), subtrahend.scale())
multiplier.scale() + multiplicand.scale()
dividend.scale() - divisor.scale()

这些标度是返回准确算术结果的方法使用的标度;准确相除可能必须使用较大的标度除外,因为准确的结果可能有较多的位数。例如,1/32 得到 0.03125

舍入之前,逻辑的准确中间结果的标度是该运算的首选标度。如果用 precision 位数无法表示准确的数值结果,则舍入会选择要返回的一组数字,并将该结果的标度从中间结果的标度减小到可以表示实际返回的 precision 位数的最小标度。如果准确结果可以使用最多 precision 个数字表示,则返回具有最接近首选标度的标度的结果表示形式。尤其是,通过移除结尾零并减少标度,可以用少于 precision 个数字来表示准确的可表示的商。例如,使用 floor 舍入模式将结果舍入为三个数字,
19/100 = 0.19 // integer=19, scale=2
但是
21/110 = 0.190 // integer=190, scale=3

注意,对于加、减和乘,标度的缩减量将等于丢弃的准确结果的数字位置数。如果舍入导致进位传播创建一个新的高位,则当未创建新的数位时,会丢弃该结果的附加数字。

其他方法可能与舍入语义稍微不同。例如,使用指定的算法pow 方法得到的结果可能偶尔不同于舍入得到的算术结果,如最后一位有多个单位(ulp)。

可以通过两种类型的操作来处理 BigDecimal 的标度:标度/舍入操作和小数点移动操作。标度/舍入操作(setScaleround)返回 BigDecimal,其值近似地(或精确地)等于操作数的值,但是其标度或精度是指定的值;即:它们会增加或减少对其值具有最小影响的存储数的精度。小数点移动操作(movePointLeftmovePointRight)返回从操作数创建的 BigDecimal,创建的方法是按指定方向将小数点移动一个指定距离。

为了简洁明了起见,整个 BigDecimal 方法的描述中都使用了伪代码。伪代码表达式 (i + j) 是“其值为 BigDecimal iBigDecimal jBigDecimal”的简写。伪代码表达式 (i == j) 是“当且仅当 BigDecimal i 表示与 BigDecimal j 相同的值时,则为 true”的简写。可以类似地解释其他伪代码表达式。方括号用于表示特定的 BigInteger 和定义 BigDecimal 值的标度对;例如,[19, 2] 表示 BigDecimal 在数值上等于 0.19,标度是 2。

注:如果 BigDecimal 对象用作 SortedMap 中的键或 SortedSet 中的元素,则应特别小心,因为 BigDecimal自然排序 与 equals 方法不一致。有关更多信息,请参见 ComparableSortedMapSortedSet

当为任何输入参数传递 null 对象引用时,此类的所有方法和构造方法都将抛出 NullPointerException。 BigDecimal (Java 2 Platform SE 6)

方法摘要
 BigDecimalabs()           返回 BigDecimal,其值为此 BigDecimal 的绝对值,其标度为 this.scale()
 BigDecimalabs(MathContext mc)           返回其值为此 BigDecimal 绝对值的 BigDecimal(根据上下文设置进行舍入)。
 BigDecimaladd(BigDecimal augend)           返回一个 BigDecimal,其值为 (this + augend),其标度为 max(this.scale(), augend.scale())
 BigDecimaladd(BigDecimal augend, MathContext mc)           返回其值为 (this + augend)BigDecimal(根据上下文设置进行舍入)。
 bytebyteValueExact()           将此 BigDecimal 转换为 byte,以检查丢失的信息。
 intcompareTo(BigDecimal val)           将此 BigDecimal 与指定的 BigDecimal 比较。
 BigDecimaldivide(BigDecimal divisor)           返回一个 BigDecimal,其值为 (this / divisor),其首选标度为 (this.scale() - divisor.scale());如果无法表示准确的商值(因为它有无穷的十进制扩展),则抛出 ArithmeticException
 BigDecimaldivide(BigDecimal divisor, int roundingMode)           返回一个 BigDecimal,其值为 (this / divisor),其标度为 this.scale()
 BigDecimaldivide(BigDecimal divisor, int scale, int roundingMode)           返回一个 BigDecimal,其值为 (this / divisor),其标度为指定标度。
 BigDecimaldivide(BigDecimal divisor, int scale, RoundingMode roundingMode)           返回一个 BigDecimal,其值为 (this / divisor),其标度为指定标度。
 BigDecimaldivide(BigDecimal divisor, MathContext mc)           返回其值为 (this / divisor)BigDecimal(根据上下文设置进行舍入)。
 BigDecimaldivide(BigDecimal divisor, RoundingMode roundingMode)           返回一个 BigDecimal,其值为 (this / divisor),其标度为 this.scale()
 BigDecimal[]divideAndRemainder(BigDecimal divisor)           返回由两个元素组成的 BigDecimal 数组,该数组包含 divideToIntegralValue 的结果,后跟对两个操作数计算所得到的 remainder
 BigDecimal[]divideAndRemainder(BigDecimal divisor, MathContext mc)           返回由两个元素组成的 BigDecimal 数组,该数组包含 divideToIntegralValue 的结果,后跟根据上下文设置对两个操作数进行舍入计算所得到的 remainder 的结果。
 BigDecimaldivideToIntegralValue(BigDecimal divisor)           返回 BigDecimal,其值为向下舍入所得商值 (this / divisor) 的整数部分。
 BigDecimaldivideToIntegralValue(BigDecimal divisor, MathContext mc)           返回 BigDecimal,其值为 (this / divisor) 的整数部分。
 doubledoubleValue()           将此 BigDecimal 转换为 double
 booleanequals(Object x)           比较此 BigDecimal 与指定的 Object 的相等性。
 floatfloatValue()           将此 BigDecimal 转换为 float
 inthashCode()           返回此 BigDecimal 的哈希码。
 intintValue()           将此 BigDecimal 转换为 int
 intintValueExact()           将此 BigDecimal 转换为 int,以检查丢失的信息。
 longlongValue()           将此 BigDecimal 转换为 long
 longlongValueExact()           将此 BigDecimal 转换为 long,以检查丢失的信息。
 BigDecimalmax(BigDecimal val)           返回此 BigDecimalval 的最大值。
 BigDecimalmin(BigDecimal val)           返回此 BigDecimalval 的最小值。
 BigDecimalmovePointLeft(int n)           返回一个 BigDecimal,它等效于将该值的小数点向左移动 n 位。
 BigDecimalmovePointRight(int n)           返回一个 BigDecimal,它等效于将该值的小数点向右移动 n 位。
 BigDecimalmultiply(BigDecimal multiplicand)           返回一个 BigDecimal,其值为 (this × multiplicand),其标度为 (this.scale() + multiplicand.scale())
 BigDecimalmultiply(BigDecimal multiplicand, MathContext mc)           返回其值为 (this × multiplicand)BigDecimal(根据上下文设置进行舍入)。
 BigDecimalnegate()           返回 BigDecimal,其值为 (-this),其标度为 this.scale()
 BigDecimalnegate(MathContext mc)           返回其值为 (-this)BigDecimal(根据上下文设置进行舍入)。
 BigDecimalplus()           返回 BigDecimal,其值为 (+this),其标度为 this.scale()
 BigDecimalplus(MathContext mc)           返回其值为 (+this)BigDecimal(根据上下文设置进行舍入)。
 BigDecimalpow(int n)           返回其值为 (thisn)BigDecimal,准确计算该幂,使其具有无限精度。
 BigDecimalpow(int n, MathContext mc)           返回其值为 (thisn)BigDecimal
 intprecision()           返回此 BigDecimal精度
 BigDecimalremainder(BigDecimal divisor)           返回其值为 (this % divisor)BigDecimal
 BigDecimalremainder(BigDecimal divisor, MathContext mc)           返回其值为 (this % divisor)BigDecimal(根据上下文设置进行舍入)。
 BigDecimalround(MathContext mc)           返回根据 MathContext 设置进行舍入后的 BigDecimal
 intscale()           返回此 BigDecimal标度
 BigDecimalscaleByPowerOfTen(int n)           返回其数值等于 (this * 10n) 的 BigDecimal。
 BigDecimalsetScale(int newScale)           返回一个 BigDecimal,其标度为指定值,其值在数值上等于此 BigDecimal 的值。
 BigDecimalsetScale(int newScale, int roundingMode)           返回一个 BigDecimal,其标度为指定值,其非标度值通过此 BigDecimal 的非标度值乘以或除以十的适当次幂来确定,以维护其总值。
 BigDecimalsetScale(int newScale, RoundingMode roundingMode)           返回 BigDecimal,其标度为指定值,其非标度值通过此 BigDecimal 的非标度值乘以或除以十的适当次幂来确定,以维护其总值。
 shortshortValueExact()           将此 BigDecimal 转换为 short,以检查丢失的信息。
 intsignum()           返回此 BigDecimal 的正负号函数。
 BigDecimalstripTrailingZeros()           返回数值上等于此小数,但从该表示形式移除所有尾部零的 BigDecimal
 BigDecimalsubtract(BigDecimal subtrahend)           返回一个 BigDecimal,其值为 (this - subtrahend),其标度为 max(this.scale(), subtrahend.scale())
 BigDecimalsubtract(BigDecimal subtrahend, MathContext mc)           返回其值为 (this - subtrahend)BigDecimal(根据上下文设置进行舍入)。
 BigIntegertoBigInteger()           将此 BigDecimal 转换为 BigInteger
 BigIntegertoBigIntegerExact()           将此 BigDecimal 转换为 BigInteger,以检查丢失的信息。
 StringtoEngineeringString()           返回此 BigDecimal 的字符串表示形式,需要指数时,则使用工程计数法。
 StringtoPlainString()           返回不带指数字段的此 BigDecimal 的字符串表示形式。
 StringtoString()           返回此 BigDecimal 的字符串表示形式,如果需要指数,则使用科学记数法。
 BigDecimalulp()           返回此 BigDecimal 的 ulp(最后一位的单位)的大小。
 BigIntegerunscaledValue()           返回其值为此 BigDecimal非标度值BigInteger
static BigDecimalvalueOf(double val)           使用 Double.toString(double) 方法提供的 double 规范的字符串表示形式将 double 转换为 BigDecimal
static BigDecimalvalueOf(long val)           将 long 值转换为具有零标度的 BigDecimal
static BigDecimalvalueOf(long unscaledVal, int scale)           将 long 非标度值和 int 标度转换为 BigDecimal

10.数组

数组是存储相同类型数值的序列

10.1 声明数组

数组是一种数据结构,用来存储同类型值的集合.通过一个整型下标可以访问数组中的每一个值,eg:a[1];

在声明数组变量时,需要指出数组类型

int[] a;

数组一旦创建,无法改变其长度

如果程序运行中需要经常扩展数组的大小,就应该使用另一种数据结构--数组列表(array list)

int[] smallPrimes = {2, 3, 5, 7, 11, 13};  
  
for (int smallPrime : smallPrimes) {  
System.out.println("smallPrime = " + smallPrime);  
}  
  
// 数组的地址和长度  
System.out.println("smallPrimes = " + smallPrimes);  
System.out.println("smallPrimes.length = " + smallPrimes.length);

图片.png

10.2 数组拷贝

在Java中,数组拷贝是一个常见的操作,可以通过多种方式实现。以下是几种常用的数组拷贝方法:

1. 使用 System.arraycopy()

System.arraycopy() 是一个高效的方法,用于将一个数组的内容复制到另一个数组中。这个方法是原生的(native),因此性能非常好。

public class ArrayCopyExample {
    public static void main(String[] args) {
        int[] source = {1, 2, 3, 4, 5};
        int[] destination = new int[5];

        // 拷贝整个数组
        System.arraycopy(source, 0, destination, 0, source.length);

        // 打印目标数组
        for (int value : destination) {
            System.out.print(value + " ");
        }
    }
}
参数说明:
  • source:源数组。
  • srcPos:源数组中的起始位置。
  • destination:目标数组。
  • destPos:目标数组中的起始位置。
  • length:要复制的元素数量。

2. 使用 Arrays.copyOf()

Arrays.copyOf() 方法可以创建一个新的数组,并将指定数组的元素复制到新数组中。这个方法非常方便,特别是当你需要创建一个与原数组相同或不同大小的新数组时。

import java.util.Arrays;

public class ArrayCopyOfExample {
    public static void main(String[] args) {
        int[] source = {1, 2, 3, 4, 5};

        // 创建一个与源数组相同的新数组
        int[] copy = Arrays.copyOf(source, source.length);

        // 打印新数组
        System.out.println(Arrays.toString(copy));
    }
}
参数说明:
  • original:源数组。
  • newLength:新数组的长度。如果 newLength 大于源数组的长度,则新数组中超出的部分会被填充为默认值(对于基本类型是0,对于引用类型是null);如果 newLength 小于源数组的长度,则只复制前 newLength 个元素。

3. 使用 Arrays.copyOfRange()

Arrays.copyOfRange() 方法可以创建一个新的数组,并将指定范围内的元素从源数组复制到新数组中。

import java.util.Arrays;

public class ArrayCopyOfRangeExample {
    public static void main(String[] args) {
        int[] source = {1, 2, 3, 4, 5};

        // 创建一个包含源数组部分元素的新数组
        int[] copy = Arrays.copyOfRange(source, 1, 4);  // 包含索引1到3的元素

        // 打印新数组
        System.out.println(Arrays.toString(copy));  // 输出: [2, 3, 4]
    }
}
参数说明:
  • original:源数组。
  • from:开始索引(包含)。
  • to:结束索引(不包含)。

4. 使用循环手动拷贝

你也可以使用传统的 for 循环来逐个元素地进行拷贝。

public class ManualArrayCopyExample {
    public static void main(String[] args) {
        int[] source = {1, 2, 3, 4, 5};
        int[] destination = new int[source.length];

        // 使用for循环手动拷贝
        for (int i = 0; i < source.length; i++) {
            destination[i] = source[i];
        }

        // 打印目标数组
        for (int value : destination) {
            System.out.print(value + " ");
        }
    }
}

总结

  • System.arraycopy():适用于高效的数组拷贝。
  • Arrays.copyOf():适用于创建一个与源数组相同的新数组。
  • Arrays.copyOfRange():适用于创建一个包含源数组部分元素的新数组。
  • 手动循环拷贝:适用于简单的情况,或者当你需要自定义拷贝逻辑时。

选择哪种方法取决于你的具体需求和上下文。通常情况下,System.arraycopy()Arrays.copyOf() 是最常用且效率较高的方法。

10.3 多维数组

在Java中,多维数组是一种数组的数组。最常见的多维数组是二维数组(也称为矩阵),但你可以创建任意维度的数组。下面是一些关于如何声明、初始化和使用多维数组的基本信息。

1. 声明多维数组

二维数组
int[][] matrix;  // 声明一个二维整型数组
三维数组
int[][][] threeDimensionalArray;  // 声明一个三维整型数组

2. 初始化多维数组

二维数组
// 方法一:直接初始化
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

// 方法二:分步初始化
int[][] matrix = new int[3][3];  // 创建一个3x3的二维数组
matrix[0][0] = 1;
matrix[0][1] = 2;
matrix[0][2] = 3;
matrix[1][0] = 4;
matrix[1][1] = 5;
matrix[1][2] = 6;
matrix[2][0] = 7;
matrix[2][1] = 8;
matrix[2][2] = 9;

// 方法三:动态初始化行
int[][] matrix = new int[3][];  // 创建一个3行的二维数组
matrix[0] = new int[2];  // 第一行有2个元素
matrix[1] = new int[3];  // 第二行有3个元素
matrix[2] = new int[4];  // 第三行有4个元素
三维数组
// 直接初始化
int[][][] threeDimensionalArray = {
    {{1, 2}, {3, 4}},
    {{5, 6}, {7, 8}}
};

// 分步初始化
int[][][] threeDimensionalArray = new int[2][2][2];
threeDimensionalArray[0][0][0] = 1;
threeDimensionalArray[0][0][1] = 2;
threeDimensionalArray[0][1][0] = 3;
threeDimensionalArray[0][1][1] = 4;
threeDimensionalArray[1][0][0] = 5;
threeDimensionalArray[1][0][1] = 6;
threeDimensionalArray[1][1][0] = 7;
threeDimensionalArray[1][1][1] = 8;

3. 访问多维数组中的元素

二维数组
int value = matrix[1][2];  // 获取第二行第三列的值
matrix[1][2] = 10;  // 设置第二行第三列的值为10
三维数组
int value = threeDimensionalArray[1][0][1];  // 获取第二层第一行第二列的值
threeDimensionalArray[1][0][1] = 20;  // 设置第二层第一行第二列的值为20

4. 遍历多维数组

二维数组
for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        System.out.print(matrix[i][j] + " ");
    }
    System.out.println();
}
三维数组
for (int i = 0; i < threeDimensionalArray.length; i++) {
    for (int j = 0; j < threeDimensionalArray[i].length; j++) {
        for (int k = 0; k < threeDimensionalArray[i][j].length; k++) {
            System.out.print(threeDimensionalArray[i][j][k] + " ");
        }
        System.out.println();
    }
    System.out.println();
}

5. 多维数组的应用

  • 表格数据:二维数组非常适合表示表格数据,如电子表格或数据库表。
  • 图像处理:图像可以表示为二维数组,其中每个元素代表一个像素的颜色值。
  • 游戏开发:游戏中的地图或棋盘可以用二维数组来表示。
  • 科学计算:在科学计算中,多维数组常用于存储和操作多维数据集。

注意事项

  • 在使用多维数组时,要注意索引越界的问题。确保访问的索引在有效范围内。
  • 动态初始化多维数组时,每一维的大小可以不同。例如,在二维数组中,每一行可以有不同的列数。