## **一、实验名称** 数据类型与表达式部分 ## **二、实验目的及要求** 1. **第1章 page 4 基础训练2**: 当同一文件中含两个类时,访问另一类的静态属性 **目的**: 了解如何访问另一个类的静态属性。 2. **第二章 page10 基础练习1**: 变量的数据类型及赋值。 **目的**: 了解变量的赋值及转换问题。 3. **第二章 page11 基础练习2**: 典型运算符的使用 **目的**: 熟悉++和%运算符的使用。 ## **三、实验环境** 调试工具: IntelliJ IDEA 2024.3.2.2 (Ultimate Edition) 服务配置: openjdk 23.0.2 2025-01-21 OpenJDK Runtime Environment (build 23.0.2+7-58) OpenJDK 64-Bit Server VM (build 23.0.2+7-58, mixed mode, sharing) ## **四、实验设计** #### 1. 第1章 page 4 基础训练2: 当同一文件中含两个类时,访问另一类的静态属性 ```java public class My { public static void main(String[] args) { System.out.println(you.info); } } class you { static String info = "同学们好!"; } ``` **思考:** 1. 编译产生了两个类文件, 分别叫`My.class`和`you.class` image-20250302223608988 2. 因为you类中没有main方法, java以main方法作为程序的入口 ![image-20250302223916203](C:\Users\29701\AppData\Roaming\Typora\typora-user-images\image-20250302223916203.png) ```java public class My { public static void main(String[] args) { System.out.println(you.info); } } class you { static String info = "同学们好!"; public static void main(String[] args) { System.out.println(info); } } ``` 3. 重新编译后执行`java you`成功输出`同学们好!` image-20250302224016153 4. 将源程序名改为`you.java`之后无法通过编译, 报错如下: ` error: class My is public, should be declared in a file named My.java` 所以可以知道如果一个类被声明为 `public`(例如 `public class My`),那么 **文件名必须与 `public` 类的名称完全一致**,即文件名必须是 `My.java` image-20250302224215159 #### 2. 第二章 page10 基础练习1 ##### (1) 变量的定义与赋值 ```java public class p10_l1 { public static void main(String[] args) { int a = 20; boolean b = true; double c = 3.14159; char d = 'a'; System.out.println(a + "," + b + "," + c + "," + d); } } ``` 此时程序编译运行输出`20,true,3.14159,a`, 四种类型在一个print里面输出, 说明print中的`+`起到了将所有元素的输出作为字符串拼接在一起的作用 **思考** 1. 在a的定义语句下一行增加 `a = 123456789`后重新编译正常输出`123456789,true,3.14159,a`, 所以可以将123456789赋值给a 2. 可以通过另外一个转义字符`\`加在\前面即可将`\`赋值给d, 即: `d = '\\';` 重新编译运行后成功输出`123456789,true,3.14159,\` image-20250302224936749 ##### (2) 理解强制转换 ① 将a的赋值语句修改成 `int a = Math.random();` 后编译报错: `incompatible types: possible lossy conversion from double to int` . 原因应该是 `Math.random()`方法会生成一个double类型的数据, 无法赋值给定义为int类型的a ![image-20250302225141185](C:\Users\29701\AppData\Roaming\Typora\typora-user-images\image-20250302225141185.png) ② 改为 `int a = (int) Math.random();` 之后重新编译, 运行五次之后得到的输出结果均为 `0,true,3.14159,\` 也就是说在这五次中a都是0. 原因应该是使用`Math.random()`方法生成浮点数之后使用 `(int)` 进行强制类型转换向下取整, 使得a总为零 ![image-20250302225238988](C:\Users\29701\AppData\Roaming\Typora\typora-user-images\image-20250302225238988.png) ③ 改为 `int a = (int) (Math.random() * 100);` 之后多次运行, 发现输出a的值大致分布在0~100之间. 查询文档可知 `Math.random()` 方法产生的数据范围为[0,1)的double类型数据, `Math.random() * 100` 得到的数据范围则会是[0, 100). 然后经过强制类型转换为int后a为[0,99]的整数. ![image-20250302225338469](C:\Users\29701\AppData\Roaming\Typora\typora-user-images\image-20250302225338469.png) **思考** `Math.random()`方法产生的是[0,1)的随机浮点数, 想要得到[10,90]的范围首先左边界无法通过乘法来得到, 所以在最外层需要加上+10. 此时我们需要生成的范围就是[0,80], 根据左闭右开的原则强制转换为int类型就是[0,81). [0,1) -> [0,81), 所以再需要再`random()`生成的数上载乘以81 所以最终是`int a = (int) (Math.random() * 81) + 10;` 能得到[10,90]的数据 ![image-20250302225446812](C:\Users\29701\AppData\Roaming\Typora\typora-user-images\image-20250302225446812.png) #### 第二章 page11 基础练习2: 典型运算符的使用 ##### (1) 理解++运算符的位置差异 ```java public class p11_l2 { public static void main(String[] args) { int a = 20; int b = a++; System.out.println(a + "," + b); } } ``` 此时编译运行的输出为 `21,20` , 将 `int b = a++` 改为 `int b = ++a`后, 得到输出结果 `21,21` `a++`和`++a`的相同性在于: 他们都等价于 `a += 1` 不同性在于: `a++` 是执行完这条指令之后再将`a+=1`, `++a` 是执行这条指令之前将`a+=1` ![image-20250302230035483](C:\Users\29701\AppData\Roaming\Typora\typora-user-images\image-20250302230035483.png) ##### (2) 理解求余运算 ```java public class p11_l2 { public static void main(String[] args) { int a = 20; int b = (int) 3.65; System.out.println(a % b); } } ``` 该程序编译运行得到结果 `2` 将b的赋值修改 `double b = 3.2` 之后重新编译运行得到结果 `0.7999999999999989` 总结出混合类型运算的规律: 当运算中存在更高级的数据类型, 运算结果将和更高级的数据类型相同 通过数据语句改成 `System.out.printf("%.2f\n", a % b);` 得到输出结果 `0.80` ![image-20250302230355634](C:\Users\29701\AppData\Roaming\Typora\typora-user-images\image-20250302230355634.png) #### 3. 第二章 page13 编程练习1 输入一个圆柱体的高和底面半径,求其体积,输出结果精确到小数点后3位 ```java import java.util.Scanner; public class p13_e1 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入圆柱体的高"); double h = sc.nextDouble(); System.out.println("请输入圆柱体底面半径"); double r = sc.nextDouble(); double v = Math.PI * r * r * h; System.out.println("圆柱体的体积是"); System.out.printf("%.3f",v); sc.close(); } } ``` 编译运行, 设定高为5, 底面半径为2.5, 得到输出: ``` 请输入圆柱体的高 5 请输入圆柱体底面半径 2.5 圆柱体的体积是 98.175 ``` 经过计算器验算结果正确 ![image-20250302230715731](C:\Users\29701\AppData\Roaming\Typora\typora-user-images\image-20250302230715731.png) ## **五、实验体会** **遇到的问题: ** 1. **数据类型转换错误** `Math.random()`返回`double`, 不能直接赋值给`int`, 强制转换`(int) Math.random()`后总为0. 调整为`(int) (Math.random() * 100)`后, 成功生成0~99的随机整数. 另外的总结, 数据类型转换, 从高级到低级(比如double到int)就必须要强制类型转换, 从低级到高级(如byte到int)就不需要手动进行强制转换, 而是被自动地隐式转换了. 2. **`++`运算符位置差异** `a++`先赋值后递增, `++a`先递增后赋值, 在循环和逻辑判断中需注意区别. 3. **求余运算的浮点误差** `a % b`在`b`为浮点数时可能出现精度误差, 使用`System.out.printf("%.2f", a % b);`格式化输出可避免问题. 总而言之, 本次实验加深了我对Java数据类型, 运算符, 输入输出的理解, 并通过调试解决了类型转换, 浮点误差, 格式控制等问题, 体会到细节对程序正确性的重要性.