Java 新手入门与实战开发指南
面向零基础读者,手把手带你从安装环境到写出第一个可运行程序,再到理解面向对象、集合、多线程,最后用一个综合案例把知识串起来。所有代码均可复制运行。
目录
① [JDK 环境搭建与第一个程序运行](#JDK 环境搭建与第一个程序运行)
⑦ [文件读写操作与 IO 流应用](#文件读写操作与 IO 流应用)
一、JDK 环境搭建与第一个程序运行
1.1 什么是 JDK / JRE / JVM
初学者先搞清楚三个缩写,避免后面绕晕:
- JVM(Java 虚拟机):真正"运行"Java 程序的地方。Java 之所以能"一次编写,到处运行",靠的就是不同平台有不同的 JVM,但执行的是同一份字节码。
- JRE(Java 运行环境):JVM + 运行 Java 程序所需的基础类库。只运行程序、不开发,装 JRE 就够了。
- JDK(Java 开发工具包) :JRE + 编译器(javac)+ 调试等开发工具。我们要开发,必须装 JDK。
一句话:开发装 JDK,JDK 已经包含了 JRE。
1.2 下载与安装
- 打开浏览器访问 Oracle 官网(https://www.oracle.com/java/technologies/downloads/)或 Adoptium(https://adoptium.net/,开源免费,推荐新手用)。
- 选择 LTS 长期支持版本 (目前主流是 Java 17 或 Java 21),下载对应操作系统的安装包:
- Windows:选
.msi安装包,双击按提示安装。 - macOS:选
.pkg。 - Linux:可用
apt install openjdk-17-jdk等命令。
- Windows:选
- 记住安装路径(Windows 默认类似
C:\Program Files\Java\jdk-17)。
建议:新手优先用 Adoptium 的 Temurin 发行版,无需注册、无商业授权顾虑。
1.3 配置环境变量(Windows)
配置环境变量是为了在任意目录下都能使用 java 和 javac 命令。
-
右键"此电脑" → 属性 → 高级系统设置 → 环境变量。
-
在"系统变量"中新建
JAVA_HOME,值为 JDK 安装路径,例如:C:\Program Files\Java\jdk-17 -
找到已有的
Path变量,编辑 → 新建,添加两行:%JAVA_HOME%\bin -
一路确定保存。
1.4 验证安装
打开命令行(Win + R → 输入 cmd),执行:
bash
java -version
javac -version
能正确显示版本号(如 java version "17.0.x")即表示安装成功。
1.5 写出第一个程序:Hello World
新建一个文件 HelloWorld.java,注意文件名必须和类名完全一致:
java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, Java 世界!");
}
}
逐行解释:
public class HelloWorld:定义一个公开的"类",类名是HelloWorld。Java 要求public类的文件名必须等于类名。public static void main(String[] args):程序的入口方法(主方法)。JVM 启动时会自动找它并执行。System.out.println(...):向控制台打印一行文字。
1.6 编译与运行
在 HelloWorld.java 所在目录执行:
bash
javac HelloWorld.java # 编译:生成 HelloWorld.class 字节码文件
java HelloWorld # 运行:JVM 执行字节码(注意不需要写 .class)
看到输出 Hello, Java 世界! 就成功了!🎉
新手易错:
java命令后面跟的是类名HelloWorld,不是文件名HelloWorld.class,也不带.java。
二、核心语法基础与变量数据类型
2.1 程序的基本结构
Java 是强类型、面向对象 语言,所有代码都写在类 {} 里,语句以分号 ; 结尾。
2.2 变量的声明与使用
变量就是"装数据的盒子",先声明类型再使用:
java
int age = 18; // 整数
double price = 9.9; // 小数
String name = "小明"; // 字符串(引用类型)
boolean isStudent = true; // 布尔值:true / false
age = 19; // 可以重新赋值
System.out.println(name + " 今年 " + age + " 岁");
2.3 八大基本数据类型
| 类型 | 占用空间 | 取值范围 | 示例 |
|---|---|---|---|
byte |
1 字节 | -128 ~ 127 | byte b = 10; |
short |
2 字节 | -32768 ~ 32767 | short s = 1000; |
int |
4 字节 | 约 ±21 亿 | int i = 100000; |
long |
8 字节 | 非常大 | long l = 100L; |
float |
4 字节 | 单精度小数 | float f = 3.14f; |
double |
8 字节 | 双精度小数 | double d = 3.14; |
char |
2 字节 | 单个字符 | char c = 'A'; |
boolean |
1 位 | true / false |
boolean flag = true; |
注意:
long类型数字末尾要加L,float末尾要加f,否则编译报错(默认整数是 int,小数是 double)。
2.4 引用类型(Reference Type)
除了基本类型,其他都是引用类型,常见有:
String:字符串,用双引号包裹。- 数组、类、接口、集合等(后面章节会讲)。
引用类型存的是"对象在内存中的地址",不是数据本身。
2.5 类型转换
java
// 自动转换(小 → 大,安全)
int a = 10;
double b = a; // int 自动转 double
// 强制转换(大 → 小,可能丢精度,需手动)
double d = 9.99;
int i = (int) d; // 结果为 9,小数部分被截断
// String 与数字的互转
String s = "123";
int n = Integer.parseInt(s); // 字符串 → int
String s2 = String.valueOf(n); // int → 字符串
2.6 常量(final)
不希望被修改的值用 final 修饰,相当于常量:
java
final double PI = 3.14159;
// PI = 3.14; // 编译报错:不能修改 final 变量
2.7 命名规范(养成好习惯)
- 类名:
大驼峰(首字母大写),如StudentManager。 - 变量/方法名:
小驼峰(首字母小写),如studentName、getAge()。 - 常量:全大写加下划线,如
MAX_COUNT。
三、流程控制语句与逻辑判断实战
3.1 条件判断 if / else
java
int score = 85;
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
3.2 switch 多分支(JDK 12+ 新写法更简洁)
java
String day = "周一";
switch (day) {
case "周一":
case "周二":
case "周三":
case "周四":
case "周五":
System.out.println("工作日");
break; // 不加 break 会"穿透"执行下一个 case
case "周六":
case "周日":
System.out.println("休息日");
break;
default:
System.out.println("未知");
}
JDK 14+ 还支持
switch表达式(返回值),写法更现代,学有余力可了解。
3.3 循环:for
java
// 打印 1~5
for (int i = 1; i <= 5; i++) {
System.out.println("第 " + i + " 次");
}
// 增强 for(遍历数组/集合时用,后面常用)
int[] nums = {10, 20, 30};
for (int n : nums) {
System.out.println(n);
}
3.4 循环:while 与 do-while
java
int i = 1;
while (i <= 3) { // 先判断,再执行
System.out.println(i);
i++;
}
int j = 1;
do {
System.out.println(j); // 先执行一次,再判断
j++;
} while (j <= 3);
3.5 break 与 continue
break:跳出整个循环。continue:跳过本次循环,进入下一轮。
java
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) continue; // 偶数跳过
if (i > 7) break; // 超过 7 停止
System.out.println("奇数:" + i); // 输出 1 3 5 7
}
3.6 实战:简单计算器
java
import java.util.Scanner; // 读取键盘输入
public class Calculator {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("输入第一个数:");
double a = sc.nextDouble();
System.out.print("输入运算符(+ - * /):");
String op = sc.next();
System.out.print("输入第二个数:");
double b = sc.nextDouble();
double result;
switch (op) {
case "+": result = a + b; break;
case "-": result = a - b; break;
case "*": result = a * b; break;
case "/": result = (b != 0) ? a / b : 0; break;
default: result = 0; System.out.println("不支持的运算符");
}
System.out.println("结果 = " + result);
sc.close();
}
}
四、面向对象编程思想与类的设计
4.1 什么是面向对象(OOP)
面向过程关注"怎么做步骤",面向对象关注"谁来做"。现实世界由对象 组成(一个学生、一本书),对象有属性(数据)和行为(方法) 。把对象抽象成类(Class),用类创建具体对象,就是面向对象编程。
4.2 定义一个类
java
public class Student {
// 属性(字段)
String name;
int age;
double score;
// 行为(方法)
public void study() {
System.out.println(name + " 正在学习");
}
public void showInfo() {
System.out.println("姓名:" + name + ",年龄:" + age + ",成绩:" + score);
}
}
4.3 创建对象(实例化)
java
public class Test {
public static void main(String[] args) {
Student stu = new Student(); // 用 new 创建对象
stu.name = "小红";
stu.age = 20;
stu.score = 95.5;
stu.study();
stu.showInfo();
}
}
4.4 构造方法
构造方法在 new 对象时自动执行,用来初始化属性。名字必须与类名相同,没有返回值。
java
public class Student {
String name;
int age;
// 无参构造
public Student() {}
// 有参构造
public Student(String name, int age) {
this.name = name; // this 指代"当前对象"
this.age = age;
}
}
使用:Student stu = new Student("小明", 18);
4.5 封装(Encapsulation)------ 三大特性之一
封装 = 把属性藏起来,只通过公开的方法访问,保护数据安全。
java
public class Student {
private String name; // 私有,外部不能直接访问
private int age;
public void setAge(int age) {
if (age >= 0 && age <= 150) { // 校验合法性
this.age = age;
} else {
System.out.println("年龄不合法");
}
}
public int getAge() {
return age;
}
public void setName(String name) { this.name = name; }
public String getName() { return name; }
}
这是 JavaBean 规范的雏形:
private字段 +getter/setter方法。
4.6 继承(Inheritance)------ 三大特性之二
子类继承父类的属性和方法,实现代码复用。
java
class Person {
String name;
public void eat() { System.out.println(name + " 吃饭"); }
}
class Teacher extends Person { // Teacher 继承 Person
public void teach() { System.out.println(name + " 讲课"); }
}
Teacher 自动拥有 name 和 eat(),并新增自己的 teach()。
4.7 多态(Polymorphism)------ 三大特性之三
父类引用指向子类对象,运行时才决定调用哪个方法。
java
class Animal {
public void sound() { System.out.println("动物叫"); }
}
class Cat extends Animal {
public void sound() { System.out.println("喵喵"); }
}
class Dog extends Animal {
public void sound() { System.out.println("汪汪"); }
}
// 多态:统一用 Animal 类型,调用同一个方法,表现不同
Animal a1 = new Cat();
Animal a2 = new Dog();
a1.sound(); // 喵喵
a2.sound(); // 汪汪
五、常用集合框架的使用与遍历
数组长度固定,不够灵活。集合(Collection) 能动态增删元素,是日常开发的主力。
5.1 List(有序、可重复)
常用实现:ArrayList(查询快)、LinkedList(增删快)。
java
import java.util.*;
public class ListDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("苹果");
list.add("香蕉");
list.add("苹果"); // 允许重复
// 遍历方式一:for 循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 遍历方式二:增强 for(最常用)
for (String s : list) {
System.out.println(s);
}
// 遍历方式三:forEach + Lambda(JDK 8+)
list.forEach(s -> System.out.println(s));
System.out.println("长度:" + list.size());
list.remove("香蕉");
}
}
5.2 Set(无序、不可重复)
常用实现:HashSet。适合去重。
java
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(1); // 重复,不会加入
System.out.println(set.size()); // 2
for (Integer n : set) {
System.out.println(n);
}
5.3 Map(键值对)
常用实现:HashMap。适合"通过 key 找 value",如字典、配置表。
java
Map<String, Integer> map = new HashMap<>();
map.put("语文", 90);
map.put("数学", 95);
map.put("英语", 88);
// 遍历方式一:遍历 key
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
// 遍历方式二:遍历 entry(推荐,效率高)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
System.out.println("数学分数:" + map.get("数学"));
5.4 如何选择
| 需求 | 用哪个 |
|---|---|
| 有序、可重复、按下标取 | ArrayList |
| 去重、不关心顺序 | HashSet |
| 键值对应(如学号→学生) | HashMap |
六、异常处理机制与调试技巧
6.1 什么是异常
程序运行中出现的错误叫异常,比如除以 0、读取不存在的文件。Java 用 try-catch 优雅处理,避免程序崩溃。
6.2 try-catch-finally
java
try {
int a = 10 / 0; // 可能出错的代码
} catch (ArithmeticException e) {
System.out.println("出错了:" + e.getMessage());
} finally {
System.out.println("无论是否出错,这里都会执行"); // 常用于关闭资源
}
6.3 多重捕获与异常层级
异常有继承关系:Exception 是父类,下面是各种具体异常。可用多个 catch 分别处理,或用一个 catch (Exception e) 兜底。
java
try {
int[] arr = {1, 2};
System.out.println(arr[5]); // 数组越界
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界");
} catch (Exception e) {
System.out.println("其他异常:" + e);
}
6.4 throw 与 throws
throw:在方法内主动抛出一个异常。throws:在方法签名上声明该方法可能抛出异常,交给调用者处理。
java
public static int divide(int a, int b) throws Exception {
if (b == 0) {
throw new Exception("除数不能为 0");
}
return a / b;
}
// 调用处必须处理(try-catch 或继续 throws)
6.5 自定义异常
java
class AgeException extends Exception {
public AgeException(String msg) { super(msg); }
}
public void setAge(int age) throws AgeException {
if (age < 0) throw new AgeException("年龄不能为负数");
}
6.6 调试技巧(IDE 中)
以 IntelliJ IDEA / Eclipse 为例:
- 在代码行号左侧单击打红点(断点)。
- 右键 → Debug 运行。
- 程序在断点处暂停,可查看变量值、单步执行(Step Over / Step Into)。
- 用 Watch 窗口监控表达式。
- 控制台查看完整异常堆栈,从最上面的"自己写的类"行定位问题。
新手排错黄金法则:认真读异常信息里的 类名 + 行号,90% 的问题都在那里。
七、文件读写操作与 IO 流应用
7.1 IO 流概念
"流(Stream)"就是数据流动的通道。按方向分:
- 输入流 :读数据进程序(如
InputStream、Reader)。 - 输出流 :写数据出程序(如
OutputStream、Writer)。
按单位分:字节流(图片、视频等任意文件)和字符流(文本文件,带编码)。
7.2 写文本文件(字符流)
java
import java.io.*;
public class WriteFile {
public static void main(String[] args) {
try (FileWriter fw = new FileWriter("note.txt");
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write("第一行内容");
bw.newLine(); // 换行
bw.write("第二行内容");
} catch (IOException e) {
e.printStackTrace(); // 打印异常
}
}
}
try (...)是 try-with-resources 语法,写完自动关闭流,避免资源泄漏,强烈推荐。
7.3 读文本文件(字符流)
java
import java.io.*;
public class ReadFile {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("note.txt"))) {
String line;
while ((line = br.readLine()) != null) { // 逐行读取
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
7.4 复制二进制文件(字节流)
java
try (FileInputStream fis = new FileInputStream("a.jpg");
FileOutputStream fos = new FileOutputStream("b.jpg")) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("复制完成");
} catch (IOException e) {
e.printStackTrace();
}
7.5 路径说明
- 相对路径 :相对当前项目目录,如
"note.txt"。 - 绝对路径 :从盘符开始,如
"D:/data/note.txt"(Windows 建议用/或\\)。
八、多线程基础与并发安全初探
8.1 为什么需要多线程
单线程一次只做一件事。多线程让程序"同时"处理多个任务,比如下载文件时界面不卡顿。Java 天然支持多线程。
8.2 创建线程的两种方式
方式一:继承 Thread
java
class MyThread extends Thread {
@Override
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.println(getName() + " 执行:" + i);
}
}
}
// 启动:new MyThread().start();
方式二:实现 Runnable(推荐,更灵活)
java
class MyTask implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + " 执行:" + i);
}
}
}
// 启动:new Thread(new MyTask()).start();
注意:启动线程用
start(),不是直接调用run()。start()才会真正开新线程。
8.3 线程不安全示例
多个线程同时修改同一个变量,结果可能错乱:
java
class Counter {
static int count = 0;
}
// 两个线程各加 1000 次,理论结果 2000,实际可能 < 2000
Runnable task = () -> {
for (int i = 0; i < 1000; i++) Counter.count++;
};
new Thread(task).start();
new Thread(task).start();
8.4 并发安全初探:synchronized
用 synchronized 加锁,保证同一时间只有一个线程能执行被保护的代码:
java
class SafeCounter {
private int count = 0;
public synchronized void add() { // 加锁
count++;
}
public synchronized int get() {
return count;
}
}
进阶可了解 ReentrantLock、volatile、AtomicInteger 等并发工具(JUC 包)。
8.5 线程的状态
新建(New)→ 就绪(Runnable)→ 运行(Running)→ 阻塞(Blocked/Waiting)→ 死亡(Terminated)。理解状态有助于排查卡死问题。
九、综合案例:简易管理系统实现
把前面知识串起来,做一个学生信息管理系统 (控制台版),支持增、删、查、遍历,并用 ArrayList 存储、Scanner 交互。
java
import java.util.*;
// 学生类(封装属性)
class Student {
private String id;
private String name;
private int age;
public Student(String id, String name, int age) {
this.id = id; this.name = name; this.age = age;
}
public String getId() { return id; }
public String getName() { return name; }
public int getAge() { return age; }
@Override
public String toString() {
return "学号:" + id + ",姓名:" + name + ",年龄:" + age;
}
}
// 管理类
class StudentManager {
private List<Student> list = new ArrayList<>();
public void add(Student s) { list.add(s); }
public void remove(String id) {
list.removeIf(s -> s.getId().equals(id));
}
public Student find(String id) {
for (Student s : list) {
if (s.getId().equals(id)) return s;
}
return null;
}
public void showAll() {
if (list.isEmpty()) {
System.out.println("暂无学生");
return;
}
for (Student s : list) System.out.println(s);
}
}
// 主程序
public class StudentSystem {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
StudentManager mgr = new StudentManager();
while (true) {
System.out.println("\n===== 学生管理系统 =====");
System.out.println("1.添加 2.删除 3.查询 4.显示全部 5.退出");
System.out.print("请选择:");
int choice = sc.nextInt();
sc.nextLine(); // 吸收换行符
switch (choice) {
case 1:
System.out.print("学号:"); String id = sc.nextLine();
System.out.print("姓名:"); String name = sc.nextLine();
System.out.print("年龄:"); int age = sc.nextInt(); sc.nextLine();
mgr.add(new Student(id, name, age));
System.out.println("添加成功");
break;
case 2:
System.out.print("输入要删除的学号:");
mgr.remove(sc.nextLine());
System.out.println("删除完成");
break;
case 3:
System.out.print("输入要查询的学号:");
Student s = mgr.find(sc.nextLine());
System.out.println(s != null ? s : "未找到");
break;
case 4:
mgr.showAll();
break;
case 5:
System.out.println("再见");
sc.close();
return;
default:
System.out.println("无效选择");
}
}
}
}
这个案例综合运用了:类与对象(第④章)、封装与构造方法、集合 ArrayList(第⑤章)、Scanner 与循环/分支(第③章)、switch 与 toString 重写。你可以把它作为第一个"完整小项目"反复练习、逐步加功能(如存文件、改信息、按成绩排序)。
十、常见编译报错分析与解决策略
| 报错信息 | 原因 | 解决办法 |
|---|---|---|
error: class X is public, should be declared in a file named X.java |
文件名与 public 类名不一致 | 让文件名=类名,或去掉 public |
error: cannot find symbol |
变量/方法名拼错,或作用域不对 | 检查拼写、是否已声明、是否导包 |
error: incompatible types |
类型不匹配(如把 String 赋给 int) | 加类型转换,或改正确类型 |
error: ';' expected |
少了分号 | 在报错行末尾补 ; |
error: reached end of file while parsing |
大括号 {} 没配对 |
检查并补齐 } |
Exception in thread "main" java.lang.NullPointerException |
调用了 null 对象的方法 | 使用前判空 if (obj != null) |
ArrayIndexOutOfBoundsException |
数组下标越界 | 检查循环条件和下标范围 |
NumberFormatException |
Integer.parseInt("abc") 转非数字 |
确保字符串是合法数字 |
java: 找不到或无法加载主类 |
没先 javac 编译,或 java 后跟了 .class |
先编译,再 java 类名(不带后缀) |
编码 GBK 的不可映射字符 |
源码含中文但用 GBK 编译 | 编译时加 -encoding UTF-8:javac -encoding UTF-8 X.java |
排错三步法
- 看报错行号 :异常堆栈里
at 你的类.方法(文件名.java:行号)直接定位到代码。 - 搜索关键词:把英文报错粘到搜索引擎,多半有人遇到过。
- 最小化复现:把出问题的代码抽成几行小程序单独跑,快速隔离原因。
学习路线建议
- 第 1~2 周:吃透 ①~③(环境、语法、流程控制),每天写小程序。
- 第 3~4 周:攻下 ④~⑦(面向对象、集合、异常、IO),完成第⑨章案例。
- 第 5 周起:了解 ⑧(多线程),并尝试接入真实项目或框架(如 Spring Boot)。
- 贯穿全程:遇到报错就回到 ⑩,把每个错误变成经验。
写在最后:编程是"做会"的,不是"看懂"的。复制本文代码运行一遍,改改参数,再自己从头敲一遍,你就已经超过了大多数只看不练的人。加油!💪