Java基础---数据类型与变量、运算符、逻辑控制

Java 基础:数据类型与变量、运算符、逻辑控制

一、数据类型与变量

1.1 字面常量 (Literal Constants)

在 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 不能直接打印,通常用于引用类型
    }
}

字面常量的分类:

  1. 字符串常量:由 "" 括起来的,例如 "12345""hello""你好"
  2. 整型常量:程序中直接写的整数(没有小数点),例如 1001000
  3. 浮点数常量:程序中直接写的小数,例如 3.140.49
  4. 字符常量:由 单引号 '' 括起来的单个字符,例如 'A''1'
  5. 布尔常量:只有两种值,truefalse
  6. 空常量null。代表不指向任何对象的引用。

1.2 数据类型 (Data Types)

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

注意:

  • 不论是 32 位还是 64 位 Java 虚拟机 (JVM),int 都占 4 个字节,long 都占 8 个字节。
  • 整型和浮点型都是带有符号的(能表示负数)。
  • 整型字面量默认为 int 类型,浮点字面量默认为 double 类型。如果要表示 long 类型常量,需在数字后加 Ll (推荐 L),例如 100L。要表示 float 类型常量,需在数字后加 Ff,例如 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"
    }
}

1.3 变量 (Variables)

① 概念:

对于程序中可能改变的内容,我们使用变量来存储。数据类型就是用来定义不同种类变量的。

② 语法格式:

数据类型 变量名 = 初始值;
  • 数据类型: 指定变量能存储什么类型的数据 (如 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

1.4 类型转换 (Type Conversion)

Java 是一个强类型编程语言,当不同类型之间的变量相互赋值或参与运算时,会有严格的校验。

int a = 10;
long b = 100L; // L 表示这是一个 long 类型的字面量

// 小范围类型 -> 大范围类型
b = a; // 编译通过,int(4字节) 赋值给 long(8字节)

// 大范围类型 -> 小范围类型 (可能丢失精度)
// a = b; // 编译失败!错误: 不兼容的类型: 从long转换到int可能会有损失

Java 中类型转换主要分为两类:

  1. 自动类型转换 (隐式转换)

    • 代码不需要任何处理,编译器会自动完成。
    • 特点:数据范围小的类型转换为数据范围大的类型时自动发生。
    • 转换规则 (按箭头方向自动转换):byte -> short -> int -> long -> float -> double
    • char -> int
  2. 强制类型转换 (显式转换)

    • 代码需要使用特定格式处理,不能自动完成。
    • 特点:数据范围大的类型转换为数据范围小的类型时需要使用。
    • 语法(目标类型) 变量名或值;
    • 风险:可能导致精度丢失数据溢出
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 (小数部分被截断,精度丢失)

1.5 类型提升 (Type Promotion)

在表达式计算时,为了保证精度,Java 会进行类型提升:

  1. 不同类型数据混合运算时:范围小的数据类型会自动提升为范围大的数据类型,然后进行运算。最终结果的类型是提升后的最高类型。

    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
    
  2. 小于 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范围内)
    

二、运算符 (Operators)

2.1 算术运算符 (+, -, *, /, %)

用于执行基本的数学运算。

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

2.2 复合赋值运算符 (+=, -=, *=, /=, %=)

这些运算符是赋值运算符 (=) 和算术运算符的结合,可以简化代码。

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
    

2.3 关系运算符 (>, <, ==, !=, >=, <=)

用于比较两个值之间的关系,其运算结果是 boolean 类型 (truefalse)。

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

重要注意:

  • 在 Java 中,=赋值运算符,而 == 才是相等比较运算符
  • 关系运算符的结果只能是 truefalse
  • 不能像数学中那样连续书写比较,例如 3 < a < 5错误的写法。应使用逻辑运算符连接:(a > 3) && (a < 5)

2.4 逻辑运算符 (&&, ||, !)

用于对 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 中也有 &|。当操作数是布尔值时,它们也表示逻辑与和逻辑或,但不支持短路求值,即无论左侧结果如何,右侧总会被计算。通常推荐使用 &&|| 以利用短路特性。

2.5 自增/自减运算符 (++, --)

++ 是将变量的值加 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

注意:

  • 如果只是想让变量自增或自减 1,不参与其他运算,前置和后置没有区别。
  • 如果变量的值需要在同一个表达式中被使用,前置和后置就有显著区别。
  • 只有变量才能使用自增/自减运算符,常量或表达式结果不能使用 (例如 (a+b)++ 是错误的)。

三、逻辑控制 (Logic Control)

逻辑控制语句用于控制程序的执行流程,主要包括顺序结构、分支结构和循环结构。

3.1 顺序结构 (Sequential Structure)

程序按照代码书写的顺序,从上到下,一行一行地执行。这是最基本的结构。

System.out.println("第一步:开始");
System.out.println("第二步:执行操作 A");
System.out.println("第三步:执行操作 B");
System.out.println("第四步:结束");
// 运行结果按顺序输出
// 第一步:开始
// 第二步:执行操作 A
// 第三步:执行操作 B
// 第四步:结束

如果调整代码的书写顺序,执行顺序也随之改变。

3.2 分支结构 (Branching Structure)

根据条件的真假,选择性地执行某部分代码。

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,什么都不输出

最佳实践: 为了避免混淆和潜在错误,强烈建议 即使 ifelse 后面只有一条语句,也总是使用大括号 {}

// 推荐写法
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 通常也建议加上
}

执行流程:

  1. 计算 switch 后面括号中 表达式 的值。
  2. 将该值与每个 case 后面的 常量值 依次比较。
  3. 如果找到匹配的 case,则从该 case 开始执行其后的语句,直到遇到 break 语句跳出 switch,或者执行到 switch 语句的末尾。
  4. 如果没有任何 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,最终输出 "星期四")

3.3 循环结构 (Looping Structure)

用于重复执行某段代码,直到满足特定条件为止。

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

注意事项:

  1. if 类似,while 下面的语句如果只有一条,可以省略 {},但不推荐。
  2. while 后面的 { 建议和 while 写在同一行。
  3. 务必确保循环体内部有改变循环条件的语句,否则可能导致死循环 (循环条件永远为 true)。
  4. 注意 while 后面不要误写分号 ;,例如 while(condition); { ... },这会导致循环体永远无法执行(如果 condition 开始为 false)或死循环(如果 condition 开始为 true 且循环体本应改变它)。

for 循环

for 循环通常用于已知循环次数循环变量有规律变化的情况。

基本语法格式:

for (表达式①: 初始化; 布尔表达式②: 循环条件; 表达式③: 更新) {
    // 表达式④: 循环体语句;
}

执行流程:

  1. 执行 表达式① (初始化):通常用于声明和初始化循环控制变量。只在循环开始时执行一次
  2. 判断 布尔表达式② (循环条件):如果为 true,则执行循环体 表达式④;如果为 false,则结束循环。
  3. 执行 表达式④ (循环体):执行循环的主要操作。
  4. 执行 表达式③ (更新):通常用于修改循环控制变量。执行完更新后,跳转回第 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 语句之后的代码,并立即开始下一次**循环迭代。

  • whiledo-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);
}

3.4 输入输出 (Input/Output)

① 输出到控制台 (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 类来获取用户的键盘输入。

使用步骤:

  1. 导入 Scanner 类: 在代码文件的开头添加 import java.util.Scanner;
  2. 创建 Scanner 对象: Scanner sc = new Scanner(System.in); (关联标准输入流,即键盘)。
  3. 调用方法读取输入:
    • sc.nextLine(): 读取整行文本(直到按下回车),返回 String
    • sc.nextInt(): 读取一个整数,返回 int
    • sc.nextDouble(): 读取一个双精度浮点数,返回 double
    • sc.nextFloat(): 读取一个单精度浮点数,返回 float
    • sc.next(): 读取下一个单词(以空格分隔),返回 String
    • sc.hasNextInt(), sc.hasNextDouble() 等: 检查输入流中是否还有下一个指定类型的标记,返回 boolean,常用于循环读取。
  4. 关闭 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) 信号,从而结束循环。

你可能感兴趣的:(java,开发语言)