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 中处理错误和异常情况的机制。
(一)异常的分类¶
- 受检异常(Checked Exception):编译时必须处理
- 运行时异常(Runtime Exception):编译时不强制处理
- 错误(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;
}
}
十、练习题目¶
基础练习¶
- 设计一个图书管理系统
要求: - 创建 Book 类,包含书名、作者、价格、ISBN等属性 - 创建 Library 类,管理图书的借阅和归还 - 实现添加图书、删除图书、查找图书等功能
- 设计一个形状计算器
要求: - 创建抽象类 Shape,包含计算面积和周长的抽象方法 - 创建 Circle、Rectangle、Triangle 等子类 - 实现多态,计算不同形状的面积和周长
- 实现一个简单的计算器
要求: - 使用接口定义不同的运算策略 - 实现加、减、乘、除等运算 - 支持链式调用
进阶练习¶
- 设计一个游戏角色系统
要求: - 创建角色基类,包含生命值、攻击力、防御力等属性 - 创建战士、法师、射手等职业子类 - 实现角色之间的战斗系统 - 使用多态实现不同的技能效果
- 实现一个简单的图形编辑器
要求: - 创建图形基类,包含绘制、移动、缩放等方法 - 创建直线、矩形、圆形等具体图形类 - 实现图形的选择和编辑功能
- 设计一个学生成绩管理系统
要求: - 创建 Student 类,包含基本信息和成绩 - 创建 Course 类,表示课程 - 实现成绩的录入、修改、查询 - 计算平均分、排名等统计功能
下一步建议: 学习 Java 的集合框架、多线程编程和 IO 流等高级特性,提升你的 Java 编程能力。