跳转至

JavaSE(二)面向对象编程

在 Java 中,一切皆对象。面向对象编程(Object-Oriented Programming,OOP)是 Java 语言的核心特性,它通过封装、继承和多态三大特性,让代码更加模块化、可重用和易于维护。本教程将深入讲解 Java 面向对象编程的各个方面,从基础概念到高级特性,帮助你掌握面向对象编程的核心思想。

一、类和对象

(一)类(Class)

类是对象的模板或蓝图,定义了同一类对象共有的属性(字段)和行为(方法)。

示例:定义一个学生类

public class Student {
    // 属性(字段)
    private String name;      // 姓名
    private int age;          // 年龄
    private String studentId; // 学号
    private double score;     // 成绩

    // 构造方法
    public Student() {
        // 无参构造方法
    }

    public Student(String name, int age, String studentId, double score) {
        this.name = name;
        this.age = age;
        this.studentId = studentId;
        this.score = score;
    }

    // 方法
    public void study() {
        System.out.println(name + " 正在学习");
    }

    public void takeExam() {
        System.out.println(name + " 正在考试");
    }

    // Getter 和 Setter 方法
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getStudentId() {
        return studentId;
    }

    public void setStudentId(String studentId) {
        this.studentId = studentId;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    // 重写 toString 方法
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", studentId='" + studentId + '\'' +
                ", score=" + score +
                '}';
    }
}

(二)对象(Object)

对象是类的实例,通过 new 关键字创建。

示例:创建和使用对象

public class StudentDemo {
    public static void main(String[] args) {
        // 创建对象
        Student student1 = new Student("张三", 20, "2023001", 90.5);
        Student student2 = new Student("李四", 21, "2023002", 85.0);

        // 调用方法
        student1.study();
        student2.takeExam();

        // 访问属性(通过 getter 方法)
        System.out.println("学生1: " + student1.toString());
        System.out.println("学生2: " + student2);

        // 修改属性(通过 setter 方法)
        student1.setScore(95.0);
        System.out.println("修改后的成绩: " + student1.getScore());
    }
}

(三)构造方法(Constructor)

构造方法用于创建对象时初始化对象的属性。

构造方法的特点: 1. 方法名与类名相同 2. 没有返回值类型(连 void 都没有) 3. 可以重载 4. 如果不定义构造方法,系统会自动提供一个无参构造方法

public class Point {
    private int x;
    private int y;

    // 无参构造方法
    public Point() {
        this(0, 0);  // 调用其他构造方法
    }

    // 两参数构造方法
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    // 复制构造方法
    public Point(Point other) {
        this.x = other.x;
        this.y = other.y;
    }

    // 计算两点之间的距离
    public double distanceTo(Point other) {
        int dx = this.x - other.x;
        int dy = this.y - other.y;
        return Math.sqrt(dx * dx + dy * dy);
    }

    @Override
    public String toString() {
        return "Point(" + x + ", " + y + ")";
    }
}

二、封装(Encapsulation)

封装是面向对象编程的三大特性之一,它将对象的属性和行为封装在一起,并隐藏对象的内部实现细节,只对外提供必要的访问接口。

(一)访问修饰符

Java 提供了四种访问修饰符:

修饰符 同一类 同一包 不同包的子类 不同包的非子类
private ✓ ✗ ✗ ✗
default(无) ✓ ✓ ✗ ✗
protected ✓ ✓ ✓ ✗
public ✓ ✓ ✓ ✓

(二)封装示例

public class BankAccount {
    private String accountNumber;  // 账号
    private String owner;          // 账户持有人
    private double balance;        // 余额

    public BankAccount(String accountNumber, String owner, double initialBalance) {
        this.accountNumber = accountNumber;
        this.owner = owner;
        this.balance = initialBalance;
    }

    // 存款方法
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("存款成功,当前余额: " + balance);
        } else {
            System.out.println("存款金额必须大于0");
        }
    }

    // 取款方法
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("取款成功,当前余额: " + balance);
        } else if (amount > balance) {
            System.out.println("余额不足");
        } else {
            System.out.println("取款金额必须大于0");
        }
    }

    // 查询余额(只读方法)
    public double getBalance() {
        return balance;
    }

    // 转账方法
    public boolean transfer(BankAccount target, double amount) {
        if (amount > 0 && amount <= balance) {
            this.balance -= amount;
            target.balance += amount;
            System.out.println("转账成功");
            return true;
        }
        System.out.println("转账失败");
        return false;
    }

    @Override
    public String toString() {
        return "BankAccount{" +
                "accountNumber='" + accountNumber + '\'' +
                ", owner='" + owner + '\'' +
                ", balance=" + balance +
                '}';
    }
}

三、继承(Inheritance)

继承允许一个类(子类)继承另一个类(父类)的属性和方法,实现代码的重用和扩展。

(一)继承的基本语法

// 父类(基类)
public class Animal {
    private String name;
    private int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println(name + " 正在吃东西");
    }

    public void sleep() {
        System.out.println(name + " 正在睡觉");
    }

    // Getter 和 Setter 方法
    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

// 子类
public class Dog extends Animal {
    private String breed;  // 品种

    public Dog(String name, int age, String breed) {
        super(name, age);  // 调用父类的构造方法
        this.breed = breed;
    }

    // 子类特有的方法
    public void bark() {
        System.out.println(getName() + " 正在汪汪叫");
    }

    // 重写父类的方法
    @Override
    public void eat() {
        System.out.println(getName() + " 正在吃狗粮");
    }

    public String getBreed() {
        return breed;
    }

    public void setBreed(String breed) {
        this.breed = breed;
    }
}

// 另一个子类
public class Cat extends Animal {
    private String color;  // 毛色

    public Cat(String name, int age, String color) {
        super(name, age);
        this.color = color;
    }

    public void meow() {
        System.out.println(getName() + " 正在喵喵叫");
    }

    @Override
    public void eat() {
        System.out.println(getName() + " 正在吃猫粮");
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

(二)super 关键字

super 关键字用于访问父类的成员。

public class Vehicle {
    protected String brand;
    protected int speed;

    public Vehicle(String brand) {
        this.brand = brand;
        this.speed = 0;
    }

    public void accelerate(int increment) {
        speed += increment;
        System.out.println(brand + " 加速到 " + speed + " km/h");
    }
}

public class Car extends Vehicle {
    private int fuelLevel;

    public Car(String brand, int fuelLevel) {
        super(brand);  // 调用父类的构造方法
        this.fuelLevel = fuelLevel;
    }

    @Override
    public void accelerate(int increment) {
        if (fuelLevel > 0) {
            super.accelerate(increment);  // 调用父类的方法
            fuelLevel--;
        } else {
            System.out.println("没有燃料了,无法加速");
        }
    }

    public void refuel(int amount) {
        fuelLevel += amount;
        System.out.println("加油 " + amount + " 升,当前油量: " + fuelLevel);
    }
}

(三)方法重写(Override)

子类可以重写父类的方法,提供新的实现。

public class Shape {
    public double area() {
        return 0;
    }

    public double perimeter() {
        return 0;
    }
}

public class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }

    @Override
    public double perimeter() {
        return 2 * Math.PI * radius;
    }
}

public class Rectangle extends Shape {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double area() {
        return width * height;
    }

    @Override
    public double perimeter() {
        return 2 * (width + height);
    }
}

四、多态(Polymorphism)

多态是指同一个方法在不同的对象上可以有不同的实现方式。多态性让程序更加灵活和可扩展。

(一)方法重载(Overload)

方法重载是指在同一个类中定义多个同名方法,但参数列表不同。

public class Calculator {
    // 两个整数相加
    public int add(int a, int b) {
        return a + b;
    }

    // 三个整数相加
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // 两个浮点数相加
    public double add(double a, double b) {
        return a + b;
    }

    // 数组求和
    public int add(int[] numbers) {
        int sum = 0;
        for (int num : numbers) {
            sum += num;
        }
        return sum;
    }
}

(二)运行时多态(动态绑定)

运行时多态通过继承和方法重写实现。

public class PolymorphismDemo {
    public static void main(String[] args) {
        // 父类引用指向子类对象
        Animal animal1 = new Dog("旺财", 3, "金毛");
        Animal animal2 = new Cat("咪咪", 2, "白色");

        // 调用重写的方法
        animal1.eat();  // 输出: 旺财 正在吃狗粮
        animal2.eat();  // 输出: 咪咪 正在吃猫粮

        // 多态数组
        Animal[] animals = {
            new Dog("大黄", 4, "中华田园犬"),
            new Cat("小白", 1, "黑色"),
            new Dog("小黑", 2, "拉布拉多")
        };

        for (Animal animal : animals) {
            animal.eat();  // 每个动物调用自己重写的 eat 方法
        }
    }
}

(三)instanceof 操作符

instanceof 用于判断对象是否是某个类或其子类的实例。

public class InstanceofDemo {
    public static void main(String[] args) {
        Animal[] animals = {
            new Dog("旺财", 3, "金毛"),
            new Cat("咪咪", 2, "白色")
        };

        for (Animal animal : animals) {
            animal.eat();

            // 类型判断和转换
            if (animal instanceof Dog) {
                Dog dog = (Dog) animal;
                dog.bark();
            } else if (animal instanceof Cat) {
                Cat cat = (Cat) animal;
                cat.meow();
            }
        }
    }
}

五、抽象类和接口

(一)抽象类(Abstract Class)

抽象类不能被实例化,可以包含抽象方法(没有实现的方法)和具体方法。

// 抽象类
public abstract class Employee {
    protected String name;
    protected double baseSalary;

    public Employee(String name, double baseSalary) {
        this.name = name;
        this.baseSalary = baseSalary;
    }

    // 抽象方法(子类必须实现)
    public abstract double calculateSalary();

    // 具体方法
    public void work() {
        System.out.println(name + " 正在工作");
    }

    public String getName() {
        return name;
    }
}

// 子类1:程序员
public class Programmer extends Employee {
    private int overtimeHours;
    private double overtimeRate;

    public Programmer(String name, double baseSalary, int overtimeHours, double overtimeRate) {
        super(name, baseSalary);
        this.overtimeHours = overtimeHours;
        this.overtimeRate = overtimeRate;
    }

    @Override
    public double calculateSalary() {
        return baseSalary + overtimeHours * overtimeRate;
    }
}

// 子类2:销售员
public class Salesperson extends Employee {
    private double salesAmount;
    private double commissionRate;

    public Salesperson(String name, double baseSalary, double salesAmount, double commissionRate) {
        super(name, baseSalary);
        this.salesAmount = salesAmount;
        this.commissionRate = commissionRate;
    }

    @Override
    public double calculateSalary() {
        return baseSalary + salesAmount * commissionRate;
    }
}

(二)接口(Interface)

接口定义了一组方法的规范,类可以实现多个接口。

// 可飞行的接口
public interface Flyable {
    void fly();
    int getMaxAltitude();
}

// 可游泳的接口
public interface Swimmable {
    void swim();
}

// 可爬行的接口
public interface Climbable {
    void climb();
}

// 鸟类(实现了可飞行接口)
public class Bird implements Flyable {
    private String name;

    public Bird(String name) {
        this.name = name;
    }

    @Override
    public void fly() {
        System.out.println(name + " 正在飞翔");
    }

    @Override
    public int getMaxAltitude() {
        return 1000;  // 最大高度1000米
    }
}

// 鸭子(实现了可飞行和可游泳接口)
public class Duck implements Flyable, Swimmable {
    private String name;

    public Duck(String name) {
        this.name = name;
    }

    @Override
    public void fly() {
        System.out.println(name + " 正在飞行");
    }

    @Override
    public int getMaxAltitude() {
        return 500;
    }

    @Override
    public void swim() {
        System.out.println(name + " 正在游泳");
    }
}

// 乌龟(实现了可游泳和可爬行接口)
public class Turtle implements Swimmable, Climbable {
    private String name;

    public Turtle(String name) {
        this.name = name;
    }

    @Override
    public void swim() {
        System.out.println(name + " 正在游泳");
    }

    @Override
    public void climb() {
        System.out.println(name + " 正在爬行");
    }
}

(三)接口的默认方法和静态方法(Java 8+)

public interface MyInterface {
    // 抽象方法
    void doSomething();

    // 默认方法(提供了默认实现)
    default void doDefault() {
        System.out.println("这是默认方法的实现");
    }

    // 静态方法
    static void doStatic() {
        System.out.println("这是静态方法");
    }
}

public class MyClass implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("实现抽象方法");
    }

    // 可以选择重写默认方法
    @Override
    public void doDefault() {
        System.out.println("重写默认方法");
    }
}

六、内部类

Java 支持在一个类内部定义另一个类,称为内部类。

(一)成员内部类

public class OuterClass {
    private int outerData = 10;

    // 成员内部类
    class InnerClass {
        private int innerData = 20;

        public void display() {
            System.out.println("外部类数据: " + outerData);
            System.out.println("内部类数据: " + innerData);
        }
    }

    public void createInner() {
        InnerClass inner = new InnerClass();
        inner.display();
    }
}

(二)静态内部类

public class OuterClass {
    private static int outerStaticData = 10;
    private int outerData = 20;

    // 静态内部类
    static class StaticInnerClass {
        private int innerData = 30;

        public void display() {
            System.out.println("外部类静态数据: " + outerStaticData);
            // 不能访问外部类的非静态成员
            System.out.println("内部类数据: " + innerData);
        }
    }
}

(三)局部内部类

public class OuterClass {
    public void methodWithLocalClass() {
        // 局部内部类
        class LocalClass {
            public void display() {
                System.out.println("这是局部内部类");
            }
        }

        LocalClass local = new LocalClass();
        local.display();
    }
}

(四)匿名内部类

public interface ClickListener {
    void onClick();
}

public class Button {
    private ClickListener listener;

    public void setOnClickListener(ClickListener listener) {
        this.listener = listener;
    }

    public void click() {
        if (listener != null) {
            listener.onClick();
        }
    }
}

public class AnonymousClassDemo {
    public static void main(String[] args) {
        Button button = new Button();

        // 使用匿名内部类
        button.setOnClickListener(new ClickListener() {
            @Override
            public void onClick() {
                System.out.println("按钮被点击了");
            }
        });

        button.click();  // 输出: 按钮被点击了
    }
}

七、异常处理

异常处理是 Java 中处理错误和异常情况的机制。

(一)异常的分类

  1. 受检异常(Checked Exception):编译时必须处理
  2. 运行时异常(Runtime Exception):编译时不强制处理
  3. 错误(Error):系统级别的错误,通常无法恢复

(二)try-catch-finally

public class ExceptionDemo {
    public static void main(String[] args) {
        try {
            // 可能抛出异常的代码
            int result = divide(10, 0);
            System.out.println("结果: " + result);
        } catch (ArithmeticException e) {
            // 捕获并处理异常
            System.out.println("除数不能为零: " + e.getMessage());
        } finally {
            // 无论是否发生异常都会执行
            System.out.println("finally 块总是执行");
        }
    }

    public static int divide(int a, int b) {
        return a / b;
    }
}

(三)throw 和 throws

public class ExceptionDemo2 {
    // 使用 throws 声明可能抛出的异常
    public static void checkAge(int age) throws IllegalArgumentException {
        if (age < 0) {
            // 使用 throw 抛出异常
            throw new IllegalArgumentException("年龄不能为负数");
        }
        if (age > 150) {
            throw new IllegalArgumentException("年龄不能超过150");
        }
        System.out.println("年龄有效: " + age);
    }

    public static void main(String[] args) {
        try {
            checkAge(25);
            checkAge(-5);
        } catch (IllegalArgumentException e) {
            System.out.println("错误: " + e.getMessage());
        }
    }
}

(四)自定义异常

// 自定义异常类
public class InsufficientBalanceException extends Exception {
    public InsufficientBalanceException(String message) {
        super(message);
    }
}

public class BankAccount {
    private double balance;

    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    public void withdraw(double amount) throws InsufficientBalanceException {
        if (amount > balance) {
            throw new InsufficientBalanceException("余额不足,当前余额: " + balance);
        }
        balance -= amount;
        System.out.println("取款成功,剩余余额: " + balance);
    }
}

八、包(Package)

包用于组织类,避免命名冲突,并提供访问控制。

(一)包的声明和使用

// 文件: com/example/utils/StringUtils.java
package com.example.utils;

public class StringUtils {
    public static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }

    public static String reverse(String str) {
        if (str == null) return null;
        return new StringBuilder(str).reverse().toString();
    }
}

// 文件: com/example/main/Main.java
package com.example.main;

import com.example.utils.StringUtils;

public class Main {
    public static void main(String[] args) {
        String str = "Hello, World!";
        System.out.println("反转: " + StringUtils.reverse(str));
    }
}

九、竞赛级编程技巧

(一)快速输入输出

import java.io.*;
import java.util.StringTokenizer;

public class FastIO {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));

    static String next() throws IOException {
        while (st == null || !st.hasMoreTokens())
            st = new StringTokenizer(br.readLine());
        return st.nextToken();
    }

    static int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    static long nextLong() throws IOException {
        return Long.parseLong(next());
    }

    static double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }

    public static void main(String[] args) throws IOException {
        int n = nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = nextInt();
        }
        // 处理数据...
        out.println("结果");
        out.flush();
    }
}

(二)常用工具类

import java.util.*;

public class Utility {
    // 最大公约数
    public static int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }

    // 最小公倍数
    public static int lcm(int a, int b) {
        return a / gcd(a, b) * b;
    }

    // 判断素数
    public static boolean isPrime(int n) {
        if (n < 2) return false;
        for (int i = 2; i * i <= n; i++) {
            if (n % i == 0) return false;
        }
        return true;
    }

    // 快速幂
    public static long pow(long base, long exp, long mod) {
        long result = 1;
        while (exp > 0) {
            if ((exp & 1) == 1) {
                result = (result * base) % mod;
            }
            base = (base * base) % mod;
            exp >>= 1;
        }
        return result;
    }
}

十、练习题目

基础练习

  1. 设计一个图书管理系统

要求: - 创建 Book 类,包含书名、作者、价格、ISBN等属性 - 创建 Library 类,管理图书的借阅和归还 - 实现添加图书、删除图书、查找图书等功能

  1. 设计一个形状计算器

要求: - 创建抽象类 Shape,包含计算面积和周长的抽象方法 - 创建 Circle、Rectangle、Triangle 等子类 - 实现多态,计算不同形状的面积和周长

  1. 实现一个简单的计算器

要求: - 使用接口定义不同的运算策略 - 实现加、减、乘、除等运算 - 支持链式调用

进阶练习

  1. 设计一个游戏角色系统

要求: - 创建角色基类,包含生命值、攻击力、防御力等属性 - 创建战士、法师、射手等职业子类 - 实现角色之间的战斗系统 - 使用多态实现不同的技能效果

  1. 实现一个简单的图形编辑器

要求: - 创建图形基类,包含绘制、移动、缩放等方法 - 创建直线、矩形、圆形等具体图形类 - 实现图形的选择和编辑功能

  1. 设计一个学生成绩管理系统

要求: - 创建 Student 类,包含基本信息和成绩 - 创建 Course 类,表示课程 - 实现成绩的录入、修改、查询 - 计算平均分、排名等统计功能


下一步建议: 学习 Java 的集合框架、多线程编程和 IO 流等高级特性,提升你的 Java 编程能力。