第3章 变量与数据类型 第3章 变量与数据类型程序的核心是处理数据而数据要存放在容器里这个容器就是变量。本节学习 Java 中变量的定义方式与八种基本数据类型。一、什么是变量变量是内存中一块用于存储数据的空间它有名字变量名和类型决定能存什么数据、占多大空间。intage25;// 定义一个 int 类型变量存整数 25doubleprice9.9;// 定义一个 double 类型变量存小数 9.9Stringname小明;// 定义一个 String 类型变量存字符串基本语法类型 变量名 值;变量有三要素类型、名字、值。它最大的特点是可以重新赋值intage25;// 第一次赋值age26;// 重新赋值覆盖旧值System.out.println(age);// 输出26本系列统一按 JDK 8/11/17 三个版本讲解本节介绍的变量定义、数据类型、命名规则、类型转换三个版本的写法完全一致可以放心照着练习。二、基本数据类型8 种Java 的 8 种基本数据类型分为四类1. 整数类型4 种类型占字节取值范围byte1-128 ~ 127short2-32768 ~ 32767int4约 ±21 亿long8约 ±922 亿亿byteb100;inti1000000;longl10000000000L;// long 类型值后面要加 L 或 l整数默认类型是 int超出 int 范围时必须加L后缀。日常开发 90% 的整数都用 intlong 用于时间戳、金额分等大数据byte/short 只在节省内存的场景出现。2. 浮点类型2 种类型占字节说明float4单精度精度约 7 位有效数字double8双精度精度约 15 位有效数字floatf3.14F;// float 值要加 F 或 fdoubled3.14159265358979;小数默认类型是 double运算结果也默认是 double。金额计算不建议直接用浮点数会有精度问题后续讲解 BigDecimal 时再展开。double 是默认选择float 只在内存紧张时使用。为什么金额不能用浮点数因为浮点数是二进制近似存储0.1 0.2的结果并不是0.3扩展知识里有 BigDecimal 方案。3. 字符类型1 种charcA;// 单个字符用单引号charch中;// Java 支持 Unicode一个 char 能存一个汉字chartab\t;// 转义字符制表符字符类型占 2 字节底层存的是字符对应的 Unicode 编码。char 用单引号且只能有一个字符String 用双引号可有多个字符两者不要混淆char 底层是整数可参与算术运算扩展知识有示例。4. 布尔类型1 种booleanflagtrue;// 只有两个值true / falsebooleanisOkfalse;布尔类型常用于条件判断和循环控制后面会大量使用。它只有true/false两个值不能用 0/1 代替和 C 语言不同。三、引用类型除了 8 种基本类型其余都是引用类型类String、自己定义的类、数组、接口等。Stringname张三;// String 是引用类型int[]arr{1,2,3};// 数组是引用类型基本类型存值引用类型存地址指向堆内存中对象的位置这是两者最本质的区别——好比基本类型口袋里直接揣着现金引用类型手里只有一张写着地址的纸条钱存在别处。所以引用类型变量还可以不指向任何对象Stringsnull;// null 表示不指向任何对象对null调用方法会抛NullPointerException空指针异常后面章节会专门讲。四、变量命名规则必须遵守否则编译报错只能由字母、数字、下划线_、美元符$组成不能以数字开头不能是 Java 关键字如class、int、if大小写敏感Age和age是两个不同变量建议遵守编码规范变量名使用小驼峰studentAge、totalCount见名知意不用a、b、x这类无意义名字// ✅ 规范命名intstudentAge18;doubletotalPrice99.5;// ❌ 不规范命名int1age18;// 以数字开头编译报错intclass1;// class 是关键字编译报错五、类型转换1. 自动类型转换隐式小范围类型自动转为大范围类型byte → short → int → long → float → doubleinti100;longli;// int 自动转 longdoubledi;// int 自动转 double自动转换的规则是小转大、不丢数据方向固定byte → short → int → long → float → double以及char → int。注意int → float、long → float/double理论上也可能丢精度但 Java 依然允许。2. 强制类型转换显式大范围转小范围可能丢失精度必须显式强转doubled9.99;inti(int)d;// 结果为 9小数部分被丢弃强转是你告诉编译器我知道可能丢精度我负责语法上必须写(类型)。强转不仅丢小数超出目标范围还会溢出见易错点第 4 条。3. 运算中的自动提升inta5;doubleb2.0;// a b 的结果是 double因为 double 级别更高bytex1,y2;// x y 的结果是 intbyte、short、char 参与运算时自动提升为 int六、变量作用域变量从定义处开始到所在的花括号结束处失效publicclassDemo{inta1;// 成员变量整个类内可用publicvoidtest(){intb2;// 局部变量仅在 test() 方法内可用if(b0){intc3;// 仅在 if 块内可用}// System.out.println(c); // 编译错误c 已超出作用域}}注意局部变量必须初始化后才能使用成员变量有默认值。作用域的意义在于控制变量的可见范围、避免命名冲突——两个方法里可以各有各的i互不干扰。顺带提一下版本差异如果你用的是 JDK 11 或 JDK 17局部变量还可以用var声明类型由编译器根据初始值自动推断——比如var b 2;和int b 2;效果完全一样。JDK 8 不支持var必须写出完整类型所以本节示例都写完整类型。var只能用于局部变量而且必须有初始值正好呼应上面局部变量必须初始化后才能使用的规则。七、扩展知识1. 基本类型默认值与内存占用局部变量不初始化不能使用但成员变量类的属性不赋值也有默认值类型默认值byte / short / int / long0float / double0.0char‘\u0000’空字符booleanfalse验证一下成员变量写在类里、方法外publicclassDefaultValue{staticinti;// 成员变量有默认值staticdoubled;staticbooleanb;publicstaticvoidmain(String[]args){System.out.println(int 默认值i);// 输出int 默认值0System.out.println(double 默认值d);// 输出double 默认值0.0System.out.println(boolean 默认值b);// 输出boolean 默认值false}}2. Integer 缓存-128 ~ 127Java 对Integerint 的包装类做了个小优化-128 到 127 之间的整数会被缓存复用Integera127;Integerb127;System.out.println(ab);// 输出true 缓存范围内两个是同一个对象Integerc128;Integerd128;System.out.println(cd);// 输出false 超出缓存各自 new 了对象System.out.println(c.equals(d));// 输出true equals 比较值始终正确比较引用类型时比的是是不是同一个对象所以比较包装类的值永远用equals不要用。3. 用 BigDecimal 算钱别用浮点数前面提到0.1 0.2不等于0.3金额计算绝不允许这种误差解决方式是使用BigDecimalimportjava.math.BigDecimal;publicclassMoneyDemo{publicstaticvoidmain(String[]args){// 注意构造器传字符串不要传 double否则精度问题依旧BigDecimalpricenewBigDecimal(9.9);BigDecimalcountnewBigDecimal(3);System.out.println(price.multiply(count));// 输出29.7}}BigDecimal 能精确表示十进制小数适合金额、利息计算代价是性能慢、写法啰嗦只在精度敏感的领域使用。4. char 与 UnicodeJava 的 char 采用Unicode 编码所以一个 char 就能存下世界主流文字包括中文。除了直接写字符还能用\u加四位十六进制数表示charc1A;charc2\u4e2d;// 4e2d 是中的 Unicode 编码System.out.println(c1);// 输出ASystem.out.println(c2);// 输出中System.out.println((int)c1);// 输出65这对处理国际化文本、编码转换很有用比如判断字符是不是数字c 0 c 9本质是比较编码值大小。八、易错点1. long 忘加 L// ❌ 2000000000 超出 int 范围编译报错过大的整数longnum2000000000;// ✅ 加 L 后缀longnum2000000000L;2. float 忘加 F// ❌ 小数默认是 double不能直接赋给 float编译报错不兼容的类型floatf3.14;// ✅ 加 F 后缀floatf3.14F;3. char 用双引号// ❌ 双引号是字符串编译报错不兼容的类型charcA;// ✅ char 用单引号String 用双引号charcA;StringsA;4. 整数溢出// ❌ int 最大值加 1溢出变成负数intmax2147483647;System.out.println(max1);// 输出-2147483648// ✅ 预期会超范围时改用 longlongmax2147483647L1;System.out.println(max);// 输出21474836485. byte/short 超范围赋值// ❌ 128 超出 byte 范围-128 ~ 127编译报错byteb128;// ✅ 在范围内byteb127;6. 强制转换丢精度// ❌ 直接强转小数被无情丢弃3.99 变成 3doubleprice3.99;inti(int)price;// i 3// ✅ 需要四舍五入用 Math.round需要精确计算用 BigDecimalinti(int)Math.round(price);// i 4九、小结8 种基本类型byte、short、int、long、float、double、char、boolean整数默认 int小数默认 doublelong 加 Lfloat 加 F基本类型存值引用类型存地址小转大自动转换大转小强制转换金额计算用 BigDecimal包装类比较值用 equals局部变量必须初始化成员变量有默认值下一节学习运算符与表达式。下一篇第4章 运算符与表达式