00java语法基础

Java 第一讲《Java 语法基础》:动手动脑问题与课后实验整理


目录

  1. 动手动脑 1:运行 EnumTest.java,枚举类型怎么用?

  2. 动脑动手 2:原码、反码、补码与位运算

  3. 动脑动手 3:同名变量的 "屏蔽原则"(变量作用域)

  4. 动手动脑 4:基本类型转换图能得出什么结论?

  5. 动手实验 5:TestDouble.java 为什么算出 "意外" 结果?

  6. 动手动脑 6:"X+Y="+X+Y 的输出是什么?

  7. 课后实验:两数相加程序 Addition.java


1. 动手动脑 1:运行 EnumTest.java,枚举类型怎么用?

题目

仔细阅读示例 EnumTest.java,运行它并分析运行结果:你能得到什么结论?你掌握枚举类型的基本用法了吗?

代码

enum Size { SMALL, MEDIUM, LARGE }   // 枚举类型

public class EnumTest {
    public static void main(String[] args) {
        Size s = Size.SMALL;                 // 直接取值
        Size t = Size.valueOf("SMALL");      // 从字符串转枚举

        System.out.println(s);               // SMALL
        System.out.println(s == t);          // true
        System.out.println(s.equals(t));     // true

        // 枚举的 foreach 遍历
        for (Size v : Size.values()) {
            System.out.println(v);
        }
    }
}

结论

  • 枚举类型是引用类型,不属于原始数据类型;

  • 它的每个具体值都引用一个特定的对象,相同的值引用同一个对象;

  • 因此枚举变量可以直接用 == 比较,此时 == 和 equals() 结果等价;

  • 枚举可以用 values() 遍历,也可以用在 switch 语句中。


2. 动脑动手 2:原码、反码、补码与位运算

题目

查阅资料弄清原码、反码、补码的概念,然后编写示例程序,对正数、负数进行各种位操作(&、|、^、~、<<、>>),观察输出并与手工计算结果比对,看看 Java 中的数到底采用哪种码表示。

代码

public class BitTest {
    public static void main(String[] args) {
        int a = 5;    //  二进制  000...0101
        int b = -5;

        System.out.println("a       = " + a);
        System.out.println("b       = " + 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       = " + (~a));        // -6
        System.out.println("a << 1   = " + (a << 1));    // 10,左移一位相当于×2
        System.out.println("a >> 1   = " + (a >> 1));    // 2,右移一位相当于÷2

        // 直接看二进制表示(32 位)
        System.out.println("5 的二进制 : " + Integer.toBinaryString(a));
        System.out.println("-5 的二进制: " + Integer.toBinaryString(b));
    }
}

结论

运行后 -5 的二进制串是 11111111111111111111111111111011—— 高位全是 1,这正是补码的形式:

  • 原码:最高位是符号位,其余位表示绝对值;

  • 反码:正数不变,负数在原码基础上符号位不变、其余位取反;

  • 补码:正数不变,负数在反码基础上 +1。

Java 内部对有符号整数统一使用补码存储。补码的好处是:0 的表示唯一,且加减法可以统一处理(减法变成加上负数的补码),这也是为什么 ~5 = -6、-5 高位全 1。


3. 动脑动手 3:同名变量的 "屏蔽原则"(变量作用域)

题目

Java 变量遵循 "同名变量的屏蔽原则"。请自己编写测试代码,像示例一样有意识地在不同地方定义同名变量,看看输出的到底是哪个值。

代码

public class ScopeTest {
    public static void main(String[] args) {
        int x = 10;
        System.out.println("外层 x = " + x);   // 10

        {
            int x = 20;   // 内层块里定义同名变量,屏蔽外层的 x
            System.out.println("内层 x = " + x); // 20
        }

        System.out.println("外层 x = " + x);   // 10,内层的 x 已失效
    }
}

如果有成员变量和局部变量同名,局部变量同样会 "屏蔽" 成员变量:

class Demo {
    int x = 100;                 // 成员变量
    void show() {
        int x = 50;              // 局部变量,屏蔽成员变量
        System.out.println(x);   // 50;要用成员变量需写 this.x
    }
}

结论

  • 每个变量都有它的作用域(一对花括号 {} 内),出了作用域变量即失效;

  • 当内层作用域定义了与外层同名的变量时,内层变量会 ** 屏蔽(shadow)** 外层变量,在内层看到的是就近定义的那个;

  • 这就是 "同名变量的屏蔽原则"—— 使用变量时遵循就近匹配。


4. 动手动脑 4:基本类型转换图能得出什么结论?

题目

课件给出了一张类型自动转换方向图(标注了 "无精度损失" 和 "有精度损失" 两条路径)。查阅 Java 各基本数据类型所占位数和数值范围,你能得出什么结论?

各类型位数与范围

类型 位数 范围(约)
byte 8 −128 ~ 127
short 16 ±3.2 万
int 32 ±21 亿
long 64 ±9.2×10¹⁸
float 32 ±3.4×10³⁸(有效约 7 位)
double 64 ±1.8×10³⁰⁸(有效约 15 位)
char 16 0 ~ 65535

自动转换方向(无精度损失)

byte → short → int → long → float → double
              char ↗

结论

  1. 小范围 → 大范围可以自动转换(如 int → long → double),编译器自动完成,无精度损失;

  2. 大范围 → 小范围必须强制类型转换(如 double → int),可能丢失信息:

double d = 1234567890;
float f = (float) d;
System.out.println(f);   // 1.23456794E9,末尾已经不准了
  1. 一个容易踩的坑:long 是 64 位、float 只有 32 位,但 long → float 是自动转换的 —— 因为 float 表示范围更大,但尾数精度只有 23 位,大整数转成 float 时仍可能损失精度。所以 "自动转换" 不等于 "绝对安全"。

5. 动手实验 5:TestDouble.java 为什么算出 "意外" 结果?

题目

运行示例 TestDouble.java:你看到了什么输出?意外吗?为什么 double 运算得不到 "数学上精确" 的结果?怎样处理?

代码

public class TestDouble {
    public static void main(String[] args) {
        System.out.println(0.07 + 0.01);
        // 你以为是 0.08,实际输出:0.07999999999999999
    }
}

原因

计算机用 IEEE 754 浮点数标准存储 float/double,很多十进制小数(如 0.07、0.1)在二进制下是无限循环小数,只能被截断近似存储。因此用 double 做十进制精确运算(如金额)时,结果会有微小误差。

解决:BigDecimal(且要用字符串构造)

import java.math.BigDecimal;

public class TestBigDecimal {
    public static void main(String[] args) {
        // 正确:用字符串构造,才能保留十进制精度
        BigDecimal a = new BigDecimal("0.07");
        BigDecimal b = new BigDecimal("0.01");
        System.out.println(a.add(b));   // 0.08  精确

        // 错误:用 double 构造,传入的 double 本身已经不精确
        BigDecimal bad = new BigDecimal(0.07);
        System.out.println(bad);        // 0.0699999999999999977...
    }
}

课件特别提醒:构造

BigDecimal

时应传

字符串

而不是

double

,否则 double 本身的近似误差会被带进来。


6. 动手动脑 6:"X+Y="+X+Y 的输出是什么?

题目

int X = 100;
int Y = 200;
System.out.println("X+Y=" + X + Y);
System.out.println(X + Y + "=X+Y");

这两行分别输出什么?为什么?

分析与答案

+ 有两种含义:算术加法、字符串连接。只要 + 两边有一个是字符串,它就变成字符串连接;运算符结合性是从左到右。

  • 第一行 "X+Y=" + X:字符串 + int → "X+Y=100";再 + Y → "X+Y=100200"

  • 第二行 X + Y 先算(两个 int,算术加)= 300;再 + "=X+Y" → "300=X+Y"

所以输出为:

X+Y=100200
300=X+Y

如果希望第一行输出 X+Y=300,应给加法加括号:

System.out.println("X+Y=" + (X + Y));   // X+Y=300

小结

知识点 对应问题
枚举类型(引用类型、== 与 equals 等价) 动手动脑 1
原码 / 反码 / 补码、位运算(Java 用补码) 动脑动手 2
变量作用域、同名变量屏蔽(就近原则) 动脑动手 3
基本类型位数、自动 / 强制类型转换 动手动脑 4
double 精度误差、BigDecimal 精确计算 动手实验 5
+ 的双重含义、字符串连接从左到右 动手动脑 6

这些问题串起来正好覆盖了本讲主线:变量怎么存(数据类型与内存)、数据怎么算(运算符与类型转换)、数据怎么进出程序(输入输出)—— 把这三件事弄清楚,就迈出了 Java 语法基础的第一步。

posted @ 2026-10-08 12:44  maglevpotato  阅读(6)  评论(0)    收藏  举报