Java 零基础入门:3 小时掌握变量、循环与面向对象核心
Java编程的起点:从环境搭建到实战开发
你有没有试过第一次在电脑上敲下 Hello World 时那种微妙的兴奋感?指尖按下回车,屏幕跳出那行熟悉的文字——仿佛整个编程世界的大门“咔哒”一声为你打开。这不只是一个简单的输出语句,而是一段旅程的开始。而对于无数开发者来说,这个起点正是 Java 。
作为一门诞生于1995年的语言,Java至今仍在TIOBE排行榜前列稳坐江山。它不像某些新兴语言那样追求极致的简洁与炫技,而是以“一次编写,到处运行”的稳健理念深入人心。无论你是想做安卓应用、企业后台系统,还是大数据处理平台,Java都能给你坚实的支撑。
但别被它的“老资格”吓到。学习Java的过程,其实就像搭积木:先准备好工具箱(JDK),再掌握基本零件(语法),然后学会怎么把它们组合成有意义的结构(面向对象),最后亲手造出一个小房子(图书管理系统)。今天,我们就一步步走完这段路,不讲空话,只说你能用上的干货。
准备好你的开发武器库:JDK安装与验证
所有Java程序的灵魂都藏在一个叫 JVM(Java虚拟机) 的黑盒子里。它就像是一个跨平台的翻译官,把你写的 .java 文件翻译成每台机器都能听懂的“本地语言”。而要启动这一切,你需要先装好 JDK(Java Development Kit) ——也就是Java开发工具包。
JDK里面包含了三样关键东西:
- javac :编译器,负责把源码变成字节码
- java :运行器,交给JVM去执行
- JRE :运行环境,包括核心类库和JVM本身
安装过程很简单,官网下载对应系统的版本,一路下一步就行。重点来了——装完之后必须配置两个环境变量:
JAVA_HOME=C:\Program Files\Java\jdk-21
PATH=%JAVA_HOME%\bin;%PATH%
💡 小贴士:Windows用户可以在命令提示符里输入
set JAVA_HOME查看是否设置成功;Mac/Linux用户用echo $JAVA_HOME。
接着,打开终端跑两行命令验证一下:
java -version
javac -version
如果看到类似这样的输出:
openjdk version "21" 2023-09-19
OpenJDK Runtime Environment (build 21+35-2368)
OpenJDK 64-Bit Server VM (build 21+35-2368, mixed mode)
恭喜!你的开发环境已经就绪 ✅
现在来写第一个程序吧。新建一个文件叫 HelloWorld.java ,内容如下:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
注意几点:
- 类名必须和文件名完全一致(包括大小写)
- main 方法是程序入口,少一个字符都会报错
- 输出语句结尾的分号不能丢!
保存后,在终端执行:
javac HelloWorld.java # 编译 → 生成 HelloWorld.class
java HelloWorld # 运行 → 输出结果
当你看到屏幕上蹦出 “Hello World”,你就正式踏入Java的世界了 🎉
变量、类型与运算:构建程序的基石
写程序的本质是什么?说白了就是 操作数据 。而变量,就是我们用来装数据的“盒子”。
Java是个“强类型”语言,这意味着每个盒子在创建时就得明确告诉编译器:“我只能装整数”或者“我专门放小数”。这种看似麻烦的规定,其实是防止你在后期把字符串塞进年龄字段里的救命绳索。
基本数据类型一览表
| 类型 | 关键字 | 字节 | 范围/说明 |
|---|---|---|---|
| 字节型 | byte | 1 | -128 ~ 127 |
| 短整型 | short | 2 | -32,768 ~ 32,767 |
| 整型 | int | 4 | ±21亿左右,最常用 |
| 长整型 | long | 8 | 极大数值,如时间戳 |
| 单精度浮点 | float | 4 | 科学计算用,末尾加 f |
| 双精度浮点 | double | 8 | 默认浮点类型 |
| 字符型 | char | 2 | Unicode字符,单引号 |
| 布尔型 | boolean | - | true/false |
来看个实际例子:
public class DataTypeExample {
public static void main(String[] args) {
byte age = 25; // 年龄不会超127,省空间
short year = 2025; // 存年份刚刚好
long bigNumber = 8_000_000_000L; // 数字太大,int装不下,后面加L
float price = 9.99f; // float默认是double,得加f
char grade = 'A'; // 注意是单引号!双引号是字符串
boolean isActive = true;
System.out.println("年龄:" + age);
System.out.println("价格:" + price);
System.out.println("等级:" + grade);
}
}
有几个坑你一定要避开:
- int population = 8_000_000_000; ❌ 直接报错!因为超过了int最大值
- float pi = 3.14; ❌ 默认是double类型,赋给float会丢失精度
- char c = "a"; ❌ 字符必须用单引号
🔍 技巧:数字中的下划线
_是Java 7引入的语法糖,只是为了增强可读性,不影响值。比如1_000_000比1000000更容易数清楚零的个数。
变量的作用域:谁能在哪看到它?
变量不是随随便便就能访问的。Java有一套清晰的作用域规则,决定了某个变量“活”在哪个范围里。
局部变量:方法内的临时工
定义在方法或代码块内部的变量,只在当前作用域有效:
public class ScopeExample {
public static void main(String[] args) {
int x = 10;
if (x > 5) {
int y = 20; // y只在这个if块里能用
System.out.println(x + y); // OK
}
// System.out.println(y); // ❌ 编译错误!y已死
}
}
局部变量有个铁律: 必须显式初始化才能使用 。下面这段代码通不过编译:
int score;
System.out.println(score); // ❌ 错!没赋值就用
成员变量:属于对象的数据
定义在类中、方法外的变量,也叫实例变量。它们随着对象创建而存在,每个对象都有自己的一份副本。
class Student {
String name; // 默认为 null
int age; // 默认为 0
boolean isEnrolled; // 默认为 false
void display() {
System.out.println(name + "今年" + age + "岁");
}
}
和局部变量不同,成员变量即使你不初始化,JVM也会给它们一个“默认值”。但这并不意味着你可以偷懒——依赖默认值会让代码变得难以追踪。
静态变量:全班共享的黑板
加上 static 的变量属于类本身,而不是某个具体对象。所有实例共用同一份数据。
class Counter {
static int count = 0; // 所有Counter对象共享
Counter() {
count++; // 每创建一个对象,计数+1
}
static void showTotal() {
System.out.println("总共创建了" + count + "个对象");
}
}
静态变量适合用于计数器、全局配置、缓存等场景。但要注意别滥用,否则容易引发内存泄漏或并发问题。
类型转换:当不同类型相遇时会发生什么?
表达式中经常出现多种类型混合运算。比如:
int a = 100;
double b = 3.14;
double result = a + b; // 103.14
这里发生了 自动类型提升 :Java会把低精度的 int 自动转成高精度的 double 再进行计算。顺序是:
byte → short → int → long → float → double
但如果反过来呢?想把 double 转成 int :
double d = 98.76;
int i = (int) d; // 结果是98,小数部分直接截断
这就是 强制类型转换 ,需要手动加 (int) 。代价是可能丢失数据。
还有一个容易翻车的例子:
byte b = (byte) 300; // 看似越界了?
System.out.println(b); // 输出:44
为什么是44?因为byte范围是-128~127,超过的部分会按模运算回绕。300 % 256 = 44(256是byte的取值总数)。所以强制转换前一定要检查数值范围!
运算符优先级:别让括号替你思考
多个运算符在一起时,谁先算?记住这张表就够了:
| 优先级 | 运算符 | 示例 |
|---|---|---|
| 1 | () 括号 |
(a + b) * c |
| 2 | ++ , -- , ! |
!flag , ++i |
| 3 | * , / , % |
a * b + c |
| 4 | + , - |
a + b - c |
| 5 | < , > , <= , >= |
a < b |
| 6 | == , != |
a == b |
| 7 | && |
a > 0 && b < 10 |
| 8 | \|\| |
a == 1 \|\| b == 2 |
| 9 | = , += , etc. |
a += 5 |
举个复杂点的例子:
int x = 5, y = 3, z = 2;
boolean result = x + y > z * 2 && !(y == z);
计算过程分解:
1. 先算 z * 2 = 4
2. 再算 x + y = 8
3. 比较 8 > 4 → true
4. y == z → false ,取反 !false → true
5. 最后 true && true → true
虽然你能算出来,但别人读起来费劲。建议: 复杂的表达式一律加括号 !
boolean result = ((x + y) > (z * 2)) && !(y == z);
一眼就明白,对不对?
面向对象:让代码更像现实世界
如果你之前学过C语言,可能会觉得Java啰嗦:光是一个“学生”就要写一堆getter/setter。但这种“啰嗦”背后藏着一种强大的思维方式—— 面向对象编程(OOP) 。
传统编程关注“怎么做”,比如:
输入姓名 → 存入数组 → 计算长度 → 输出结果
而OOP关心的是“谁来做”:
“学生”这个对象应该有哪些属性?能做什么事?
这种思维转变,是从“码农”迈向“工程师”的关键一步。
封装:把细节关进盒子里
封装的核心思想是: 隐藏内部实现,暴露安全接口 。
想象你有一个银行账户类:
public class BankAccount {
private String accountNumber;
private double balance;
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
if (accountNumber == null || accountNumber.length() != 10) {
throw new IllegalArgumentException("账号必须为10位字符");
}
this.accountNumber = accountNumber;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
if (balance < 0) {
throw new IllegalArgumentException("余额不能为负数");
}
this.balance = balance;
}
}
重点在哪?
- 字段用 private 修饰,外部无法直接修改
- 提供公共方法控制访问,并加入校验逻辑
这样哪怕有人试图 account.setBalance(-1000) ,也会被拦下来。想想看,如果字段是 public 的,谁能保证没人偷偷改余额?
IDE(如IntelliJ IDEA)支持自动生成getter/setter,效率一点不低。关键是你要养成这个习惯。
继承:代码复用的艺术
现实中,“大学生”是一种“人”,“狗”是一种“动物”。这种“is-a”关系,在Java里通过继承实现。
public class Person {
protected String name;
protected int age;
public void introduce() {
System.out.println("我是" + name + ",今年" + age + "岁。");
}
}
class Student extends Person {
private String studentId;
public void study() {
System.out.println(name + "正在学习课程。");
}
}
子类 Student 自动拥有父类 Person 的非私有成员。测试一下:
Student stu = new Student();
stu.name = "张三";
stu.age = 20;
stu.introduce(); // 输出:我是张三,今年20岁。
stu.study(); // 输出:张三正在学习课程。
几个要点:
- Java只支持 单继承 (一个类只能有一个父类),避免菱形继承带来的混乱
- 使用 protected 可以让子类访问父类成员,又不让外部随意修改
- 构造器不会被继承,子类需显式调用 super()
合理使用继承能让共性代码集中管理,个性行为自由扩展。但别过度设计—— 优先使用组合而非继承 ,这是很多老鸟的经验之谈。
多态:同一个动作,不同的表现
多态可能是OOP中最神奇的部分。它允许我们用统一的方式处理不同类型的对象。
继续上面的例子,让 Student 重写介绍方法:
@Override
public void introduce() {
System.out.println("我是学生" + name + ",学号:" + studentId);
}
然后看这段代码:
Person p1 = new Person();
Person p2 = new Student(); // 父类引用指向子类对象
p1.introduce(); // 调用Person的方法
p2.introduce(); // 实际调用Student的方法!
尽管 p2 的声明类型是 Person ,但在运行时JVM会根据实际对象类型决定调用哪个版本。这就是 动态绑定 ,靠虚方法表(vtable)实现。
应用场景太多了:
- Spring框架中 BeanFactory.getBean() 返回不同类型bean
- Android里 onClick(View v) 接收各种按钮点击
- 游戏开发中不同怪物共享 attack() 接口但实现各异
掌握了多态,你就离写出“优雅又灵活”的代码不远了。
数组、字符串与包管理:让代码更有条理
随着项目变大,代码组织成了难题。总不能把几百个类全扔在一个文件夹里吧?这时候就需要 包(package)机制 和一些高效的数据操作技巧。
数组:批量处理数据的第一选择
数组是最基础的集合类型,特点是 固定长度、连续内存、随机访问快 。
声明方式有三种:
// 动态初始化(已知长度)
int[] numbers = new int[5]; // 默认值0
// 静态初始化(已知元素)
double[] scores = new double[]{89.5, 92.0, 78.3};
// 简写形式
String[] names = {"张三", "李四", "王五"};
遍历可以用普通for循环或增强for(foreach):
// 方式一:带索引
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]);
}
// 方式二:更简洁
for (String name : names) {
System.out.println(name);
}
推荐后者,除非你需要索引值。
Java还提供了 Arrays 工具类,极大简化常见操作:
import java.util.Arrays;
int[] data = {5, 2, 8, 1, 9};
Arrays.sort(data); // 排序 → [1,2,5,8,9]
System.out.println(Arrays.toString(data)); // 打印数组内容
int index = Arrays.binarySearch(data, 8); // 二分查找,返回索引
二维数组本质是“数组的数组”,常用于矩阵运算:
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 遍历输出
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + "\t");
}
System.out.println();
}
有趣的是,Java的二维数组可以是“锯齿状”的:
int[][] jagged = {
{1, 2},
{3, 4, 5, 6},
{7}
};
每行长度可以不一样,适合表示不规则数据结构。
字符串操作:小心性能陷阱
String 是Java中最常用的类之一,但它有个重要特性: 不可变性 。
一旦创建,内容就不能改变。任何拼接、替换操作都会产生新对象:
String str = "";
for (int i = 0; i < 1000; i++) {
str += "a"; // 每次都创建新String对象!
}
这段代码会产生上千个临时对象,GC压力巨大。解决方案?用 StringBuilder !
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("a"); // 在缓冲区追加,不创建新对象
}
String result = sb.toString();
性能差距有多大?做个实验:
long start = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 50000; i++) sb.append("x");
System.out.println("StringBuilder耗时:" + (System.currentTimeMillis() - start) + "ms");
start = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 50000; i++) s += "x";
System.out.println("String拼接耗时:" + (System.currentTimeMillis() - start) + "ms");
在我的机器上,前者不到1ms,后者接近2秒!差了上千倍。
常用方法总结:
| 方法 | 用途 | 示例 |
|---|---|---|
substring() |
截取子串 | "hello".substring(1,4) → “ell” |
indexOf() |
查找位置 | "world".indexOf('o') → 1 |
equals() |
内容比较 | "abc".equals("ABC") → false |
equalsIgnoreCase() |
忽略大小写比较 | true |
trim() |
去除首尾空白 | " abc ".trim() → “abc” |
toUpperCase() / toLowerCase() |
大小写转换 | |
startsWith() / endsWith() |
前缀/后缀判断 |
记住:永远不要用 == 比较字符串内容!那是比较引用地址。
包与访问控制:打造模块化代码结构
大型项目必须分包管理。Java的包机制映射到文件系统:
src/
└── com/
└── example/
├── utils/
│ └── MathHelper.java
└── app/
└── Main.java
在 MathHelper.java 中声明:
package com.example.utils;
public class MathHelper {
public static int add(int a, int b) {
return a + b;
}
}
另一个包中的类要使用它,就得导入:
package com.example.app;
import com.example.utils.MathHelper;
public class Main {
public static void main(String[] args) {
int sum = MathHelper.add(3, 5);
System.out.println(sum);
}
}
四种访问修饰符决定了可见性:
| 修饰符 | 同一类 | 同一包 | 子类(不同包) | 其他包 |
|---|---|---|---|---|
| private | ✅ | ❌ | ❌ | ❌ |
| default | ✅ | ✅ | ❌ | ❌ |
| protected | ✅ | ✅ | ✅ | ❌ |
| public | ✅ | ✅ | ✅ | ✅ |
最佳实践:
- 字段尽量私有,通过getter/setter访问
- 工具类方法设为 public static
- 包级私有(default)适合内部协作类,对外隐藏
还可以使用静态导入简化代码:
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
double area = PI * 10 * 10;
double root = sqrt(16);
但别滥用,否则别人看不懂这些常量来自哪里。
抽象类与接口:定义规范的力量
到了进阶阶段,你会发现光靠继承不够用了。我们需要更强的抽象能力来应对复杂系统。
抽象类:提供部分实现的模板
有时候,父类无法给出完整的方法实现,只能规定“子类必须实现这个功能”。
abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// 抽象方法:没有方法体
public abstract void makeSound();
// 普通方法:可以被继承
public void sleep() {
System.out.println(name + " 正在睡觉");
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " 汪汪叫");
}
}
特点:
- 不能被实例化
- 可包含构造器、成员变量、普通方法
- 至少有一个抽象方法
适合用于“基类提供通用功能,子类定制特殊行为”的场景。
接口:多重行为的契约
如果说抽象类是“是什么”,那接口就是“能做什么”。
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("鸭子飞行");
}
@Override
public void swim() {
System.out.println("鸭子游泳");
}
}
Java允许一个类实现多个接口,从而获得多重能力。这弥补了单继承的局限。
从Java 8开始,接口还能有默认方法:
interface Loggable {
default void log(String msg) {
System.out.println("[LOG]" + msg);
}
static void info() {
System.out.println("这是日志接口");
}
}
好处是可以在不破坏旧实现的前提下添加新功能。比如JDK集合框架就在 Collection 接口中新增了许多默认方法。
对比一下抽象类和接口:
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 是否可含具体方法 | 是 | Java 8+ 支持默认方法 |
| 属性 | 可任意访问级别 | 全为 public static final |
| 多继承支持 | 否 | 是 |
| 构造器 | 可定义 | 不可定义 |
现代设计趋势是 优先使用接口 ,配合默认方法实现灵活组合。
设计模式初体验:写出更聪明的代码
设计模式不是语法,而是解决常见问题的“套路”。掌握几个基础模式,能让你的代码质量飞跃。
单例模式:全局唯一的实例
有些资源只需要一份,比如数据库连接池、日志管理器。
饿汉式(简单安全)
public class SingletonEager {
private static final SingletonEager INSTANCE = new SingletonEager();
private SingletonEager() {} // 私有构造器
public static SingletonEager getInstance() {
return INSTANCE;
}
}
优点:线程安全,实现简单
缺点:类加载时就创建,可能浪费资源
懒汉式(延迟加载)
public class SingletonLazy {
private static SingletonLazy instance;
private SingletonLazy() {}
public static synchronized SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
synchronized 保证线程安全,但每次调用都要加锁,影响性能。
双重检查锁定(推荐)
public class SingletonDoubleCheck {
private static volatile SingletonDoubleCheck instance;
private SingletonDoubleCheck() {}
public static SingletonDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingletonDoubleCheck.class) {
if (instance == null) {
instance = new SingletonDoubleCheck();
}
}
}
return instance;
}
}
既实现了延迟加载,又避免了不必要的同步开销。 volatile 关键字防止指令重排序,确保对象发布安全。
工厂模式:解耦对象创建逻辑
客户端不应该关心具体创建哪个类。工厂模式把创建过程封装起来:
interface Shape {
void draw();
}
class Circle implements Shape { @Override public void draw() { /*...*/ } }
class Rectangle implements Shape { @Override public void draw() { /*...*/ } }
class ShapeFactory {
public static Shape getShape(String type) {
switch (type.toLowerCase()) {
case "circle": return new Circle();
case "rectangle": return new Rectangle();
default: throw new IllegalArgumentException("未知形状");
}
}
}
调用方只需:
Shape shape = ShapeFactory.getShape("circle");
shape.draw();
优势:
- 客户端无需知道具体类名
- 易于扩展新类型(符合开闭原则)
- 创建逻辑集中管理,便于维护
实战项目:做一个图书管理系统
理论学了一堆,是时候动手做个完整的项目了。我们要做一个控制台版的 简易图书管理系统 ,涵盖前面讲的所有知识点。
功能需求
- 添加图书(编号、书名、作者、年份)
- 按书名或作者模糊查询
- 根据ID删除图书
- 显示全部图书列表
- 菜单交互式操作
类设计
| 类名 | 职责 |
|---|---|
Book |
封装图书属性,提供getter/setter |
BookService |
管理图书集合,实现增删查 |
Main |
主程序,处理用户输入与菜单 |
Book类:数据模型
public class Book {
private int id;
private String title;
private String author;
private int publishYear;
public Book(int id, String title, String author, int publishYear) {
this.id = id;
this.title = title;
this.author = author;
this.publishYear = publishYear;
}
// getter/setter 省略...
@Override
public String toString() {
return String.format("%-5d %-20s %-15s %-6d", id, title, author, publishYear);
}
}
重写 toString() 是为了格式化输出,表格对齐更美观。
BookService:业务逻辑中心
import java.util.ArrayList;
import java.util.List;
public class BookService {
private List<Book> books = new ArrayList<>();
public void addBook(Book book) {
books.add(book);
System.out.println("✅ 图书《" + book.getTitle() + "》添加成功!");
}
public List<Book> searchByTitle(String keyword) {
List<Book> result = new ArrayList<>();
for (Book book : books) {
if (book.getTitle().toLowerCase().contains(keyword.toLowerCase())) {
result.add(book);
}
}
return result;
}
public List<Book> searchByAuthor(String keyword) {
List<Book> result = new ArrayList<>();
for (Book book : books) {
if (book.getAuthor().toLowerCase().contains(keyword.toLowerCase())) {
result.add(book);
}
}
return result;
}
public boolean deleteBook(int id) {
return books.removeIf(book -> book.getId() == id);
}
public void displayAllBooks() {
if (books.isEmpty()) {
System.out.println("📚 当前无任何图书记录。");
return;
}
System.out.printf("%-5s %-20s %-15s %-6s\n", "ID", "书名", "作者", "年份");
System.out.println("---------------------------------------------");
for (Book book : books) {
System.out.println(book);
}
}
}
亮点:
- 使用 ArrayList 替代数组,自动扩容
- removeIf() 简化删除逻辑
- 查询时不区分大小写,用户体验更好
- 表格输出对齐,视觉清爽
主程序:交互入口
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
BookService service = new BookService();
int nextId = 1;
while (true) {
System.out.println("\n========== 图书管理系统 ==========");
System.out.println("1. 添加图书");
System.out.println("2. 查询图书(按书名)");
System.out.println("3. 查询图书(按作者)");
System.out.println("4. 删除图书");
System.out.println("5. 查看所有图书");
System.out.println("6. 退出系统");
System.out.print("请选择操作:");
int choice = getIntInput(scanner);
switch (choice) {
case 1:
// 添加逻辑...
break;
case 2:
// 查询逻辑...
break;
// ...其余case省略
case 6:
System.out.println("👋 感谢使用,再见!");
scanner.close();
return;
default:
System.out.println("⚠️ 无效选项,请重新选择。");
}
}
}
private static int getIntInput(Scanner scanner) {
while (!scanner.hasNextInt()) {
System.out.print("请输入有效的数字:");
scanner.next();
}
int value = scanner.nextInt();
scanner.nextLine(); // 消费换行符
return value;
}
private static void displayResults(List<Book> results) {
if (results.isEmpty()) {
System.out.println("🔍 未找到匹配的图书。");
} else {
System.out.printf("%-5s %-20s %-15s %-6s\n", "ID", "书名", "作者", "年份");
System.out.println("---------------------------------------------");
for (Book b : results) {
System.out.println(b);
}
}
}
}
这个项目虽小,却麻雀虽小五脏俱全:
- 面向对象设计
- 控制台交互
- 异常输入处理
- 数据结构操作
- 格式化输出
你可以继续扩展它:
- 加入文件存储实现持久化
- 用Swing或JavaFX做图形界面
- 改造成Web应用,接入数据库
写在最后:编程是一场马拉松
看到这里,你已经完成了从环境搭建到项目实战的完整闭环。也许有些概念还需要反复咀嚼,比如多态的动态绑定、双重检查锁定的内存屏障……没关系,没人一开始就能吃透所有东西。
真正重要的不是记住了多少语法,而是建立起一套解决问题的思维方式。当你面对一个新需求时,能自然地想到:“这应该拆成几个类?”、“哪些该封装?”、“要不要用工厂?”——那一刻,你就真正入门了。
Java这条路很长,今天我们只是走了第一步。前方还有集合框架、异常处理、泛型、注解、反射、多线程、网络编程……每一关都值得深入探索。
但别忘了初心。就像那个简单的 Hello World ,它提醒我们:编程的本质,是让机器听懂人类的想法。而你能做到这一点,就已经很酷了 😎
更多推荐


所有评论(0)