零基础学Java第二天:变量、流程控制与首个交互程序
学Java第二天说实话我是有点慌的。所谓“中登”就是那种上有老下有小、发际线已经开始告急、但还硬着头皮啃新东西的中年人。昨天光是配置JDK和IDEA就折腾了半宿环境变量配了三回才跑通第一个Hello World今天坐下来继续学突然发现Java这东西特别“讲道理”——语法就是一堆明明白白的规则不玩玄学。第二天我给自己定的任务很朴素搞懂变量、数据类型、运算符和流程控制然后用这些知识写一个能交互的小程序。这篇文章就是给跟我一样零基础起步、或者学过但一直没系统敲过代码的朋友看的。今天的内容不碰面向对象、不碰集合框架只讲最基础的语法地基但我会把每一步“为什么这么做”都说清楚还会把我自己踩过的坑原原本本摆出来。学编程最怕的不是不会而是没人告诉你错在哪、怎么改。这篇就当是一个中登学Java的现场直播。1. 第二天怎么学先把路线理顺再动手1.1 为什么第二天不能继续只配环境我见过不少新手在环境配置这个环节耗了太久。今天装个JDK明天换个版本后天又研究编译器代码一行没写热情先耗光了。我的建议是环境能用就行版本别追新正式学习从“能跑通Hello World”那一刻就直接开始语法。第二天的核心不是工具而是让电脑按你的规则算数、做判断、反复执行同一件事——这就是程序的本质。第一天如果把Java比喻成学做饭那JDK只是把锅和灶台搬进厨房了。第二天才是真正学习“洗菜、切菜、下锅”的动作。只有开始写代码你才会知道编译器报错长什么样、分号漏了是什么感觉、变量的类型用错有多崩溃。这些体验配环境配得再熟练也学不到。1.2 我给自己排的学习路线我前一天晚上花了十分钟做了个简单计划第二天就按这个节奏走上午复习第一天的Hello World顺手把IDEA里项目结构看明白src、包名、类名这些概念混个脸熟。下午学习变量、八种基本类型、运算符这一点动手敲每学一个就在代码里跑一遍。晚上学if、switch、for、while然后用Scanner写一个带输入的BMI计算器作为第二天的综合小练习。这个顺序是有讲究的变量相当于“认字”运算符相当于“组词”流程控制相当于“造句”最后的综合案例相当于“写一段话”。初学者最容易犯的毛病是跳跃式学习今天看集合明天看线程结果连int和double都分不清。我告诉自己第二天就老老实实打地基。1.3 对抗遗忘的两个土办法中登学东西最大的敌人是遗忘。我用的办法很土但很有效一个是“错题本”每次编译报错我都把错误信息和对应代码粘到一个文档里标上原因另一个是“默写”睡前不看书自己把当天学的知识点用大白话写一遍写不出来的第二天早上再看。第二天学习结束时你大概率会有一个感受好像什么都会一点又好像什么都记不住。这太正常了。语法这东西不背十遍、不敲烂十次根本不算会。别灰心继续往下看。2. 变量与数据类型Java里的一切都是“盒子”2.1 变量的本质贴了标签的储物柜我学变量时喜欢把它想成储物柜。每个柜子里只能放一类东西柜门上都贴着一个名字。当你往柜子里放新东西时旧东西就被盖住了——变量只能存最新值。int age 30; age 31;这里age就是一个柜子第一次往里面放了30第二次换成31。记住一个关键点变量名是“名字”而真正的数据躺在内存里。你操作变量就是通过名字找到那块内存读取或修改里面的值。初学者不用管内存地址这些细节但脑子里要有“变量只是引用”这个概念后面学数组、对象时你会感谢现在的自己。Java是强类型语言什么意思就是每个变量在出生前就必须说清楚自己是什么类型不能一会儿存整数一会儿存字符串。这一开始觉得麻烦写多了反而觉得安心——类型不对编译器立刻告诉你总比运行时跑到一半才崩要强。2.2 八种基本类型先把常用的四个吃透Java有八种基本类型我列个表建议收藏类型占用字节取值范围用途byte1-128 ~ 127小整数文件流处理时常用short2-32768 ~ 32767极少用int4-21亿 ~ 21亿日常整数首选long8超极大整数时间戳、大数据量计数float4约±3.4E38一般不用精度差double8约±1.7E308小数优先用它char20 ~ 65535单个字符用单引号boolean1逻辑上true / false判断条件我学的时候只盯住了四个int、double、boolean、char。String不是基本类型它是类但日常使用频率极高所以我把它当“最熟悉的陌生人”先记着。重点说int。它的默认值是0范围大约21亿。我一开始不理解为什么要记范围直到我写了int num 2147483647; num num 1;结果num变成了-2147483648。这就是溢出。我当时整个人懵了后来才知道整数在内存里是二进制补码表示的最大值加一会翻到最小值。这个坑在工作中特别常见尤其是计算金额、统计数量时。处理大数要么用long要么用double谨慎点要么后期学BigDecimal。2.3 声明变量的几种写法我最开始看代码总觉得别人写得很随意其实规则非常固定。常见的有三种写法int a; // 先声明后赋值 a 10; int b 20; // 声明的同时赋值 int c 30, d 40; // 一行声明多个但不推荐第三种写法虽然合法但可读性差我建议不要用。另外一个非常容易踩的坑局部变量必须初始化才能使用。int e; System.out.println(e); // 编译报错variable e might not have been initialized我一开始很烦这个报错觉得编译器多管闲事。后来才明白这是Java在保护你。未初始化的变量到底存的是什么垃圾值编译器不知道干脆不让你用。这个特性在后面的“方法内局部变量”场景里尤其重要。2.4 命名的规矩和几个“狗皮膏药”式细节变量命名只有一个硬性规则不能以数字开头不能是Java关键字其他随你但行业通用的是小驼峰第一个单词首字母小写后面每个单词首字母大写。int myAge 18; // 推荐 int MyAge 18; // 不规范类名才这么写 int my_age 18; // 下划线风格Python常用Java里不推荐真正让新手栽跟头的不是命名而是这个小细节long类型的字面量要加Lfloat要加F。long big 123456789012345L; float f 3.14F;不加L编译器会认为123456789012345是int结果直接报“过大的整数”。不加F3.14会被当成double给float赋值就报精度损失。这俩坑我一天踩了七八回后来自动形成肌肉记忆见long就L见float就F。3. 运算符与表达式算数、判断和逻辑的混合操练3.1 算术运算符加、减、乘、除、取余Java有五个基本算术运算符、-、*、/、%。大部分人都以为这些是小学知识但Java里有两个反直觉的地方。第一整数相除结果还是整数小数部分直接丢掉。10除以3结果是3不是3.333。int result 10 / 3; // result 3如果你真想要小数至少让一边变成小数double result 10.0 / 3; // 结果是3.3333333333333335第二%是取余数。10 % 3结果是1。这个符号最大的用处是判断奇偶、判断整除后面写算法题几乎天天见面。int num 17; boolean isOdd num % 2 1; // true3.2 自增自减a和a到底差在哪这是第二天所有初学者都会卡半小时的经典问题。我先给结论a是“先使用后加1”a是“先加1后使用”。int a 5; int b a; // b 5a 6 int c 5; int d c; // d 6c 6核心区别在于整个表达式的结果值不同。我用个生活化类比a就像“先拍照后付钱”你先把当前的值交给别人自己再涨价a就像“先付款再拿货”价格先变了再交易。实际工作中我强烈建议不要在一个复杂表达式里混用自增自减。比如这样写int i 5; int result i i;最终结果是12还是我没算第二次就不敢猜了。这种代码没有任何人喜欢别秀操作拆成两行写它不香吗。3.3 比较运算符和逻辑运算符短路是真的秀比较运算符就是、!、、、、。最容易犯的错误是把写成等号是赋值双等号才是比较。这个错误编译器会报错但如果你在if条件里误写了一个赋值某些情况下编译器还不一定拦得住逻辑就彻底歪了。逻辑运算符有三个与、||或、!非。值得花力气理解的是“短路”机制。int a 10; if (a 5 a 20) { // 两个条件都满足走这里 }必须前后两个条件都为true整体才为true。但Java有优化如果第一个条件已经为false第二个条件根本不会执行。if (obj ! null obj.getName().equals(张三)) { // 安全不会空指针 }这句话我在工作时见过无数次。只要obj是null第一个条件为false第二个条件就不会执行空指针被巧妙地规避了。||同理第一个条件为true第二个就不执行了。理解这个机制后你写复杂多条件判断时的思路会清晰很多。3.4 类型转换自动转和强转的恩怨我第一天看到double d 3;时心里咯噔一下int不是不能直接赋给double吗实际上这是“自动类型转换”。规则很简单小范围可以自动转成大范围因为大类型装得下小类型。int a 100; double d a; // 没问题int自动变成double long l a; // 没问题反过来就不行大范围给小范围会丢数据必须强制转换。double d 3.99; int a (int) d; // a 3小数部分直接没了强制转换有个大坑不是四舍五入而是直接截断。3.99变成3-3.99变成-3。我以前天真地以为会变成4和-4结果被现场打脸。如果你要四舍五入得用Math.round方法这个后面学到工具类时再展开。另外char和int可以直接互相转因为char本质上是字符对应的Unicode编码。char c A; int code c; // code 65知道这个后面处理英文字母大小写转换时能省不少事。4. 流程控制让程序学会选择和循环4.1 if-else分支程序第一次有了“想法”学完变量和运算符你已经能让程序算数了但它永远是直线执行从第一行跑到最后一行。if-else打破了这个直线。int score 76; if (score 60) { System.out.println(及格了稳住); } else { System.out.println(没及格复习去); }几个容易犯的错必须说清楚悬空else。else总是跟最近的if配对不是跟缩进配对。如果你写了嵌套if再看结果经常怀疑人生。花括号风格。不管单行还是多行我都建议写花括号哪怕里面只有一句话。没有花括号的if后面只跟一行新手一压缩代码就屎山。条件顺序。把最容易满足的条件放前面还是把最具体的放前面经验是先判断边界条件再判断通用条件。比如判断成绩等级先判断是否超出100再判断优秀、良好这些。if (score 100 || score 0) { System.out.println(成绩不合法); } else if (score 90) { System.out.println(优秀); } else if (score 60) { System.out.println(及格); } else { System.out.println(不及格); }4.2 switch分支匹配后小心“一路穿到底”switch是另一种分支方式适合“拿一个值去匹配多个固定选项”的场景。int day 3; switch (day) { case 1: System.out.println(周一); break; case 2: System.out.println(周二); break; case 3: System.out.println(周三); break; default: System.out.println(其他); break; }新手最大的坑就是漏写break。如果不写break匹配到case 3后它会继续往下执行case 4、5……直到遇到break或switch结束。这叫“穿透”。我第一次写漏了输出结果是“周三周四……”直接惊呆。穿透行为并非完全没用有些场景故意利用它合并多个case但新手别学老实加break。JDK 7以后switch可以匹配字符串这在工作中很好用String fruit apple; switch (fruit) { case apple: System.out.println(苹果); break; case banana: System.out.println(香蕉); break; }4.3 for和while循环的两张脸循环学了之后程序才算真正有“自动化”的味道。我第二天晚上的代码量都是靠for循环刷出来的。for循环的结构是固定的初始化、条件、更新。// 打印1到5 for (int i 1; i 5; i) { System.out.println(i); }三要素缺一不可int i 1是起点i 5是终点i是步长。只要有一个写错要么死循环要么一次都不执行。我建议你手写几个变体练手比如打印偶数、倒序打印、累加求和。while适合“不知道循环多少次只知道满足条件就继续”的场景。int n 100; while (n 0) { n - 30; }如果条件从一开始就为falsewhile一次都不会执行。还有一种do-while至少会执行一次。记住这个区分while是“先判断后执行”do-while是“先执行后判断”。4.4 综合小练习打印九九乘法表我建议每个初学者都敲一遍九九乘法表它是嵌套循环的经典案例逻辑短但非常锻炼思维。for (int i 1; i 9; i) { for (int j 1; j i; j) { System.out.print(j x i (i * j) \t); } System.out.println(); // 每行结束后换行 }外层循环控制行数内层循环控制每行打印多少列。关键点在于内层循环的条件是j i不是j 9。我第一次写成了j 9打印出的是倒三角形哈哈哈。这个练习特别适合体会“循环嵌套时变量作用域”的感觉i在外层循环里定义内层循环能用它而j是内层循环自己的变量外层循环看不见它。5. 第一次“交互”用Scanner写一个BMI计算器5.1 先搞清楚IDEA里的项目结构第二天实操前我把IDEA的项目结构认真看了一眼。Java项目的基本组织是项目Project下面有包Package包下面有类Class。包名一般用公司域名反写或学习用的自定义名字比如com.study.demo。我们目前写的所有代码都放在.java文件里一个public类对应一个同名文件。有个血泪教训我必须说类名和文件名必须完全一致而且类名首字母大写。我第一天把类名写成了helloWorld文件叫HelloWorld一运行直接报错。IDEA一般会自动建一个Main类我建议直接在里面写别自己乱建文件。public class Main { public static void main(String[] args) { // 代码写在这里 } }main方法是整个程序的入口你现在只需要知道这句话是固定的public、static、void这些修饰词的含义后面学到方法时自然就懂了。抄这个固定句式别问为什么问就是Java的运行约定。5.2 Scanner读取输入从“输出世界”到“倾听用户”到目前为止我们写的所有程序都是单向的程序算完打印结果。但真正的程序是能跟人对话的。Java里最基础的输入方式是Scanner。import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner new Scanner(System.in); System.out.println(请输入你的年龄); int age scanner.nextInt(); System.out.println(我记住了你 age 岁。); scanner.close(); } }第一行的import是把Scanner这个工具从java.util包里搬进来没有它编译器不认识Scanner。scanner.nextInt()会阻塞住等待用户输入一个整数再继续执行。我用“阻塞”这个词你可能陌生实际感受就是运行后程序停在那儿光标一闪一闪等你打字敲完回车才继续。这是很多初学交互程序时会觉得“程序卡死”的真相——其实它在等你。5.3 完整案例计算BMI并给出健康建议我第一天的Hello World只是向世界打了招呼第二天的BMI计算器才让我觉得“能写点有用的东西了”。直接上一个完整代码import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner new Scanner(System.in); System.out.print(请输入你的身高米); double height scanner.nextDouble(); System.out.print(请输入你的体重千克); double weight scanner.nextDouble(); double bmi weight / (height * height); System.out.printf(你的BMI是%.2f%n, bmi); if (bmi 18.5) { System.out.println(偏瘦注意营养); } else if (bmi 24) { System.out.println(正常保持); } else if (bmi 28) { System.out.println(偏胖该动了); } else { System.out.println(肥胖建议体检后科学减重); } scanner.close(); } }运行后交互效果大概是请输入你的身高米1.75 请输入你的体重千克70 你的BMI是22.86 正常保持注意几个细节printf里的%.2f表示保留两位小数%n是换行符跟\n效果类似但跨平台兼容性更好bmi公式为什么是weight除以height的平方这是国际通用标准不需要背公式会用就行。这个案例的价值在于你把第二天的语法全部串起来了——变量声明、Scanner输入、算术运算符、格式化输出、if分支判断。写完它你会突然发现原来编程就是“输入数据、处理数据、输出结果”的循环往复。5.4 改进思路常量和方法为明天埋钩子我的代码里现在有一堆魔法数字18.5、24、28。如果以后标准变了你得满屏改。专业的做法是用final定义常量final double LOW_WEIGHT_LIMIT 18.5; final double NORMAL_WEIGHT_LIMIT 24;另一个可以改进的方向是“方法”。把BMI计算单独抽成一个方法public static double calcBMI(double height, double weight) { return weight / (height * height); }看到没有学习路径是滚雪球的。你不需要今天就把这些全掌握但写代码时留个“这里可以更好”的心思学起来会有方向感。6. 中登踩坑实录从编译错误到逻辑错误6.1 编译期最常见的5个错误编译期错误是编译器直接给你报出来的不解决根本运行不了。我第二天几乎把所有常见错误挨个犯了一遍这里列个速查表错误类型典型报错原因解法缺少分号; expected语句结束没写分号看上一行末尾括号不匹配reached end of file while parsing大括号少了或多了用IDE的括号高亮检查类名文件不一致类名报红/找不到主类public类名与文件名不一致改成一致中文分号illegal character输入法没切英文代码全程英文标点未初始化variable might not have been initialized局部变量没赋值就用声明时赋个初值我个人的体会是编译错误看着吓人其实最友好。它至少告诉你在哪一行出错你花两分钟改完就会产生一种“我战胜了电脑”的快感这在学习枯燥期特别提气。6.2 运行期最常见的几个问题编译通过不代表程序正确运行时错误更隐蔽。第一个经典问题除数为0。int a 10; int b 0; int c a / b; // 抛出ArithmeticException整数除以0会直接崩但如果是double除0不会崩结果会是Infinity。这个差异我在测试BMI时没注意输入身高为0结果直接输出Infinity人给整懵了。所以写代码时要考虑用户可能输入非法的数据。怎么解决可以先判断if (height 0) { System.out.println(身高不合法); return; }第二个经典问题Scanner输入类型不匹配。int age scanner.nextInt(); // 用户输入了 abc // 抛出InputMismatchException用户才不会按你的剧本输入所以真实产品里要做异常处理那是try-catch的内容第二天知道有这个问题就行。第三个是逻辑错误最阴险程序不报错但结果不对。double bmi weight / height * height;这行代码数学上等价于weight / height再乘height结果接近weight根本不是BMI。我当初写的时候没加括号程序跑得飞快输出却离谱。排查这种问题最土的办法就是打印中间变量把每一步的结果打出来看。6.3 排错三板斧以及“心态”就是生产力我第二天最大的收获不是会写多少语法而是学会了怎么面对报错。第一板斧看错误信息的第一行里面通常有文件名和行号比如Main.java:12。点过去就知道错在哪了。第二板斧用打印大法。System.out.println(调试标记1 bmi);我不会算就让电脑算把算式拆成几个临时变量逐个打印哪儿不对改哪儿。第三板斧二分注释法。当一段代码整体报错找不到原因时把代码从中间注释掉一半看哪一半还在报错然后继续二分错误范围迅速缩小。学编程还有一个很玄但很真实的心态问题编译报错别烦。报错是编译器在跟你说话告诉你怎么改。真正该怕的是程序静悄悄跑完结果却是一堆垃圾数据。把“报错坏事”改成“报错老师在批改作业”心态会稳很多。最后再分享一点“第二天之后”的心里话第二天结束时我电脑上已经多了十几个练习文件从最简单的变量打印到BMI计算器再到九九乘法表。说实话没有那种“突然成了高手”的爽感反而是长时间盯着代码后的头昏脑涨。但我有一个很深的感受Java的语法规则虽然多但它们之间环环相扣每解决一个报错你对整个体系的信任就多一分。我个人觉得学编程最难的不是某一句话看不懂而是面对大段大段看不懂的知识时不知道从哪里下口。所以我特别建议你像我一样第二天就只看四个东西变量、运算符、if分支、循环。别的什么都不碰。把这三个小时的量砸实比你硬啃五小时还强。有个技巧我越用越顺每天结束前把当天的代码翻出来找一小段自己写的然后故意造两个错——比如删个分号、把改成然后看编译器怎么骂你。这个玩法又解压又能巩固记忆还顺便把常见报错混了个脸熟。第三天的计划我也订好了进入方法的世界学参数、学返回值然后把我那个BMI计算器改造成方法版。我猜又会踩不少坑但那正好坑踩得多了路也就熟了。