第一单元 · 终端、变量、输入 · 第 2 / 12 节
变量、类型与字符串拼接
用 int/double/char/boolean/String 保存数据,分清整数除法与小数除法,用 + 拼接字符串,用强制转换和 % 处理取整与余数。
把网页放左边,SSH 终端放右边。本节继续在终端里写 .java、编译、运行;所有代码都放在独立目录 ~/java-practice/lesson02,不碰 lesson01 的文件。
再提醒一次四种块:bash 块是要粘到终端的命令,java 块是源码,input 块是只读的输入示例,output 块是只读的程序输出;复制按钮只对前两种有效。
上一节 Hello 只会打印一句固定的话。这一节让程序记住数据:先给数据起名字、规定类型,再在后面的语句里使用。变量可以想成一个贴了标签的盒子:标签是变量名,盒子形状是类型,盒子里装的是值。Java 是“强类型”语言,盒子一旦声明成 int,就不能直接塞进 9.9 这样的小数;类型不匹配时编译器会拦住你。
| 类型 | 能存什么 | 字面量写法示例 |
|---|---|---|
int | 整数(没有小数点) | 18、-3、2026 |
double | 小数(双精度浮点数) | 9.9、12.5、3.0 |
char | 单个字符,用单引号 | 'A'、'中' |
boolean | 只有两个值:true / false | true、false |
String | 一串文字,用双引号 | "小安"、"你好" |
表里的“字面量”就是直接写在代码里的值,例如 18、9.9、'A'、"你好";它们不需要先读输入,也不是从变量里取出来的。double 是 Java 最常用的“浮点数”类型,浮点数就是带小数点的数。
String 不是八种基本类型之一,它是 Java 提供的文本类型;现在先把它当成“装一串文字的盒子”,第四单元再解释它和对象的关系。本节不需要键盘输入,所有值都直接写在源码里;下一节才用 Scanner 读终端输入。
$ 提示符;输出和输入示例没有复制按钮。已完成 0 / 6 步
第 1 步:建 lesson02 目录,写第一版 VarDemo.java
先建本节自己的目录,并保护可能存在的旧文件。下面这套动作和上一节一样,只是目录名、文件名换了;请仍然逐行读,不要因为“见过”就跳过。
$ source ~/java-practice/env.sh
$ mkdir -p ~/java-practice/lesson02
$ cd ~/java-practice/lesson02
$ pwd
$ if [ -e VarDemo.java ]; then mv VarDemo.java "VarDemo.java.bak.$(date +%s)"; fi
最后一行先检查 VarDemo.java 是否存在;存在就改名成带时间戳的备份,不存在就什么也不做。这样你之前写的内容不会被静默覆盖。
nano 仍然单独占一个命令块,避免它吞掉后面的编译命令:
$ nano VarDemo.java
打开后粘贴下面整份源码,按 Ctrl+O、Enter、Ctrl+X 保存退出。
public class VarDemo {
public static void main(String[] args) {
int age = 18;
double price = 9.9;
System.out.println(age);
System.out.println(price);
}
}
这份源码做了三件事:
int age = 18;:声明一个int类型的变量,名字叫age,并赋值为18。int是“整数”类型,不能存小数。double price = 9.9;:声明一个double类型的变量price,赋值为9.9。double用来存带小数点的数。System.out.println(age);:这里没有双引号,所以打印的是变量里保存的值,不是文字age。
= 在这里是“赋值”:把右边的值放进左边的变量,不是数学里的“相等”。判断相等要用 ==,下一节会看到。变量名习惯用小写开头的驼峰写法,例如 age、totalPrice;名字区分大小写。
第 2 步:编译运行,看变量值
先编译,再运行。命令仍然是 javac -encoding UTF-8 文件名.java 和 java 类名。
$ javac -encoding UTF-8 VarDemo.java
$ java VarDemo
屏幕上应该出现:
18
9.9
println(age) 打印 18,println(price) 打印 9.9。注意输出里没有 age、price 这些变量名,变量名只是给人和编译器看的标签,不会自动变成输出内容。想让输出带说明文字,就要用本页第 6 步会细讲的字符串拼接,例如 "年龄:" + age。
如果 javac 报 cannot find symbol,先检查变量名拼写和大小写;如果报 incompatible types,先检查等号右边的值能不能放进左边声明的类型。
第 3 步:认识 char、boolean 和 String
现在把文件整份替换成下面这份,一次认识另外三种常用类型。仍然是打开同一个文件、整份替换,不是追加。
$ nano VarDemo.java
public class VarDemo {
public static void main(String[] args) {
char grade = 'A';
boolean passed = true;
String name = "小安";
System.out.println(grade);
System.out.println(passed);
System.out.println(name);
}
}
保存退出后,编译运行:
$ javac -encoding UTF-8 VarDemo.java
$ java VarDemo
A
true
小安
三种类型逐个看:
char:单个字符,必须用单引号,例如'A'、'中'。'A'是一个字符;"A"是一个长度为 1 的字符串,两者类型不同。boolean:只有true和false两个值,不带引号。Java 的boolean不能用0/1代替;这一点和某些语言不同。String:一串文字,必须用双引号,例如"小安"。字符串里可以有空格、中文、标点,甚至空字符串""。
println 对这三种类型都能直接打印:char 原样打印字符,boolean 打印 true/false,String 打印引号里的内容(不打印引号本身)。
第 4 步:整数除法和小数除法不是一回事
这是初学者最常踩的坑之一。把文件整份替换成下面这份,先自己算一遍结果,再运行对照。
$ nano VarDemo.java
public class VarDemo {
public static void main(String[] args) {
int total = 17;
int people = 5;
System.out.println("整数除法:" + (total / people));
System.out.println("余数:" + (total % people));
System.out.println("先转 double:" + ((double) total / people));
double half = 7.0 / 2;
System.out.println("小数除法:" + half);
}
}
$ javac -encoding UTF-8 VarDemo.java
$ java VarDemo
整数除法:3
余数:2
先转 double:3.4
小数除法:3.5
规则:
int / int做整数除法,结果只保留整数部分,小数部分被直接丢掉(不是四舍五入)。17 / 5是3,不是3.4。%是取余,也叫求余数:17 % 5是2,因为 17 = 5 × 3 + 2。- 只要有一个操作数是
double,就做小数除法。(double) total / people先把total临时转成double,再除以people,得到3.4。 7.0 / 2里7.0是double,所以结果是3.5。写7 / 2则会得到3。
这里第一次出现 "文字" + 数值 的写法,它的作用是把文字和数字接起来;本节第 6 步会专门讲 + 的两种含义,现在先照着看输出即可。
第 5 步:强制转换与 %,处理“取整”和“余数”
(int) 写在值前面叫强制转换(cast):明确告诉编译器“我知道会丢小数,还是把它转成整数”。把文件整份替换成:
$ nano VarDemo.java
public class VarDemo {
public static void main(String[] args) {
double measured = 3.99;
int cut = (int) measured;
int apples = 23;
int bags = 5;
System.out.println("(int) 3.99 = " + cut);
System.out.println("23 / 5 = " + (apples / bags));
System.out.println("23 % 5 = " + (apples % bags));
System.out.println("先加再除:" + ((apples + 1) / bags));
}
}
$ javac -encoding UTF-8 VarDemo.java
$ java VarDemo
(int) 3.99 = 3
23 / 5 = 4
23 % 5 = 3
先加再除:4
要点:
(int) 3.99得到3,不是4。强制转换是截断小数部分,向零取整,不做四舍五入。23 / 5是4,因为整数除法只留整数部分;23 % 5是3,因为 23 = 5 × 4 + 3。(apples + 1) / bags先算括号里的24,再除以5,仍是整数除法,结果是4。括号改变的是运算顺序,不会自动把整数除法变成小数除法。- 如果想让
23 / 5得到4.6,要写成(double) apples / bags或23.0 / 5。
% 不只是“余数”,后面学循环时会用它判断奇偶、做周期;现在只要会算 a % b,并知道 b 不能是 0。
第 6 步:用 + 拼接字符串,分清加法和拼接
+ 有两个身份:两边都是数字时做加法;只要有一边是 String,就做字符串拼接,把两边转成文字接起来。把文件整份替换成:
$ nano VarDemo.java
public class VarDemo {
public static void main(String[] args) {
String name = "小安";
int score = 92;
System.out.println("姓名:" + name);
System.out.println("分数:" + score);
System.out.println("加分后:" + (score + 8));
System.out.println("没有括号:" + score + 8);
System.out.println("字母:" + 'A');
System.out.println("字符加数字:" + ('A' + 1));
}
}
$ javac -encoding UTF-8 VarDemo.java
$ java VarDemo
姓名:小安
分数:92
加分后:100
没有括号:928
字母:A
字符加数字:66
关键规则:
"姓名:" + name:左边是字符串,右边是字符串,直接拼接,得到姓名:小安。"分数:" + score:左边是字符串,右边是int,score被转成文字92再拼接,得到分数:92。"加分后:" + (score + 8):括号里的score + 8先做数字加法,得到100,再拼接,输出加分后:100。"没有括号:" + score + 8:+从左到右算。先算"没有括号:" + score,此时结果已经是字符串没有括号:92;再+ 8就变成拼接,得到没有括号:928。"字母:" + 'A':char和字符串拼接,得到字母:A。('A' + 1):括号里两边都是“能当数字算”的类型,char会按 Unicode 编码参与加法;Unicode 是给字符编号的标准,'A'的编号是 65,所以结果是66。想得到文字A1,要写成"" + 'A' + 1。
+ 的优先级和从左到右的结合方向是考试和调试都常考的点。Java 的算术优先级和数学一样(先乘除后加减),同级从左到右。记不住时加括号:想先做算术,就把算术表达式括起来。
常见错误
- **现象:
incompatible types: possible lossy conversion from double to int。原因:把小数赋给int,例如int price = 9.9;。先检查什么:这个变量是否真的只存整数;要存小数就改成double,确定要取整就用(int) 9.9并接受截断。** - **现象:
cannot find symbol,指向一个变量名。原因:变量名拼错、大小写不一致,或使用发生在声明之前。先检查什么:逐字对照声明行和使用行;Java 要求先声明、再使用。** - **现象:
unclosed character literal或unclosed string literal。原因:引号不配对,或该用双引号的地方用了单引号。先检查什么:char用单引号且只放一个字符;String用双引号;中文引号“”不是 Java 语法。** - **现象:
int除法得到3,但你以为会得到3.4。原因:两边都是int,执行的是整数除法。先检查什么:看除号两边类型;需要小数就把其中一个转成double,例如(double) a / b。** - **现象:
"总分:" + score + 8输出928,不是100。原因:+从左到右,先拼接成字符串,后面的8也被拼接。先检查什么:给算术部分加括号(score + 8)。** - **现象:
variable age might not have been initialized。原因:只声明了变量,没有赋值就使用。先检查什么:声明时直接赋值,或在使用前补一行age = 18;。** - **现象:
';' expected。原因:上一行末尾漏了分号。先检查什么:看报错指出的行号和上一行末尾。**
练习
- 声明三个变量:
String city = "杭州";、int days = 3;、double price = 12.5;,然后输出三行:目的地:杭州、天数:3、总价:37.5。先手算总价,再写程序核对。 - 不要运行,先判断下面两行分别输出什么,再写进程序验证:
System.out.println(1 + 2 + "3");System.out.println("1" + 2 + 3);
先自己写、先写预测,再展开答案。
提示 提示
第 1 题的总价是 price * days;字符串和数字拼接时,想先算乘法就加括号。第 2 题盯着 + 的从左到右顺序:先遇到数字还是先遇到字符串,结果会不同。
参考答案 对答案
第 1 题的一份完整源码:
public class TripDemo {
public static void main(String[] args) {
String city = "杭州";
int days = 3;
double price = 12.5;
System.out.println("目的地:" + city);
System.out.println("天数:" + days);
System.out.println("总价:" + (price * days));
}
}
运行输出:
目的地:杭州
天数:3
总价:37.5
第 2 题:1 + 2 + "3" 先算数字加法 1 + 2 得到 3,再和字符串 "3" 拼接,输出 33;"1" + 2 + 3 先拼接成 "12",再拼接 3,输出 123。两行都不是数学上的 6。
做到这里
做到这里今天可以停。你已经会用 int、double、char、boolean、String 声明变量,能读懂整数除法与小数除法的差别,会用 (int) 截断、用 % 取余,也能解释 + 什么时候是加法、什么时候是拼接。
本节还没有键盘输入,也没有 if、循环、数组或自定义方法。下一节 lesson03 才让程序用 Scanner 从终端读数据,并把本节的计算真正接到输入上。
来源 来源与改编说明(非官方)
主题参考:黑马程序员 Java 入门到起飞(BV17F411T7Ao,2022-04-27)P017–P025、P030–P032 的变量、数据类型、标识符、算术运算、类型转换、字符串和字符操作主题。本站为独立原创讲解,非官方站点/教材,未获授权,不逐字复刻视频或讲义;示例、错误清单与练习为原创补充。详见 source/SOURCE.md。
公开核对入口:
- 课程页:https://www.bilibili.com/video/BV17F411T7Ao/
- Oracle Java 教程 · 基本数据类型:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
- Oracle Java 教程 · 运算符:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
说明:本站是个人学习整理,不是官方教材;不包含原课程的书本、视频或受版权保护的整本内容。原课程与商标归其权利人。