在 Java 程序中,直接写出来的值被称为字面常量。
public class Demo {
public static void main(String[] args) {
System.out.println("hello world!"); // 字符串常量
System.out.println(100); // 整型常量
System.out.println(3.14); // 浮点数常量
System.out.println('A'); // 字符常量
System.out.println(true); // 布尔常量
System.out.println(false); // 布尔常量
// System.out.println(null); // 空常量,null 不能直接打印,通常用于引用类型
}
}
字面常量的分类:
""
括起来的,例如 "12345"
、"hello"
、"你好"
。100
、1000
。3.14
、0.49
。''
括起来的单个字符,例如 'A'
、'1'
。true
和 false
。null
。代表不指向任何对象的引用。Java 中的数据类型主要分为两类:基本数据类型 (Primitive Types) 和 引用数据类型 (Reference Types)。
基本数据类型有四类八种:
四类:整型、浮点型、字符型、布尔型
八种:
类型 | 关键字 | 占用字节 | 取值范围 | 默认值 |
---|---|---|---|---|
字节型 | byte |
1 | [-128, 127] | 0 |
短整型 | short |
2 | [-32768, 32767] | 0 |
整型 | int |
4 | [-2^31, 2^31 - 1] (约21亿) | 0 |
长整型 | long |
8 | [-2^63, 2^63 - 1] | 0L |
单精度浮点型 | float |
4 | ±3.40E+38 | 0.0f |
双精度浮点型 | double |
8 | ±1.79E+308 | 0.0d |
字符型 | char |
2 | [0, 65535] (Unicode) | ‘\u0000’ |
布尔型 | boolean |
未规定(通常1) | true / false |
false |
注意:
int
都占 4 个字节,long
都占 8 个字节。int
类型,浮点字面量默认为 double
类型。如果要表示 long
类型常量,需在数字后加 L
或 l
(推荐 L
),例如 100L
。要表示 float
类型常量,需在数字后加 F
或 f
,例如 3.14F
。String
) 属于引用类型,不包含在上述八种基本类型中。字符串类型 (String
):
在 Java 中使用 String
类定义字符串类型。
public class StringExample {
public static void main(String[] args) {
String s1 = "hello";
String s2 = " world";
System.out.println(s1);
System.out.println(s2);
// + 用于字符串时,表示拼接 (Concatenation)
System.out.println(s1 + s2); // 输出 "hello world"
}
}
① 概念:
对于程序中可能改变的内容,我们使用变量来存储。数据类型就是用来定义不同种类变量的。
② 语法格式:
数据类型 变量名 = 初始值;
数据类型
: 指定变量能存储什么类型的数据 (如 int
, double
, String
)。变量名
: 给变量起的名字,也称为标识符 (Identifier)。需要遵循命名规则 (例如,不能以数字开头,不能是关键字)。=
: 赋值运算符,表示将右侧的值赋给左侧的变量。初始值
: 变量第一次被赋予的值。public class VariableDemo {
public static void main(String[] args) {
int a = 10; // 定义整型变量 a,并初始化为 10
double d = 3.14; // 定义双精度浮点型变量 d,并初始化为 3.14
char c = 'A'; // 定义字符型变量 c,并初始化为 'A'
boolean b = true;// 定义布尔型变量 b,并初始化为 true
System.out.println(a); // 输出 10
System.out.println(d); // 输出 3.14
System.out.println(c); // 输出 A
System.out.println(b); // 输出 true
// 变量的值可以修改
a = 100; // 将 100 赋值给变量 a,a 中原来的值 10 被覆盖
System.out.println("a 修改后的值: " + a); // 输出 100
// 注意:可以在一行定义多个相同类型的变量
int a1 = 10, a2 = 20, a3 = 30;
System.out.println(a1); // 输出 10
System.out.println(a2); // 输出 20
System.out.println(a3); // 输出 30
}
}
重要注意: 在 Java 中,局部变量 (在方法内部定义的变量) 必须先初始化 (赋值) 才能使用,否则编译会报错。
// 编译错误示例
// int x;
// System.out.println(x); // 错误: 可能尚未初始化变量x
Java 是一个强类型编程语言,当不同类型之间的变量相互赋值或参与运算时,会有严格的校验。
int a = 10;
long b = 100L; // L 表示这是一个 long 类型的字面量
// 小范围类型 -> 大范围类型
b = a; // 编译通过,int(4字节) 赋值给 long(8字节)
// 大范围类型 -> 小范围类型 (可能丢失精度)
// a = b; // 编译失败!错误: 不兼容的类型: 从long转换到int可能会有损失
Java 中类型转换主要分为两类:
自动类型转换 (隐式转换):
byte
-> short
-> int
-> long
-> float
-> double
char
-> int
强制类型转换 (显式转换):
(目标类型) 变量名或值;
long bValue = 100L;
int aValue;
// aValue = bValue; // 编译错误
// 使用强制类型转换
aValue = (int) bValue; // 强制将 long 类型的 bValue 转换为 int 类型
System.out.println(aValue); // 输出 100
long largeLong = 10000000000L;
int intFromLargeLong = (int) largeLong;
System.out.println(intFromLargeLong); // 输出 1410065408 (数据溢出导致结果不正确)
double pi = 3.14;
int intPi = (int) pi;
System.out.println(intPi); // 输出 3 (小数部分被截断,精度丢失)
在表达式计算时,为了保证精度,Java 会进行类型提升:
不同类型数据混合运算时:范围小的数据类型会自动提升为范围大的数据类型,然后进行运算。最终结果的类型是提升后的最高类型。
int i = 10;
double d = 5.5;
// i 会被提升为 double 类型 (10.0),然后与 5.5 相加
double result = i + d; // result 的类型是 double
System.out.println(result); // 输出 15.5
小于 int
的类型运算时:对于 byte
, short
, char
这三种比 int
(4字节) 小的类型,在进行算术运算时 (如 +
, -
, *
, /
),会首先被提升为 int
类型,然后再参与运算。运算结果至少是 int
类型。
byte b1 = 10;
byte b2 = 20;
// byte b3 = b1 + b2; // 编译错误!b1和b2会先提升为int,相加结果是int类型
int b3 = b1 + b2; // 正确,用 int 类型接收结果
System.out.println(b3); // 输出 30
// 如果确实需要 byte 结果,需要强制转换
byte b4 = (byte) (b1 + b2);
System.out.println(b4); // 输出 30 (因为结果30在byte范围内)
+
, -
, *
, /
, %
)用于执行基本的数学运算。
int a = 20;
int b = 10;
int c = 3;
System.out.println(a + b); // 30 (加法)
System.out.println(a - b); // 10 (减法)
System.out.println(a * b); // 200 (乘法)
System.out.println(a / b); // 2 (整数除法,结果向下取整)
System.out.println(a / c); // 6 (20 / 3 = 6.66...,整数除法结果为 6)
System.out.println(a % b); // 0 (取模/求余数,20 除以 10 余 0)
System.out.println(a % c); // 2 (20 除以 3 余 2)
// 浮点数除法
double d1 = 20.0;
double d2 = 3.0;
System.out.println(d1 / d2); // 6.666666666666667
注意:
+
, -
, *
, /
, %
都是二元运算符,需要左右两个操作数。int / int
的结果仍然是 int
类型,会舍弃小数部分(向下取整)。%
(取模) 运算结果的符号与被除数的符号相同。例如 (-20) % 3
结果是 -2
。0
(/
, %
),否则会抛出运行时异常 ArithmeticException
。+=
, -=
, *=
, /=
, %=
)这些运算符是赋值运算符 (=
) 和算术运算符的结合,可以简化代码。
int a = 1;
a += 2; // 相当于 a = a + 2;
System.out.println(a); // 输出 3
a -= 1; // 相当于 a = a - 1;
System.out.println(a); // 输出 2
a *= 3; // 相当于 a = a * 3;
System.out.println(a); // 输出 6
a /= 3; // 相当于 a = a / 3;
System.out.println(a); // 输出 2
a %= 2; // 相当于 a = a % 2; (注意原始笔记这里写错了,应该是 %= 2)
System.out.println(a); // 输出 0 (2 除以 2 余 0)
注意:
short s = 10;
// s = s + 5; // 编译错误! s+5 结果是 int 类型
s += 5; // 编译通过! 相当于 s = (short)(s + 5);
System.out.println(s); // 输出 15
>
, <
, ==
, !=
, >=
, <=
)用于比较两个值之间的关系,其运算结果是 boolean
类型 (true
或 false
)。
int a = 10;
int b = 20;
int c = 10;
System.out.println(a == b); // false (等于)
System.out.println(a == c); // true
System.out.println(a != b); // true (不等于)
System.out.println(a < b); // true (小于)
System.out.println(a > b); // false (大于)
System.out.println(a <= b); // true (小于等于)
System.out.println(a <= c); // true
System.out.println(a >= b); // false (大于等于)
System.out.println(a >= c); // true
重要注意:
=
是赋值运算符,而 ==
才是相等比较运算符。true
或 false
。3 < a < 5
是错误的写法。应使用逻辑运算符连接:(a > 3) && (a < 5)
。&&
, ||
, !
)用于对 boolean
类型的值进行运算,结果也是 boolean
类型。
&&
(AND): 两个操作数都为 true
时,结果才为 true
。||
(OR): 两个操作数至少有一个为 true
时,结果就为 true
。!
(NOT): 操作数为 true
时,结果为 false
;操作数为 false
时,结果为 true
。int a = 1;
int b = 2;
boolean c = true;
boolean d = false;
// 1. 逻辑与 (&&)
System.out.println((a == 1) && (b == 2)); // true && true -> true
System.out.println((a > 1) && (b == 2)); // false && true -> false
// 2. 逻辑或 (||)
System.out.println((a == 1) || (b > 2)); // true || false -> true
System.out.println((a > 1) || (b > 2)); // false || false -> false
// 3. 逻辑非 (!)
System.out.println(!(a == 1)); // !(true) -> false
System.out.println(!c); // !(true) -> false
System.out.println(!d); // !(false) -> true
短路求值 (Short-circuit Evaluation):
&&
和 ||
运算符遵循短路求值规则,这对于性能和避免错误很重要:
&&
:如果左侧表达式的值为 false
,则整个表达式的结果必定为 false
,不再计算右侧表达式。||
:如果左侧表达式的值为 true
,则整个表达式的结果必定为 true
,不再计算右侧表达式。int x = 10;
int y = 0;
// && 短路示例
// 因为 x > 20 为 false,所以 y++ 不会执行
boolean result1 = (x > 20) && (++y > 0);
System.out.println("result1: " + result1 + ", y: " + y); // 输出 result1: false, y: 0
// || 短路示例
// 因为 x == 10 为 true,所以 ++y > 0 不会执行
boolean result2 = (x == 10) || (++y > 0);
System.out.println("result2: " + result2 + ", y: " + y); // 输出 result2: true, y: 0
注意: Java 中也有 &
和 |
。当操作数是布尔值时,它们也表示逻辑与和逻辑或,但不支持短路求值,即无论左侧结果如何,右侧总会被计算。通常推荐使用 &&
和 ||
以利用短路特性。
++
, --
)++
是将变量的值加 1,--
是将变量的值减 1。它们是一元运算符。
根据运算符相对于变量的位置,分为前置和后置。
++a
, --a
): 先将变量的值加 1 (或减 1),然后使用变量新的值参与表达式运算。a++
, a--
): 先使用变量原来的值参与表达式运算,然后再将变量的值加 1 (或减 1)。int a = 1;
int b;
// 后置++
b = a++; // 1. 先使用 a 的原值(1) 赋值给 b (b=1)
// 2. 然后 a 自增 (a=2)
System.out.println("a=" + a + ", b=" + b); // 输出 a=2, b=1
int c = 1;
int d;
// 前置++
d = ++c; // 1. 先 c 自增 (c=2)
// 2. 然后使用 c 的新值(2) 赋值给 d (d=2)
System.out.println("c=" + c + ", d=" + d); // 输出 c=2, d=2
// 单独使用时,前置和后置效果一样
int e = 10;
e++; // e 变为 11
System.out.println("e=" + e); // 输出 11
int f = 10;
++f; // f 变为 11
System.out.println("f=" + f); // 输出 11
// -- 操作符与 ++ 类似
int g = 5;
int h = g--; // h=5, g=4
System.out.println("g=" + g + ", h=" + h); // 输出 g=4, h=5
int i = 5;
int j = --i; // i=4, j=4
System.out.println("i=" + i + ", j=" + j); // 输出 i=4, j=4
注意:
(a+b)++
是错误的)。逻辑控制语句用于控制程序的执行流程,主要包括顺序结构、分支结构和循环结构。
程序按照代码书写的顺序,从上到下,一行一行地执行。这是最基本的结构。
System.out.println("第一步:开始");
System.out.println("第二步:执行操作 A");
System.out.println("第三步:执行操作 B");
System.out.println("第四步:结束");
// 运行结果按顺序输出
// 第一步:开始
// 第二步:执行操作 A
// 第三步:执行操作 B
// 第四步:结束
如果调整代码的书写顺序,执行顺序也随之改变。
根据条件的真假,选择性地执行某部分代码。
① if
语句
有三种基本形式:
形式一:if
if (布尔表达式) {
// 条件为 true 时执行的语句
}
形式二:if-else
if (布尔表达式) {
// 条件为 true 时执行的语句
} else {
// 条件为 false 时执行的语句
}
形式三:if-else if-else
if (布尔表达式1) {
// 条件1 为 true 时执行
} else if (布尔表达式2) {
// 条件1 为 false,且条件2 为 true 时执行
} else if (布尔表达式3) {
// 条件1、2 为 false,且条件3 为 true 时执行
} // 可以有更多 else if
else {
// 以上所有条件都为 false 时执行 (可选)
}
示例: 判断一个数字是正数、负数还是零。
int num = -5;
if (num > 0) {
System.out.println(num + " 是正数");
} else if (num < 0) {
System.out.println(num + " 是负数");
} else {
System.out.println(num + " 是零");
}
// 输出: -5 是负数
悬垂 else
(Dangling else) 问题:
当 if
/ else
语句嵌套且省略大括号 {}
时,else
会与最近的未匹配的 if
结合。
int x = 10;
int y = 20; // 修改 y 的值以观察不同行为
if (x == 10) // 这个 if 没有大括号
if (y == 10)
System.out.println("aaa");
else // 这个 else 属于内层的 if (y == 10)
System.out.println("bbb");
// 当前 y=20,输出 "bbb"
// 如果 y=10,输出 "aaa"
// 如果 x!=10,什么都不输出
最佳实践: 为了避免混淆和潜在错误,强烈建议 即使 if
或 else
后面只有一条语句,也总是使用大括号 {}
。
// 推荐写法
if (x == 10) {
if (y == 10) {
System.out.println("aaa");
} else {
System.out.println("bbb");
}
}
② switch
语句
适用于根据一个表达式的确定值来选择执行路径的情况。
基本语法:
switch (表达式) {
case 常量值1:
// 语句块1;
break; // 可选,用于跳出 switch
case 常量值2:
// 语句块2;
break;
// ... 可以有多个 case
default: // 可选,所有 case 都不匹配时执行
// 默认语句块;
break; // default 中的 break 通常也建议加上
}
执行流程:
switch
后面括号中 表达式
的值。case
后面的 常量值
依次比较。case
,则从该 case
开始执行其后的语句,直到遇到 break
语句跳出 switch
,或者执行到 switch
语句的末尾。case
匹配,并且存在 default
子句,则执行 default
下的语句。如果 default
也不存在,则 switch
语句什么也不执行。重要特性与注意事项:
switch
表达式类型: 表达式的值类型可以是 byte
, short
, int
, char
。从 Java 7 开始,也支持 String
类型和枚举 (enum
) 类型。不支持 long
, float
, double
, boolean
。case
常量值: case
后面的值必须是常量或字面量,且类型必须与 switch
表达式的类型兼容。case
值不能重复。break
的作用: break
用于终止 switch
语句的执行。如果没有 break
,程序会继续执行下一个 case
的语句,这种现象称为 “穿透” (fall-through)。有时会利用穿透特性,但大多数情况需要 break
来分隔逻辑。default
子句: 是可选的,可以放在 switch
结构中的任何位置(但习惯上放在最后)。如果放在前面,执行完 default
的语句后若没有 break
,也会继续执行后面的 case
。示例:
int day = 3;
String dayName;
switch (day) {
case 1:
dayName = "星期一";
break;
case 2:
dayName = "星期二";
break;
case 3:
dayName = "星期三";
break; // 如果没有这个 break
case 4:
dayName = "星期四";
break;
case 5:
dayName = "星期五";
break;
case 6:
dayName = "星期六";
break;
case 7:
dayName = "星期日";
break;
default:
dayName = "无效的日期";
break; // default 里的 break 虽然逻辑上不是必须,但保持一致性
}
System.out.println(dayName); // 输出 "星期三" (如果 case 3 没有 break,会穿透到 case 4,最终输出 "星期四")
用于重复执行某段代码,直到满足特定条件为止。
① while
循环
基本语法格式:
// 可能先进行初始化操作
while (循环条件) { // 条件为 true 时执行循环体
// 循环体语句;
// 可能包含更新循环条件的语句
}
// 循环结束后执行这里的代码
执行流程: 先判断 循环条件
是否为 true
,如果是,则执行 循环体语句
,然后再回到条件判断;如果 循环条件
为 false
,则跳出循环,执行 while
后面的代码。
示例: 计算 1 到 100 的和。
int i = 1;
int sum = 0;
while (i <= 100) {
sum += i; // 累加
i++; // 更新循环变量,防止死循环
}
System.out.println("1到100的和是: " + sum); // 输出 5050
注意事项:
if
类似,while
下面的语句如果只有一条,可以省略 {}
,但不推荐。while
后面的 {
建议和 while
写在同一行。true
)。while
后面不要误写分号 ;
,例如 while(condition); { ... }
,这会导致循环体永远无法执行(如果 condition 开始为 false)或死循环(如果 condition 开始为 true 且循环体本应改变它)。② for
循环
for
循环通常用于已知循环次数或循环变量有规律变化的情况。
基本语法格式:
for (表达式①: 初始化; 布尔表达式②: 循环条件; 表达式③: 更新) {
// 表达式④: 循环体语句;
}
执行流程:
表达式①
(初始化):通常用于声明和初始化循环控制变量。只在循环开始时执行一次。布尔表达式②
(循环条件):如果为 true
,则执行循环体 表达式④
;如果为 false
,则结束循环。表达式④
(循环体):执行循环的主要操作。表达式③
(更新):通常用于修改循环控制变量。执行完更新后,跳转回第 2 步,重新判断循环条件。示例: 打印 0 到 4 的数字。
for (int i = 0; i < 5; i++) { // ① 初始化 i=0; ② 条件 i<5; ③ 更新 i++
System.out.println(i); // ④ 循环体
}
// 输出:
// 0
// 1
// 2
// 3
// 4
示例: 计算 1 到 100 的和 (使用 for)。
int totalSum = 0;
for (int j = 1; j <= 100; j++) {
totalSum += j;
}
System.out.println("1到100的和是: " + totalSum); // 输出 5050
注意: for
循环的初始化、条件、更新部分都可以省略,但分号 ;
必须保留。例如 for (;;)
是一个无限循环。
③ do-while
循环
基本语法格式:
// 可能先进行初始化操作
do {
// 循环体语句;
// 可能包含更新循环条件的语句
} while (循环条件); // 注意这里有一个分号
执行流程: 先执行一次 循环体语句
,然后判断 循环条件
。如果条件为 true
,则重复执行循环体;如果条件为 false
,则结束循环。
关键特点: do-while
循环至少会执行一次循环体,即使循环条件一开始就为 false
。
示例:
int k = 100; // 初始值使得条件 k<10 为 false
do {
System.out.println("Do-while executed, k = " + k);
k++;
} while (k < 10);
// 输出: Do-while executed, k = 100
// (循环体执行了一次,然后判断 100 < 10 为 false,循环结束)
④ break
语句
break
用于强制跳出当前所在的整个循环 (while
, for
, do-while
) 或 switch
语句。循环将立即终止,程序继续执行循环或 switch
之后的代码。
示例: 在 100 到 200 中找到第一个 3 的倍数。
int num = 100;
while (num <= 200) {
if (num % 3 == 0) {
System.out.println("找到了第一个 3 的倍数, 为: " + num);
break; // 找到后立即跳出 while 循环
}
num++;
}
// 执行结果: 找到了第一个 3 的倍数, 为: 102
⑤ continue
语句
continue
用于跳过当前循环体内**continue
语句之后的代码,并立即开始下一次**循环迭代。
while
和 do-while
中,continue
执行后会直接跳转到循环条件的判断。for
循环中,continue
执行后会先执行更新表达式 (表达式③),然后跳转到循环条件的判断 (表达式②)。示例: 打印 100 到 200 中所有 3 的倍数 (跳过不是 3 的倍数)。
int number = 100;
while (number <= 200) {
if (number % 3 != 0) {
number++; // **重要**: 在 continue 前必须更新条件变量,否则可能死循环
continue; // 跳过本次循环的后续语句 (println)
}
// 只有当 number 是 3 的倍数时,才会执行到这里
System.out.println("找到了 3 的倍数, 为: " + number);
number++; // 更新条件变量
}
// 使用 for 循环实现相同功能 (更简洁)
for (int i = 100; i <= 200; i++) {
if (i % 3 != 0) {
continue; // 跳过本次 println,直接执行 i++,然后判断 i <= 200
}
System.out.println("找到了 3 的倍数 (for), 为: " + i);
}
① 输出到控制台 (Console Output)
使用 System.out
对象进行输出。
常用方法:
// 1. 输出后换行
System.out.println("Hello, World!");
System.out.println(123);
System.out.println(3.14);
// 2. 输出后不换行
System.out.print("Hello, ");
System.out.print("Java!");
System.out.println(); // 输出一个换行
// 3. 格式化输出 (类似 C 语言的 printf)
String name = "Alice";
int age = 25;
double salary = 5000.50;
// %s: 字符串, %d: 十进制整数, %f: 浮点数, %.2f: 保留两位小数的浮点数, \n: 换行符
System.out.printf("姓名: %s, 年龄: %d, 工资: %.2f\n", name, age, salary);
// 输出: 姓名: Alice, 年龄: 25, 工资: 5000.50
println
输出内容后会自动添加换行符 \n
。print
输出内容后不添加换行符。printf
使用格式说明符 (%s
, %d
, %f
等) 来控制输出的格式。② 从键盘输入 (Keyboard Input)
Java 中常用 Scanner
类来获取用户的键盘输入。
使用步骤:
Scanner
类: 在代码文件的开头添加 import java.util.Scanner;
。Scanner
对象: Scanner sc = new Scanner(System.in);
(关联标准输入流,即键盘)。sc.nextLine()
: 读取整行文本(直到按下回车),返回 String
。sc.nextInt()
: 读取一个整数,返回 int
。sc.nextDouble()
: 读取一个双精度浮点数,返回 double
。sc.nextFloat()
: 读取一个单精度浮点数,返回 float
。sc.next()
: 读取下一个单词(以空格分隔),返回 String
。sc.hasNextInt()
, sc.hasNextDouble()
等: 检查输入流中是否还有下一个指定类型的标记,返回 boolean
,常用于循环读取。Scanner
对象: sc.close();
(释放资源,非常重要)。示例: 读取用户姓名、年龄、工资。
import java.util.Scanner; // 1. 导入 Scanner 类
public class ScannerDemo {
public static void main(String[] args) {
// 2. 创建 Scanner 对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入你的姓名:");
String name = sc.nextLine(); // 3. 读取姓名 (整行)
System.out.println("请输入你的年龄:");
int age = sc.nextInt(); // 3. 读取年龄 (整数)
System.out.println("请输入你的工资:");
double salary = sc.nextDouble(); // 3. 读取工资 (浮点数)
System.out.println("\n你的信息如下:"); // 加个换行美观
System.out.printf("姓名: %s\n年龄:%d\n工资:%.2f\n", name, age, salary);
// 4. 关闭 Scanner 对象
sc.close();
}
}
/* 执行与交互示例:
请输入你的姓名:
张三
请输入你的年龄:
18
请输入你的工资:
1000.75
你的信息如下:
姓名: 张三
年龄:18
工资:1000.75
*/
注意: nextInt()
等读取数值后,换行符 \n
仍留在缓冲区。如果紧接着调用 nextLine()
,它会读到这个换行符并立即返回一个空字符串。
解决方法: 在 nextInt()
等之后,显式调用一次 sc.nextLine()
来消耗掉那个换行符。
// ... 接上面的例子
int age = sc.nextInt();
sc.nextLine(); // 消耗掉 nextInt 留下的换行符
System.out.println("请输入你的地址:");
String address = sc.nextLine(); // 现在可以正确读取地址了
// ...
示例: 使用 Scanner
循环读取 N 个数字,并求其平均值。
import java.util.Scanner;
public class AverageCalculator {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
double sum = 0;
int count = 0;
System.out.println("请输入数字 (输入非数字结束):");
// 使用 hasNextDouble 检查是否还有下一个浮点数
while (sc.hasNextDouble()) {
double tmp = sc.nextDouble(); // 读取浮点数
sum += tmp;
count++;
}
if (count > 0) {
System.out.println("总和 sum = " + sum);
System.out.println("平均值 avg = " + (sum / count));
} else {
System.out.println("没有输入有效的数字。");
}
sc.close();
}
}
/* 执行与交互示例 (Windows):
请输入数字 (输入非数字结束):
10
20.5
30
abc <-- 输入非数字来结束
总和 sum = 60.5
平均值 avg = 20.166666666666668
*/
/* 执行与交互示例 (控制台输入结束信号):
请输入数字 (输入非数字结束):
10
40.0
50.5
^Z <-- 在 Windows 控制台按 Ctrl+Z 然后回车 (Linux/Mac 用 Ctrl+D) 来表示输入结束
总和 sum = 100.5
平均值 avg = 33.5
*/
注意事项: 当需要循环读取直到没有更多输入时,可以使用 hasNextXxx()
方法配合 Ctrl+Z
(Windows) 或 Ctrl+D
(Linux/Mac) 来模拟文件结束符 (EOF) 信号,从而结束循环。