Skip to content

Java 面向对象从入门到精通:基础、API与ATM系统实战

本文专为零基础新手设计,从面向对象核心概念讲起,逐步过渡到常用API的使用,最终通过一个完整的ATM系统实战,帮助你掌握Java面向对象编程思想。所有代码均附带详细注释,确保新手能轻松理解。

一、面向对象基础(从概念到代码)

1. 什么是面向对象?

  • 面向过程:关注"步骤"(如做蛋糕:打鸡蛋→拌面粉→烘烤)
  • 面向对象:关注"对象"(如做蛋糕:找厨师→用烤箱→用模具,对象是厨师、烤箱、模具)

面向对象的核心思想:将复杂问题拆解为多个对象,通过对象间的交互解决问题

2. 类与对象(核心概念)

  • 类(Class):抽象的"模板",定义对象的属性(特征)和方法(行为)。比如"手机类"定义了手机有品牌、价格(属性),能打电话、发短信(方法)。
  • 对象(Object):类的具体"实例"。比如"我的iPhone"是"手机类"的一个对象,品牌是Apple,价格是5999,能实际打电话。

(1)定义类(模板)

语法:

java
public class 类名 {
    // 属性(成员变量):定义对象的特征
    数据类型 属性名;
    
    // 方法:定义对象的行为
    方法返回值类型 方法名() {
        // 方法体
    }
}

示例:定义一个"学生类"

java
// 学生类(模板)
public class Student {
    // 属性(特征):姓名、年龄、学号
    String name;  // 姓名
    int age;      // 年龄
    String id;    // 学号
    
    // 方法(行为):学习
    public void study() {
        // 方法中可以使用属性(this代表当前对象)
        System.out.println(this.name + "正在学习,学号是" + this.id);
    }
    
    // 方法(行为):介绍自己
    public void introduce() {
        System.out.println("大家好,我叫" + name + ",今年" + age + "岁");
    }
}

(2)创建对象(实例化)

语法:类名 对象名 = new 类名();
通过对象名.属性对象名.方法()使用对象。

示例:用"学生类"创建对象

java
public class TestStudent {
    public static void main(String[] args) {
        // 创建第一个学生对象(实例)
        Student stu1 = new Student();
        // 给对象的属性赋值
        stu1.name = "张三";
        stu1.age = 18;
        stu1.id = "2023001";
        // 调用对象的方法
        stu1.study();       // 输出:张三正在学习,学号是2023001
        stu1.introduce();   // 输出:大家好,我叫张三,今年18岁
        
        // 创建第二个学生对象
        Student stu2 = new Student();
        stu2.name = "李四";
        stu2.age = 19;
        stu2.id = "2023002";
        stu2.introduce();   // 输出:大家好,我叫李四,今年19岁
    }
}

新手注意

  • 类名首字母大写(如Student),对象名首字母小写(如stu1),遵循驼峰命名法。
  • 每个对象的属性是独立的,修改stu1name不会影响stu2

3. 构造器(初始化对象的特殊方法)

创建对象时,new后面的类名()其实是在调用构造器(Constructor),用于初始化对象的属性。

(1)默认构造器

如果类中没有定义构造器,Java会自动生成一个无参数的默认构造器,如:

java
public class Student {
    // 默认构造器(隐藏)
    public Student() {
    }
}

(2)自定义构造器

我们可以手动定义构造器,实现属性的初始化(比如创建对象时直接给姓名和年龄赋值)。

语法:

java
public 类名(参数列表) {
    // 初始化属性
}

示例:给学生类添加构造器

java
public class Student {
    String name;
    int age;
    String id;
    
    // 无参构造器(手动定义后,默认构造器会消失)
    public Student() {
    }
    
    // 有参构造器:创建对象时直接赋值姓名和年龄
    public Student(String n, int a) {
        name = n;  // 将参数n赋值给属性name
        age = a;   // 将参数a赋值给属性age
    }
    
    // 有参构造器:创建对象时赋值所有属性
    public Student(String n, int a, String i) {
        name = n;
        age = a;
        id = i;
    }
    
    // 方法省略...
}

使用自定义构造器创建对象:

java
public class TestConstructor {
    public static void main(String[] args) {
        // 调用无参构造器(需手动赋值)
        Student stu1 = new Student();
        stu1.name = "王五";
        stu1.age = 20;
        
        // 调用有参构造器(直接赋值)
        Student stu2 = new Student("赵六", 21);  // 姓名=赵六,年龄=21
        Student stu3 = new Student("钱七", 22, "2023003");  // 全属性赋值
        
        stu2.introduce();  // 输出:大家好,我叫赵六,今年21岁
    }
}

新手注意

  • 构造器名必须与类名完全相同,且没有返回值类型(连void都不能有)。
  • 定义有参构造器后,默认无参构造器会消失,如需使用需手动添加。

(3)this关键字的用法

  • 区分成员变量(类中定义的属性)和局部变量(方法中的参数或变量)。
  • 在构造器中调用其他构造器(this(参数),必须放在第一行)。

示例:用this优化构造器

java
public class Student {
    String name;
    int age;
    String id;
    
    // 无参构造器
    public Student() {
    }
    
    // 有参构造器1:给name和age赋值
    public Student(String name, int age) {
        // this.name指成员变量,name指参数
        this.name = name;  
        this.age = age;
    }
    
    // 有参构造器2:调用构造器1,再给id赋值
    public Student(String name, int age, String id) {
        this(name, age);  // 调用上面的构造器(必须在第一行)
        this.id = id;
    }
}

4. 封装(面向对象三大特性之一)

封装:将对象的属性隐藏(用private修饰),只通过公共方法(getter/setter)访问和修改,保护数据安全。

(1)为什么需要封装?

如果属性直接暴露(用public),可能被随意修改导致数据错误(比如年龄设置为负数)。封装可以在方法中添加验证逻辑。

(2)封装的步骤

  1. private修饰属性(私有属性,只能在类内部访问)。
  2. 提供publicgetter方法(获取属性值)和setter方法(设置属性值,可添加验证)。

示例:封装学生类的年龄属性

java
public class Student {
    private String name;  // 私有属性
    private int age;      // 私有属性(年龄不能为负数)
    private String id;
    
    // 无参构造器
    public Student() {
    }
    
    // getter方法:获取name
    public String getName() {
        return name;
    }
    
    // setter方法:设置name
    public void setName(String name) {
        this.name = name;
    }
    
    // getter方法:获取age
    public int getAge() {
        return age;
    }
    
    // setter方法:设置age,添加验证(年龄不能小于0)
    public void setAge(int age) {
        if (age < 0) {
            System.out.println("年龄不能为负数,已默认设为0");
            this.age = 0;  // 非法值时设为默认值
        } else {
            this.age = age;
        }
    }
    
    // 其他方法省略...
}

使用封装后的对象:

java
public class TestEncapsulation {
    public static void main(String[] args) {
        Student stu = new Student();
        // 不能直接访问私有属性(编译报错):stu.age = -5;
        stu.setName("孙八");
        stu.setAge(-5);  // 输出:年龄不能为负数,已默认设为0
        System.out.println(stu.getName() + "的年龄是" + stu.getAge());  // 孙八的年龄是0
    }
}

新手总结:封装的核心是"私有属性,公共方法",通过方法控制属性的访问,保证数据合法性。

二、常用API(String与ArrayList)

API(Application Programming Interface)是Java提供的预定义类和方法,直接调用即可实现功能,无需重复开发。

1. String类(字符串处理)

String用于表示字符串(如"hello"),是Java中最常用的类之一。

(1)String的特点

  • 不可变性:字符串创建后内容不可修改,修改会产生新的String对象。
  • 直接赋值时,相同内容的字符串会共享内存(常量池)。

(2)常用方法(附代码示例)

方法功能示例
length()获取字符串长度"abc".length() → 3
charAt(int index)获取指定索引的字符(索引从0开始)"hello".charAt(1) → 'e'
equals(String s)比较字符串内容是否相等(区分大小写)"abc".equals("ABC") → false
equalsIgnoreCase(String s)比较内容(不区分大小写)"abc".equalsIgnoreCase("ABC") → true
indexOf(String s)查找子串首次出现的索引(没找到返回-1)"abcde".indexOf("cd") → 2
substring(int start)从start索引截取到末尾"abcde".substring(2) → "cde"
substring(int start, int end)截取[start, end)范围(含头不含尾)"abcde".substring(1,3) → "bc"
replace(char old, char new)替换字符"hello".replace('l','x') → "hexxo"
split(String regex)按指定规则分割字符串为数组"a,b,c".split(",") → ["a","b","c"]
trim()去除首尾空格" abc ".trim() → "abc"

示例代码:

java
public class StringDemo {
    public static void main(String[] args) {
        String s = "Hello, Java!";
        
        // 获取长度
        System.out.println("长度:" + s.length());  // 输出:11
        
        // 获取索引1的字符
        System.out.println("索引1的字符:" + s.charAt(1));  // 输出:e
        
        // 截取子串(从7到末尾)
        String sub = s.substring(7);
        System.out.println("截取结果:" + sub);  // 输出:Java!
        
        // 替换字符
        String replaced = s.replace('J', 'j');
        System.out.println("替换后:" + replaced);  // 输出:Hello, java!
        
        // 分割字符串(按","分割)
        String s2 = "apple,banana,orange";
        String[] fruits = s2.split(",");
        for (String fruit : fruits) {
            System.out.println(fruit);  // 依次输出apple、banana、orange
        }
    }
}

新手注意

  • 比较字符串内容必须用equals(),不能用====比较的是内存地址)。
  • 不可变性示例:s = s + "!"会创建新对象,原s的内容不变。

2. ArrayList(动态数组)

数组的长度固定,ArrayList是长度可变的"动态数组",可随时添加或删除元素,适合存储不确定数量的数据。

(1)创建ArrayList

需导入java.util.ArrayList,语法:

java
// 存储String类型的ArrayList
ArrayList<String> list = new ArrayList<>();

// 存储Integer(整数)类型的ArrayList
ArrayList<Integer> numbers = new ArrayList<>();

<String>泛型,指定集合中只能存储的类型(新手可理解为"元素类型")。

(2)常用方法(附代码示例)

方法功能示例
add(E e)添加元素到末尾list.add("苹果")
add(int index, E e)在指定索引插入元素list.add(1, "香蕉")
get(int index)获取指定索引的元素list.get(0)
remove(int index)删除指定索引的元素list.remove(1)
remove(Object o)删除指定元素list.remove("苹果")
size()获取元素个数list.size()
set(int index, E e)修改指定索引的元素list.set(0, "西瓜")
clear()清空所有元素list.clear()
contains(Object o)判断是否包含某元素list.contains("香蕉")

示例代码:

java
import java.util.ArrayList;  // 必须导入

public class ArrayListDemo {
    public static void main(String[] args) {
        // 创建存储字符串的ArrayList
        ArrayList<String> fruits = new ArrayList<>();
        
        // 添加元素
        fruits.add("苹果");
        fruits.add("香蕉");
        fruits.add("橙子");
        System.out.println("添加后:" + fruits);  // 输出:[苹果, 香蕉, 橙子]
        
        // 获取元素(索引0)
        String first = fruits.get(0);
        System.out.println("第一个元素:" + first);  // 输出:苹果
        
        // 修改元素(索引1改为"葡萄")
        fruits.set(1, "葡萄");
        System.out.println("修改后:" + fruits);  // 输出:[苹果, 葡萄, 橙子]
        
        // 删除元素(索引2)
        fruits.remove(2);
        System.out.println("删除后:" + fruits);  // 输出:[苹果, 葡萄]
        
        // 遍历元素(用for循环)
        System.out.println("遍历元素:");
        for (int i = 0; i < fruits.size(); i++) {
            System.out.println(fruits.get(i));  // 依次输出苹果、葡萄
        }
    }
}

新手注意

  • ArrayList的索引也是从0开始,越界会报错。
  • 泛型只能是引用类型(如StringInteger),不能是基本类型(如int,需用Integer替代)。

三、综合项目实战:ATM系统

1. 需求分析

模拟ATM机的基本功能:

  • 用户登录(账号+密码)
  • 查询余额
  • 存款
  • 取款
  • 转账
  • 退出系统

2. 系统设计(类结构)

  • Account类:封装账户信息(卡号、密码、余额、姓名)。
  • ATMSystem类:实现ATM的核心功能(登录、查询、存取款等)。
  • Test类:主程序入口,启动ATM系统。

3. 代码实现(分步讲解)

(1)Account类(账户信息封装)

java
public class Account {
    // 私有属性(封装)
    private String cardId;    // 卡号
    private String password;  // 密码
    private double money;     // 余额
    private String name;      // 姓名

    // 无参构造器
    public Account() {
    }

    // 有参构造器(创建账户时初始化信息)
    public Account(String cardId, String password, double money, String name) {
        this.cardId = cardId;
        this.password = password;
        this.money = money;
        this.name = name;
    }

    // getter和setter方法(访问和修改私有属性)
    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

(2)ATMSystem类(核心功能实现)

java
import java.util.ArrayList;
import java.util.Scanner;

public class ATMSystem {
    // 用ArrayList存储所有账户(系统初始化时添加测试账户)
    private ArrayList<Account> accounts = new ArrayList<>();
    private Scanner sc = new Scanner(System.in);  // 用于输入
    private Account loginAccount;  // 记录当前登录的账户

    // 系统初始化:添加测试账户
    public void init() {
        Account acc1 = new Account("1001", "123456", 10000, "张三");
        Account acc2 = new Account("1002", "654321", 5000, "李四");
        accounts.add(acc1);
        accounts.add(acc2);
    }

    // 启动ATM系统
    public void start() {
        init();  // 初始化账户
        while (true) {
            System.out.println("===欢迎使用ATM系统===");
            System.out.println("1. 登录");
            System.out.println("2. 退出");
            System.out.print("请选择:");
            int choice = sc.nextInt();
            switch (choice) {
                case 1:
                    login();  // 登录
                    break;
                case 2:
                    System.out.println("谢谢使用,再见!");
                    return;  // 退出程序
                default:
                    System.out.println("输入错误,请重新选择!");
            }
        }
    }

    // 登录功能
    private void login() {
        System.out.println("===登录===");
        if (accounts.size() == 0) {
            System.out.println("系统中无账户,请先开户(本系统暂不支持开户,已预设测试账户)");
            return;
        }

        // 输入卡号
        System.out.print("请输入卡号:");
        String cardId = sc.next();

        // 查找账户
        Account acc = findAccount(cardId);
        if (acc == null) {
            System.out.println("卡号不存在!");
            return;
        }

        // 验证密码(最多输3次)
        for (int i = 0; i < 3; i++) {
            System.out.print("请输入密码:");
            String pwd = sc.next();
            if (acc.getPassword().equals(pwd)) {
                System.out.println("登录成功!欢迎您," + acc.getName() + "!");
                loginAccount = acc;  // 记录当前登录账户
                showMainMenu();  // 进入主菜单
                return;
            } else {
                if (i == 2) {
                    System.out.println("密码错误3次,登录失败!");
                    return;
                }
                System.out.println("密码错误,还有" + (2 - i) + "次机会");
            }
        }
    }

    // 主菜单(登录后显示)
    private void showMainMenu() {
        while (true) {
            System.out.println("===主菜单===");
            System.out.println("1. 查询余额");
            System.out.println("2. 存款");
            System.out.println("3. 取款");
            System.out.println("4. 转账");
            System.out.println("5. 退出登录");
            System.out.print("请选择:");
            int choice = sc.nextInt();
            switch (choice) {
                case 1:
                    queryBalance();
                    break;
                case 2:
                    deposit();
                    break;
                case 3:
                    withdraw();
                    break;
                case 4:
                    transfer();
                    break;
                case 5:
                    System.out.println("已退出登录");
                    loginAccount = null;  // 清空登录状态
                    return;
                default:
                    System.out.println("输入错误,请重新选择!");
            }
        }
    }

    // 查询余额
    private void queryBalance() {
        System.out.println("===查询余额===");
        System.out.println("您的余额为:" + loginAccount.getMoney() + "元");
    }

    // 存款
    private void deposit() {
        System.out.println("===存款===");
        System.out.print("请输入存款金额:");
        double money = sc.nextDouble();
        if (money <= 0) {
            System.out.println("存款金额必须大于0!");
            return;
        }
        // 更新余额(原有余额+存款金额)
        loginAccount.setMoney(loginAccount.getMoney() + money);
        System.out.println("存款成功,当前余额:" + loginAccount.getMoney() + "元");
    }

    // 取款
    private void withdraw() {
        System.out.println("===取款===");
        double balance = loginAccount.getMoney();
        System.out.print("请输入取款金额:");
        double money = sc.nextDouble();

        // 验证金额
        if (money <= 0) {
            System.out.println("取款金额必须大于0!");
            return;
        }
        if (money > balance) {
            System.out.println("余额不足,当前余额:" + balance + "元");
            return;
        }

        // 更新余额(原有余额-取款金额)
        loginAccount.setMoney(balance - money);
        System.out.println("取款成功,当前余额:" + loginAccount.getMoney() + "元");
    }

    // 转账
    private void transfer() {
        System.out.println("===转账===");
        if (accounts.size() < 2) {
            System.out.println("系统中账户不足,无法转账");
            return;
        }

        // 输入目标卡号
        System.out.print("请输入目标卡号:");
        String targetCardId = sc.next();

        // 不能转给自己
        if (targetCardId.equals(loginAccount.getCardId())) {
            System.out.println("不能向自己转账!");
            return;
        }

        // 查找目标账户
        Account targetAccount = findAccount(targetCardId);
        if (targetAccount == null) {
            System.out.println("目标卡号不存在!");
            return;
        }

        // 验证目标账户姓名(防止输错卡号)
        System.out.print("请输入目标账户姓名:");
        String name = sc.next();
        if (!name.equals(targetAccount.getName())) {
            System.out.println("目标账户姓名错误!");
            return;
        }

        // 输入转账金额
        System.out.print("请输入转账金额:");
        double money = sc.nextDouble();
        double balance = loginAccount.getMoney();

        // 验证金额
        if (money <= 0) {
            System.out.println("转账金额必须大于0!");
            return;
        }
        if (money > balance) {
            System.out.println("余额不足,当前余额:" + balance + "元");
            return;
        }

        // 执行转账(当前账户减钱,目标账户加钱)
        loginAccount.setMoney(balance - money);
        targetAccount.setMoney(targetAccount.getMoney() + money);
        System.out.println("转账成功,向" + targetAccount.getName() + "转账" + money + "元,当前余额:" + loginAccount.getMoney() + "元");
    }

    // 工具方法:根据卡号查找账户
    private Account findAccount(String cardId) {
        for (Account acc : accounts) {
            if (acc.getCardId().equals(cardId)) {
                return acc;  // 找到返回账户
            }
        }
        return null;  // 没找到返回null
    }
}

(3)Test类(启动程序)

java
public class Test {
    public static void main(String[] args) {
        // 创建ATM系统并启动
        ATMSystem atm = new ATMSystem();
        atm.start();
    }
}

4. 系统说明与使用流程

  1. 测试账户:系统初始化了两个账户:

    • 卡号1001,密码123456,余额10000元,姓名张三
    • 卡号1002,密码654321,余额5000元,姓名李四
  2. 使用步骤

    • 运行Test类启动系统,选择"1. 登录"
    • 输入卡号和密码(如1001和123456)
    • 登录后可进行查询、存款、取款、转账等操作
    • 转账时可向1002账户转账(需输入目标姓名"李四")

四、从入门到精通的总结

  1. 面向对象基础

    • 类是模板,对象是实例,通过new创建对象。
    • 构造器用于初始化对象,this区分成员变量和局部变量。
    • 封装通过privategetter/setter保护数据,是面向对象的核心思想。
  2. 常用API

    • String处理字符串,注意equals()比较内容,==比较地址。
    • ArrayList是动态数组,适合存储可变数量的数据,掌握addgetremove等方法。
  3. 项目实战

    • ATM系统综合运用了类、对象、封装、ArrayList等知识,通过面向对象的方式拆分功能,使代码更清晰易维护。
    • 新手可尝试扩展功能(如修改密码、查询明细),加深对面向对象的理解。

Released under the MIT License.