☰
零基础学Java避坑指南:从环境搭建到数组方法的实战笔记
2026/10/15 5:13:35 网站建设 项目流程

简介:这份资源是韩顺平《循序渐进学Java零基础》的完整学习笔记,面向零基础、希望系统入门Java编程的初学者,也可作为复习Java核心概念的参考材料。笔记按课程体系分为三个阶段:基础语法、数据类型、控制结构、类与对象;异常处理、多线程、I/O流、集合框架等进阶主题;以及数据库操作、网络编程和面向对象设计原则等实际应用,并延伸介绍Java在SSM、Android、Hadoop等场景中的就业方向。资源包共1个PDF文件,大小约59.36MB,内容为完整笔记文档,便于打印或离线阅读。目前已有2715人学习下载,说明该笔记在Java入门群体中具有一定认可度。读者可借助它梳理Java知识脉络、对照课程查漏补缺,并了解Java在企业级应用、移动开发和大数据领域的典型用途,适合作为零基础学习路线中的配套资料。

1. 零基础学 Java 的第一道坎:为什么你看了三遍视频还是写不出 for 循环

很多人学 Java 的起点是一套叫「循序渐进学 Java 零基础」的完整笔记,标题里那个「1」通常意味着这是系列的第一部分,覆盖的是环境搭建、基础语法、变量、运算符、流程控制这些内容。听起来简单,但我见过太多人卡在同一个地方:视频看完了,笔记抄了,合上电脑让自己写一个「打印 1 到 100 之间的偶数」,手放在键盘上不知道从哪敲起。这不是智力问题,是学习路径的问题——看和写之间隔着一整套肌肉记忆,而零基础阶段最缺的就是这套肌肉记忆的建立方法。

这篇笔记面向的是真正从零开始的人:没写过代码、分不清编译和运行、看到public static void main(String[] args)觉得像乱码。我会把「循序渐进学 Java 零基础」第一部分涉及的核心内容拆成可复现的步骤,告诉你每一步该敲什么、为什么这么敲、报错了看哪里。如果你已经能独立写出冒泡排序,这篇可以跳过;如果你还在为「Hello World 为什么必须这么写」纠结,那正好。

2. 把开发环境跑起来:JDK 安装、环境变量与第一个能编译的类

2.1 JDK 到底装什么版本,为什么不是越新越好

零基础最容易在第一步翻车:打开搜索引擎搜「Java 下载」,出来一堆 JDK 21、JDK 17、JDK 8,不知道该点哪个。我的建议很直接——学基础语法阶段,选 JDK 17 或 JDK 8 都行,但不要选最新的非 LTS 版本。原因不是新版本不好,而是零基础阶段你需要的教程、笔记、报错搜索结果,绝大多数是基于 LTS(长期支持版)写的。你装个 JDK 23,遇到一个语法警告去搜,搜出来的答案全是 JDK 8 的写法,对不上,徒增挫败感。

安装过程本身没什么好说的,一路下一步即可。真正要确认的是三件事:java -version能输出版本号、javac -version能输出版本号、echo %JAVA_HOME%(Windows)或echo $JAVA_HOME(macOS/Linux)能输出 JDK 安装目录。这三个命令缺一个,后面全白搭。

# 验证 JDK 是否安装成功,三条命令都要有输出 java -version javac -version echo $JAVA_HOME # Windows 用 echo %JAVA_HOME%

逻辑说明:java是运行工具,javac是编译工具,两者版本号必须一致。如果java有输出但javac提示「不是内部或外部命令」,说明你装的是 JRE 而不是 JDK,或者 PATH 只配了一半。JAVA_HOME是很多构建工具(Maven、Gradle)依赖的环境变量,现在配好,后面省事。

参数说明:-version输出到标准错误流,所以如果你在脚本里想捕获它,要用2>&1。这不是零基础必须知道的,但遇到「明明装了却读不到版本」时,这个细节能救你。

2.2 第一个 Java 类的每一行到底在写什么

环境好了,写第一个类。不要用 IDE 的自动生成,手敲一遍:

// FirstDemo.java // 文件名必须和 public 类名完全一致,包括大小写 public class FirstDemo { // main 方法是程序入口,JVM 只认这个签名 public static void main(String[] args) { // 向控制台输出一行文本 System.out.println("Hello, Java"); } }

逻辑说明:Java 是编译型语言,javac FirstDemo.java会生成FirstDemo.class字节码文件,然后java FirstDemo让 JVM 加载并执行。public修饰的类要求文件名与类名一致,这是硬性规定,不是风格建议。main方法的签名public static void main(String[] args)是 JVM 约定的入口,少一个修饰符、改一个参数类型,都会报「找不到主方法」。

参数说明:String[] args是命令行参数数组。零基础阶段可以完全不理会它,但要知道它的存在——后面你想让程序接收外部输入时,就是从这里拿。System.out.println里的ln表示输出后换行,去掉ln用print就不换行,这个差别在打印图形题里很关键。

编译运行两条命令:

javac FirstDemo.java # 编译,生成 FirstDemo.class java FirstDemo # 运行,注意不要加 .class 后缀

常见翻车点:java FirstDemo.class会报错,因为java命令接收的是类名不是文件名。另外,如果代码里写了package com.demo;,编译时要加-d .,运行时要用完整类名java com.demo.FirstDemo。零基础阶段建议先不写 package,等理解目录结构了再加。

2.3 用 IDE 还是记事本:我的真实建议

网上有一种说法是「零基础必须先用记事本,才能理解编译过程」。我的看法是:用记事本手敲两三个类,理解编译和运行的区别,然后立刻换 IDE。原因很简单,零基础阶段最大的敌人是挫败感,而记事本会让你把大量时间花在「少了一个分号找了十分钟」上,这不是在学习 Java,是在练习眼力。

IDE 选 IntelliJ IDEA 社区版或 VS Code 加 Java 插件都行。关键不是用哪个,而是你要知道 IDE 帮你做了什么:自动编译、自动补全、错误提示。用 IDE 的时候,偶尔手动去终端跑一次javac和java,保持对底层流程的感知,就够了。

3. 变量、运算符与流程控制:把「看得懂」变成「写得出」

3.1 八种基本类型,先记住四个就够用

Java 的基本数据类型有八种:byte、short、int、long、float、double、char、boolean。零基础阶段全背下来意义不大,先牢牢掌握四个:int(整数)、double(小数)、boolean(真假)、char(单个字符)。剩下的等用到再查。

// 基本类型声明与初始化 int age = 25; // 最常用的整数类型 double price = 9.9; // 小数默认是 double boolean isPass = true; // 只有 true 和 false 两个值 char grade = 'A'; // 单引号,只能放一个字符 // 类型转换:小范围到大范围自动转,反过来要强制转 int num = 100; long bigNum = num; // 自动转换,安全 double d = num; // 自动转换,安全 int back = (int) 9.99; // 强制转换,结果是 9,小数部分直接丢掉

逻辑说明:int和double之间的转换规则是零基础最容易出错的地方。int转double自动完成,double转int必须加(int),而且不是四舍五入,是直接截断。9.99转完是9,不是10。这个细节在后面的除法运算里会反复咬人。

参数说明:long类型的字面量要加L后缀,比如long big = 10000000000L;,不加的话编译器会当成int处理,超出范围就报错。float要加F后缀,float f = 3.14F;。这两个后缀零基础经常忘,记住「大范围加 L,float 加 F」。

3.2 运算符里最容易踩的三个坑

运算符本身不难,但有三个地方几乎每个人都会栽一次。

第一个坑:整数除法。5 / 2的结果是2不是2.5,因为两边都是int,结果也是int。想要小数,至少一边要是double,写成5.0 / 2或(double)5 / 2。

第二个坑:++在前在后。int a = 5; int b = a++;执行完b是5,a是6。换成int b = ++a;则b是6,a也是6。区别在于「先取值还是先自增」。零基础阶段建议单独一行写a++;,不要嵌在表达式里,可读性优先。

第三个坑:==和=。=是赋值,==是比较。if (a = 5)在 Java 里编译不过(因为a = 5是int不是boolean),这算是 Java 比 C 安全的地方。但if (a == 5)写成if (a = 5)的笔误仍然常见,IDE 会提示,别忽略黄色波浪线。

// 三个坑的对照写法 System.out.println(5 / 2); // 输出 2,不是 2.5 System.out.println(5.0 / 2); // 输出 2.5 System.out.println(5 % 2); // 输出 1,取余 int a = 5; int b = a++; // b 先拿到 5,然后 a 变成 6 System.out.println("a=" + a + ", b=" + b); // a=6, b=5 int c = 5; int d = ++c; // c 先变成 6,然后 d 拿到 6 System.out.println("c=" + c + ", d=" + d); // c=6, d=6

逻辑说明:%是取余运算符,5 % 2得1。取余在判断奇偶、循环控制里用得极多,必须熟练。字符串拼接用+,当+一边是字符串时,另一边会被转成字符串拼接,不是数学加法。"a=" + a里的a被转成字符串,所以输出a=6。

3.3 流程控制:if、switch、for、while 的选用场景

流程控制是零基础第一部分的重点,也是「看得懂写不出」的重灾区。我的建议是按场景记,不要按语法记。

判断范围用if-else if-else,判断具体值用switch。循环次数确定用for,次数不确定用while,至少执行一次用do-while。

// 场景一:判断成绩等级,用 if-else if int score = 85; if (score >= 90) { System.out.println("优秀"); } else if (score >= 80) { System.out.println("良好"); } else if (score >= 60) { System.out.println("及格"); } else { System.out.println("不及格"); } // 场景二:根据星期几输出,用 switch int day = 3; switch (day) { case 1: System.out.println("周一"); break; // 不写 break 会继续往下执行,叫「穿透」 case 2: System.out.println("周二"); break; case 3: System.out.println("周三"); break; default: System.out.println("其他"); } // 场景三:打印 1 到 100 的偶数,用 for for (int i = 1; i <= 100; i++) { if (i % 2 == 0) { System.out.println(i); } } // 场景四:猜数字直到猜对,用 while int target = 42; int guess = 0; while (guess != target) { guess++; // 模拟每次猜大一点 } System.out.println("猜对了:" + guess);

逻辑说明:switch的break是零基础最大的坑。不写break,case 3匹配后会继续执行case 4、case 5直到遇到break或结束,这叫「穿透」。有时候故意利用穿透(比如多个 case 共用一段逻辑),但初学阶段先养成每个 case 都写 break 的习惯。

参数说明:for (int i = 1; i <= 100; i++)三个部分分别是初始化、条件、步进。i <= 100决定循环次数,改成i < 100就是 1 到 99。i++改成i += 2就是每次加 2,可以直接打印奇数或偶数,不用在循环体里判断。

3.4 嵌套循环与 break/continue:打印九九乘法表

嵌套循环是零基础第一个「脑子转不过来」的地方。用九九乘法表来练,因为输出结果直观,错了立刻能看出来。

// 九九乘法表,外层控制行,内层控制列 for (int i = 1; i <= 9; i++) { // 外层:第几行 for (int j = 1; j <= i; j++) { // 内层:每行几个表达式 System.out.print(j + "*" + i + "=" + (j * i) + "\t"); } System.out.println(); // 每行结束换行 }

逻辑说明:外层i从 1 到 9,内层j从 1 到i。所以第一行只有1*1,第二行有1*2和2*2,以此类推。\t是制表符,用来对齐列。System.out.print不换行,System.out.println()空参数只换行。

参数说明:内层条件j <= i改成j <= 9就是完整乘法表(矩形),改成j <= 9 - i就是倒三角。改条件看输出变化,是理解嵌套循环最快的方法。

break跳出当前层循环,continue跳过本次进入下一次。注意break只跳出一层,嵌套里要跳出外层需要加标签:

outer: // 标签,名字随便起 for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { if (i == 2 && j == 2) { break outer; // 直接跳出外层循环 } System.out.println("i=" + i + ", j=" + j); } }

逻辑说明:不加标签的break只结束内层循环,外层继续。加标签后break outer直接结束整个嵌套。标签语法在实际开发里用得不多,但考试和面试里会出现,知道有这回事就行。

4. 数组与方法:从「写一段」到「写一块」

4.1 数组的声明、初始化与遍历的三种写法

数组是零基础第一部分后半段的重点。声明方式有两种,推荐用int[] arr而不是int arr[],因为前者更符合 Java 的习惯,类型和变量名分得清。

// 声明并初始化 int[] nums = {1, 2, 3, 4, 5}; // 静态初始化,最常用 int[] nums2 = new int[5]; // 动态初始化,默认值全是 0 String[] names = new String[3]; // 引用类型默认值是 null // 遍历方式一:普通 for,能拿到索引 for (int i = 0; i < nums.length; i++) { System.out.println(nums[i]); } // 遍历方式二:增强 for,只拿值,拿不到索引 for (int n : nums) { System.out.println(n); } // 遍历方式三:Arrays.toString,快速打印整个数组 System.out.println(java.util.Arrays.toString(nums));

逻辑说明:nums.length是数组长度,注意是属性不是方法,不加括号。增强 for 的写法for (int n : nums)读作「对 nums 里的每个 int,叫它 n」。增强 for 不能改数组元素(改的是副本),也不能拿索引,适合只读遍历。

参数说明:new int[5]创建长度 5 的数组,索引是 0 到 4。访问nums[5]会抛ArrayIndexOutOfBoundsException,这是零基础最常见的运行时异常。数组一旦创建,长度不可变,这是和后面集合类最大的区别。

4.2 方法的定义、调用与参数传递

方法就是把一段逻辑包起来,起个名字,后面反复用。零基础阶段先掌握「有参有返回值」和「有参无返回值」两种。

public class MethodDemo { // 有参有返回值:计算两数之和 public static int add(int a, int b) { return a + b; // return 后面不能再写代码 } // 有参无返回值:打印数组 public static void printArray(int[] arr) { for (int n : arr) { System.out.print(n + " "); } System.out.println(); } // 无参有返回值:返回固定值 public static String getGreeting() { return "Hello"; } public static void main(String[] args) { int sum = add(3, 5); // 调用并接收返回值 System.out.println(sum); // 输出 8 int[] data = {1, 2, 3}; printArray(data); // 调用无返回值方法 System.out.println(getGreeting()); } }

逻辑说明:static修饰的方法可以直接在main里调用,不需要创建对象。零基础第一部分还没学到面向对象,所有方法都加static就对了。void表示没有返回值,方法体里不能写return 值;,但可以写return;提前结束。

参数说明:Java 的参数传递只有值传递。基本类型传的是值的副本,方法内改不影响外面;引用类型传的是地址的副本,方法内改数组元素会影响外面,但重新赋值整个数组不影响外面。这个区别零基础容易绕晕,记住一句话:改元素影响外面,改指向不影响外面。

public static void modify(int[] arr) { arr[0] = 100; // 改元素,外面能看到 arr = new int[]{9, 9}; // 改指向,外面看不到 } // 调用 int[] data = {1, 2, 3}; modify(data); System.out.println(data[0]); // 输出 100,不是 9

4.3 方法重载:同名不同参

重载是零基础第一部分里比较抽象的概念,但理解了一个例子就通了:同一个方法名,参数列表不同(个数、类型、顺序),编译器根据调用时传的参数自动选。

public static int max(int a, int b) { return a > b ? a : b; } public static double max(double a, double b) { return a > b ? a : b; } public static int max(int a, int b, int c) { return max(max(a, b), c); } // 调用 System.out.println(max(3, 5)); // 调 int 版本,输出 5 System.out.println(max(3.5, 2.1)); // 调 double 版本,输出 3.5 System.out.println(max(1, 9, 4)); // 调三参数版本,输出 9

逻辑说明:重载只看方法名和参数列表,和返回值类型无关。int max(int, int)和double max(int, int)不构成重载,编译报错。max(max(a, b), c)是嵌套调用,先算内层再算外层。

参数说明:a > b ? a : b是三目运算符,读作「a 大于 b 吗?是就取 a,否就取 b」。零基础阶段用三目能让代码简洁,但嵌套三目可读性差,超过一层就改回if-else。

5. 零基础学 Java 第一部分的避坑清单:五个血泪教训

5.1 编译报错「找不到符号」——九成是拼写或大小写

现象:javac报cannot find symbol,指向某个变量或方法名。

原因:Java 严格区分大小写,String写成string、System写成system、变量userName写成username,都会报这个错。另外,变量声明了但没初始化就使用,也会报「找不到符号」。

解决:看报错行号,逐个字符对比。IDE 里把光标放到变量上按Ctrl+B(或Cmd+B)能跳到声明处,对不上就是拼写问题。养成变量命名用驼峰、类名用大驼峰的习惯,减少这类错误。

5.2 数组越界——循环条件写成<=是元凶

现象:运行时报ArrayIndexOutOfBoundsException,程序直接终止。

原因:数组长度是length,索引是0到length-1。循环写成for (int i = 0; i <= arr.length; i++),当i等于length时访问越界。

解决:循环条件统一用<,不用<=。增强 for 不会有这个问题,只读遍历优先用增强 for。如果必须用索引,写完循环先在心里跑一遍边界:i=0和i=length-1是否都合法。

5.3 整数除法丢精度——5/2得2不是2.5

现象:计算平均值、百分比时结果总是整数,小数部分凭空消失。

原因:两个int相除,结果还是int,小数部分直接截断,不是四舍五入。

解决:参与运算的至少一个操作数转成double。(double)sum / count或sum / (double)count或sum * 1.0 / count都行。注意(double)(sum / count)是错的,因为括号里先算了整数除法,转的时候已经晚了。

5.4switch忘写break——穿透执行到下一个 case

现象:switch匹配了case 2,结果case 3、case 4的代码也执行了。

原因:switch的case只是入口标签,没有自动跳出机制,不写break会一直往下执行。

解决:每个case末尾加break。如果确实想利用穿透(多个值共用逻辑),加注释说明「此处故意穿透」,避免后面自己或别人误以为是漏写。

5.5==比较字符串——引用类型不能用==比内容

现象:两个内容相同的字符串,用==比较返回false。

原因:==比较的是引用地址,不是内容。字符串常量池的机制会让某些情况返回true,某些情况返回false,行为不稳定。

解决:字符串内容比较一律用.equals(),写成str1.equals(str2)。如果str1可能为null,用"常量".equals(str1)把常量放前面,避免空指针。这个坑在零基础阶段遇到得早,记住「字符串比内容用 equals」就行。

6. 从能跑到能讲清:用一个小项目验证第一部分是否真的过关

学完第一部分,怎么判断自己是真的会了,而不是「跟着视频能敲」?我的标准是:能不能不看任何参考,独立写出一个控制台版的学生成绩管理小程序,包含录入、查询、统计平均分、按分数排序四个功能。不需要面向对象,全用数组和static方法实现。能写出来,第一部分就过关了;写不出来,回去补对应章节。

下面给一个最小可运行版本,你可以先自己写,写完再对照。

import java.util.Arrays; import java.util.Scanner; public class ScoreManager { // 用数组存成绩,实际项目会用集合,这里先练数组 static int[] scores = new int[100]; static int count = 0; // 当前已录入数量 // 录入成绩 public static void addScore(int score) { if (count >= scores.length) { System.out.println("数组已满"); return; } scores[count] = score; count++; } // 计算平均分,注意转 double public static double average() { if (count == 0) return 0; int sum = 0; for (int i = 0; i < count; i++) { sum += scores[i]; } return (double) sum / count; } // 排序,只排前 count 个 public static void sortScores() { int[] valid = Arrays.copyOf(scores, count); Arrays.sort(valid); System.out.println("排序后:" + Arrays.toString(valid)); } public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (true) { System.out.println("1.录入 2.平均分 3.排序 4.退出"); int op = sc.nextInt(); if (op == 1) { System.out.print("输入成绩:"); addScore(sc.nextInt()); } else if (op == 2) { System.out.println("平均分:" + average()); } else if (op == 3) { sortScores(); } else { break; } } sc.close(); } }

逻辑说明:scores数组开 100 长度,count记录实际录入了几个。遍历和排序都只处理前count个,避免把默认的 0 也算进去。Arrays.copyOf(scores, count)截取有效部分再排序,不破坏原数组顺序。average()里(double) sum / count是前面强调过的整数除法坑,这里必须转。

参数说明:Scanner的nextInt()遇到非整数输入会抛异常,零基础版本不做处理,知道有这回事即可。sc.close()关闭输入流,实际小程序里不关也不影响,但养成习惯。Arrays.sort默认升序,要降序得自己写比较器或反转,第一部分不展开。

写完这个程序,再回头问自己几个问题:count和scores.length的区别是什么?为什么排序要copyOf?average()里不转double会怎样?能答上来,说明你不是背代码,是真的理解了。

我自己的习惯是,每学完一个阶段,就找一个「最小可用」的小项目从头写一遍,不查笔记,卡住了再回去翻。卡住的地方就是没学透的地方,比反复看视频有效得多。第一部分的内容不多,但它是后面所有内容的地基,地基松了,后面学集合、IO、多线程会越来越吃力。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询