面向对象编程(Object-Oriented Programming,OOP)是Java的核心特性。本章将深入介绍类和对象、封装、继承、多态等面向对象的基本概念和实现方法。
4.1 类和对象
4.1.1 类的定义
/**
* 学生类 - 演示类的基本结构
*/
public class Student {
// 实例变量(属性/字段)
private String name; // 姓名
private int age; // 年龄
private String studentId; // 学号
private double gpa; // 平均绩点
// 类变量(静态变量)
private static int totalStudents = 0;
public static final String SCHOOL_NAME = "Java大学";
// 构造方法
public Student() {
this("未知", 0, "000000", 0.0);
}
public Student(String name, int age, String studentId) {
this(name, age, studentId, 0.0);
}
public Student(String name, int age, String studentId, double gpa) {
this.name = name;
this.age = age;
this.studentId = studentId;
this.gpa = gpa;
totalStudents++;
}
// 实例方法
public void study(String subject) {
System.out.println(name + "正在学习" + subject);
}
public void takeExam(String subject, double score) {
System.out.println(name + "参加了" + subject + "考试,得分:" + score);
updateGPA(score);
}
private void updateGPA(double score) {
// 简化的GPA计算
this.gpa = (this.gpa + score / 25.0) / 2.0;
}
// Getter和Setter方法
public String getName() {
return name;
}
public void setName(String name) {
if (name != null && !name.trim().isEmpty()) {
this.name = name;
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0 && age <= 150) {
this.age = age;
}
}
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
public double getGpa() {
return gpa;
}
// 静态方法
public static int getTotalStudents() {
return totalStudents;
}
public static void printSchoolInfo() {
System.out.println("学校:" + SCHOOL_NAME);
System.out.println("总学生数:" + totalStudents);
}
// toString方法
@Override
public String toString() {
return String.format("Student{name='%s', age=%d, studentId='%s', gpa=%.2f}",
name, age, studentId, gpa);
}
// equals方法
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Student student = (Student) obj;
return studentId.equals(student.studentId);
}
// hashCode方法
@Override
public int hashCode() {
return studentId.hashCode();
}
}
4.1.2 对象的创建和使用
public class StudentDemo {
public static void main(String[] args) {
System.out.println("=== 对象创建和使用 ===");
// 创建对象
Student student1 = new Student();
Student student2 = new Student("张三", 20, "2023001");
Student student3 = new Student("李四", 19, "2023002", 3.5);
// 使用对象
System.out.println("初始状态:");
System.out.println(student1);
System.out.println(student2);
System.out.println(student3);
// 调用方法
student2.study("Java编程");
student2.takeExam("Java编程", 95);
student3.study("数据结构");
student3.takeExam("数据结构", 88);
// 使用getter和setter
student1.setName("王五");
student1.setAge(21);
student1.setStudentId("2023003");
System.out.println("\n更新后状态:");
System.out.println(student1);
System.out.println(student2);
System.out.println(student3);
// 调用静态方法
Student.printSchoolInfo();
// 对象比较
Student student4 = new Student("赵六", 20, "2023002", 3.2);
System.out.println("\n对象比较:");
System.out.println("student3.equals(student4): " + student3.equals(student4)); // true,学号相同
System.out.println("student2.equals(student3): " + student2.equals(student3)); // false,学号不同
// 对象引用
Student student5 = student2; // 引用赋值
System.out.println("\n引用赋值:");
System.out.println("student2 == student5: " + (student2 == student5)); // true,同一对象
System.out.println("student2.equals(student5): " + student2.equals(student5)); // true
student5.setName("张三(修改)");
System.out.println("修改student5后,student2的名字: " + student2.getName()); // 也被修改
}
}
4.2 封装
4.2.1 访问修饰符
/**
* 银行账户类 - 演示封装和访问修饰符
*/
public class BankAccount {
// private:只能在本类内部访问
private String accountNumber;
private double balance;
private String password;
// protected:可以在本类、子类和同包类中访问
protected String accountType;
// 默认(包私有):可以在同包类中访问
String bankName;
// public:可以在任何地方访问
public String ownerName;
// 构造方法
public BankAccount(String accountNumber, String ownerName, String password) {
this.accountNumber = accountNumber;
this.ownerName = ownerName;
this.password = password;
this.balance = 0.0;
this.accountType = "储蓄账户";
this.bankName = "Java银行";
}
// 公共方法提供对私有数据的访问
public double getBalance() {
return balance;
}
public String getAccountNumber() {
return accountNumber;
}
// 存款方法
public boolean deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("存款成功,金额:" + amount + ",余额:" + balance);
return true;
} else {
System.out.println("存款金额必须大于0");
return false;
}
}
// 取款方法
public boolean withdraw(double amount, String inputPassword) {
if (!verifyPassword(inputPassword)) {
System.out.println("密码错误");
return false;
}
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("取款成功,金额:" + amount + ",余额:" + balance);
return true;
} else if (amount > balance) {
System.out.println("余额不足");
return false;
} else {
System.out.println("取款金额必须大于0");
return false;
}
}
// 转账方法
public boolean transfer(BankAccount targetAccount, double amount, String inputPassword) {
if (!verifyPassword(inputPassword)) {
System.out.println("密码错误");
return false;
}
if (this.withdraw(amount, inputPassword)) {
targetAccount.deposit(amount);
System.out.println("转账成功,从" + this.ownerName + "转给" + targetAccount.ownerName);
return true;
}
return false;
}
// 私有方法:验证密码
private boolean verifyPassword(String inputPassword) {
return this.password.equals(inputPassword);
}
// 修改密码
public boolean changePassword(String oldPassword, String newPassword) {
if (verifyPassword(oldPassword)) {
if (newPassword != null && newPassword.length() >= 6) {
this.password = newPassword;
System.out.println("密码修改成功");
return true;
} else {
System.out.println("新密码长度至少6位");
return false;
}
} else {
System.out.println("原密码错误");
return false;
}
}
// 账户信息(隐藏敏感信息)
public void printAccountInfo() {
System.out.println("账户信息:");
System.out.println("账号:" + accountNumber);
System.out.println("户主:" + ownerName);
System.out.println("账户类型:" + accountType);
System.out.println("银行:" + bankName);
System.out.println("余额:" + balance);
// 注意:不显示密码
}
}
4.2.2 封装的实际应用
public class EncapsulationDemo {
public static void main(String[] args) {
System.out.println("=== 封装演示 ===");
// 创建银行账户
BankAccount account1 = new BankAccount("123456789", "张三", "password123");
BankAccount account2 = new BankAccount("987654321", "李四", "mypassword");
// 正常操作
account1.deposit(1000);
account1.withdraw(200, "password123");
// 错误操作演示
account1.withdraw(100, "wrongpassword"); // 密码错误
account1.withdraw(2000, "password123"); // 余额不足
// 转账操作
account2.deposit(500);
account1.transfer(account2, 300, "password123");
// 显示账户信息
System.out.println("\n账户信息:");
account1.printAccountInfo();
account2.printAccountInfo();
// 修改密码
account1.changePassword("password123", "newpass123");
// 尝试直接访问私有变量(编译错误)
// System.out.println(account1.password); // 编译错误
// account1.balance = 10000; // 编译错误
// 通过公共方法访问
System.out.println("\n通过公共方法访问:");
System.out.println("账号:" + account1.getAccountNumber());
System.out.println("余额:" + account1.getBalance());
// 可以直接访问public字段(不推荐)
System.out.println("户主:" + account1.ownerName);
account1.ownerName = "张三(已修改)";
System.out.println("修改后户主:" + account1.ownerName);
}
}
4.3 继承
4.3.1 基本继承
/**
* 动物基类
*/
public class Animal {
protected String name;
protected int age;
protected String species;
// 构造方法
public Animal() {
this("未知动物", 0, "未知物种");
}
public Animal(String name, int age, String species) {
this.name = name;
this.age = age;
this.species = species;
}
// 基本行为方法
public void eat() {
System.out.println(name + "正在吃东西");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
public void makeSound() {
System.out.println(name + "发出了声音");
}
// 移动方法(将被子类重写)
public void move() {
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) {
if (age >= 0) {
this.age = age;
}
}
public String getSpecies() {
return species;
}
// 获取动物信息
public String getInfo() {
return String.format("%s,年龄:%d岁,物种:%s", name, age, species);
}
@Override
public String toString() {
return getInfo();
}
}
4.3.2 子类实现
/**
* 狗类 - 继承自Animal
*/
public class Dog extends Animal {
private String breed; // 品种
private boolean isTrained; // 是否训练过
// 构造方法
public Dog() {
super(); // 调用父类构造方法
this.breed = "混种";
this.isTrained = false;
}
public Dog(String name, int age, String breed) {
super(name, age, "犬科"); // 调用父类构造方法
this.breed = breed;
this.isTrained = false;
}
public Dog(String name, int age, String breed, boolean isTrained) {
super(name, age, "犬科");
this.breed = breed;
this.isTrained = isTrained;
}
// 重写父类方法
@Override
public void makeSound() {
System.out.println(name + "汪汪叫");
}
@Override
public void move() {
System.out.println(name + "正在奔跑");
}
// 子类特有方法
public void wagTail() {
System.out.println(name + "摇尾巴表示友好");
}
public void fetch(String item) {
if (isTrained) {
System.out.println(name + "去捡" + item);
} else {
System.out.println(name + "还没学会捡东西");
}
}
public void train() {
if (!isTrained) {
isTrained = true;
System.out.println(name + "完成了训练");
} else {
System.out.println(name + "已经训练过了");
}
}
// Getter和Setter
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
public boolean isTrained() {
return isTrained;
}
// 重写getInfo方法
@Override
public String getInfo() {
return super.getInfo() + ",品种:" + breed + ",训练状态:" + (isTrained ? "已训练" : "未训练");
}
}
/**
* 鸟类 - 继承自Animal
*/
public class Bird extends Animal {
private boolean canFly; // 是否会飞
private double wingspan; // 翼展
public Bird() {
super();
this.canFly = true;
this.wingspan = 0.0;
}
public Bird(String name, int age, String species, boolean canFly, double wingspan) {
super(name, age, species);
this.canFly = canFly;
this.wingspan = wingspan;
}
// 重写父类方法
@Override
public void makeSound() {
System.out.println(name + "啁啾鸣叫");
}
@Override
public void move() {
if (canFly) {
System.out.println(name + "正在飞翔");
} else {
System.out.println(name + "正在地面行走");
}
}
// 子类特有方法
public void fly() {
if (canFly) {
System.out.println(name + "展开" + wingspan + "米的翅膀飞翔");
} else {
System.out.println(name + "不会飞");
}
}
public void buildNest() {
System.out.println(name + "正在筑巢");
}
// Getter和Setter
public boolean isCanFly() {
return canFly;
}
public void setCanFly(boolean canFly) {
this.canFly = canFly;
}
public double getWingspan() {
return wingspan;
}
public void setWingspan(double wingspan) {
if (wingspan >= 0) {
this.wingspan = wingspan;
}
}
@Override
public String getInfo() {
return super.getInfo() + ",飞行能力:" + (canFly ? "会飞" : "不会飞") + ",翼展:" + wingspan + "米";
}
}
4.3.3 继承演示
public class InheritanceDemo {
public static void main(String[] args) {
System.out.println("=== 继承演示 ===");
// 创建不同类型的动物
Animal animal = new Animal("通用动物", 5, "未知");
Dog dog = new Dog("旺财", 3, "金毛");
Bird bird = new Bird("小黄", 2, "金丝雀", true, 0.15);
// 基本信息
System.out.println("动物信息:");
System.out.println(animal.getInfo());
System.out.println(dog.getInfo());
System.out.println(bird.getInfo());
System.out.println("\n=== 共同行为 ===");
// 所有动物都有的行为
animal.eat();
dog.eat();
bird.eat();
System.out.println();
animal.sleep();
dog.sleep();
bird.sleep();
System.out.println("\n=== 重写的方法 ===");
// 重写的方法表现不同
animal.makeSound();
dog.makeSound();
bird.makeSound();
System.out.println();
animal.move();
dog.move();
bird.move();
System.out.println("\n=== 子类特有方法 ===");
// 狗的特有行为
dog.wagTail();
dog.fetch("球");
dog.train();
dog.fetch("飞盘");
System.out.println();
// 鸟的特有行为
bird.fly();
bird.buildNest();
System.out.println("\n=== 多态演示 ===");
// 多态:父类引用指向子类对象
Animal[] animals = {
new Animal("普通动物", 1, "未知"),
new Dog("小黑", 2, "拉布拉多"),
new Bird("小白", 1, "鸽子", true, 0.3)
};
for (Animal a : animals) {
System.out.println(a.getInfo());
a.makeSound(); // 调用各自重写的方法
a.move();
System.out.println();
}
System.out.println("=== instanceof检查 ===");
for (Animal a : animals) {
System.out.println(a.getName() + ":");
System.out.println(" 是Animal: " + (a instanceof Animal));
System.out.println(" 是Dog: " + (a instanceof Dog));
System.out.println(" 是Bird: " + (a instanceof Bird));
// 类型转换
if (a instanceof Dog) {
Dog d = (Dog) a;
d.wagTail();
} else if (a instanceof Bird) {
Bird b = (Bird) a;
b.fly();
}
System.out.println();
}
}
}
4.4 多态
4.4.1 方法重写和动态绑定
/**
* 形状基类 - 演示多态
*/
public abstract class Shape {
protected String color;
protected double x, y; // 位置坐标
public Shape(String color, double x, double y) {
this.color = color;
this.x = x;
this.y = y;
}
// 抽象方法 - 子类必须实现
public abstract double calculateArea();
public abstract double calculatePerimeter();
public abstract void draw();
// 具体方法
public void move(double deltaX, double deltaY) {
this.x += deltaX;
this.y += deltaY;
System.out.println("形状移动到位置: (" + x + ", " + y + ")");
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
// 模板方法模式
public void displayInfo() {
System.out.println("=== 形状信息 ===");
System.out.println("类型: " + this.getClass().getSimpleName());
System.out.println("颜色: " + color);
System.out.println("位置: (" + x + ", " + y + ")");
System.out.println("面积: " + calculateArea());
System.out.println("周长: " + calculatePerimeter());
draw();
System.out.println();
}
}
4.4.2 具体子类实现
/**
* 圆形类
*/
public class Circle extends Shape {
private double radius;
public Circle(String color, double x, double y, double radius) {
super(color, x, y);
this.radius = radius;
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
@Override
public double calculatePerimeter() {
return 2 * Math.PI * radius;
}
@Override
public void draw() {
System.out.println("绘制一个半径为" + radius + "的" + color + "圆形");
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
if (radius > 0) {
this.radius = radius;
}
}
}
/**
* 矩形类
*/
public class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(String color, double x, double y, double width, double height) {
super(color, x, y);
this.width = width;
this.height = height;
}
@Override
public double calculateArea() {
return width * height;
}
@Override
public double calculatePerimeter() {
return 2 * (width + height);
}
@Override
public void draw() {
System.out.println("绘制一个" + width + "x" + height + "的" + color + "矩形");
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
if (width > 0) {
this.width = width;
}
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
if (height > 0) {
this.height = height;
}
}
}
/**
* 三角形类
*/
public class Triangle extends Shape {
private double side1, side2, side3;
public Triangle(String color, double x, double y, double side1, double side2, double side3) {
super(color, x, y);
if (isValidTriangle(side1, side2, side3)) {
this.side1 = side1;
this.side2 = side2;
this.side3 = side3;
} else {
throw new IllegalArgumentException("无效的三角形边长");
}
}
private boolean isValidTriangle(double a, double b, double c) {
return a + b > c && a + c > b && b + c > a;
}
@Override
public double calculateArea() {
// 使用海伦公式
double s = calculatePerimeter() / 2;
return Math.sqrt(s * (s - side1) * (s - side2) * (s - side3));
}
@Override
public double calculatePerimeter() {
return side1 + side2 + side3;
}
@Override
public void draw() {
System.out.println("绘制一个边长为" + side1 + ", " + side2 + ", " + side3 + "的" + color + "三角形");
}
public double getSide1() {
return side1;
}
public double getSide2() {
return side2;
}
public double getSide3() {
return side3;
}
}
4.4.3 多态演示
import java.util.ArrayList;
import java.util.List;
public class PolymorphismDemo {
public static void main(String[] args) {
System.out.println("=== 多态演示 ===");
// 创建不同形状的对象
Shape[] shapes = {
new Circle("红色", 0, 0, 5),
new Rectangle("蓝色", 10, 10, 4, 6),
new Triangle("绿色", 20, 20, 3, 4, 5)
};
// 多态:同一接口,不同实现
System.out.println("=== 形状信息展示 ===");
for (Shape shape : shapes) {
shape.displayInfo(); // 调用各自的实现
}
// 计算总面积
double totalArea = calculateTotalArea(shapes);
System.out.println("所有形状的总面积: " + String.format("%.2f", totalArea));
// 动态类型检查和转换
System.out.println("=== 动态类型检查 ===");
for (Shape shape : shapes) {
System.out.println("处理" + shape.getClass().getSimpleName() + ":");
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
System.out.println(" 圆的半径: " + circle.getRadius());
System.out.println(" 圆的直径: " + (circle.getRadius() * 2));
} else if (shape instanceof Rectangle) {
Rectangle rectangle = (Rectangle) shape;
System.out.println(" 矩形宽度: " + rectangle.getWidth());
System.out.println(" 矩形高度: " + rectangle.getHeight());
System.out.println(" 是否为正方形: " + (rectangle.getWidth() == rectangle.getHeight()));
} else if (shape instanceof Triangle) {
Triangle triangle = (Triangle) shape;
System.out.println(" 三角形三边: " + triangle.getSide1() + ", " +
triangle.getSide2() + ", " + triangle.getSide3());
}
System.out.println();
}
// 使用List集合演示多态
System.out.println("=== 使用List集合 ===");
List<Shape> shapeList = new ArrayList<>();
shapeList.add(new Circle("黄色", 0, 0, 3));
shapeList.add(new Rectangle("紫色", 5, 5, 2, 8));
shapeList.add(new Triangle("橙色", 15, 15, 6, 8, 10));
// 对所有形状进行操作
moveAllShapes(shapeList, 10, 10);
// 找出面积最大的形状
Shape largestShape = findLargestShape(shapeList);
System.out.println("面积最大的形状:");
largestShape.displayInfo();
// 按类型分组统计
countShapesByType(shapeList);
}
// 计算总面积的方法
public static double calculateTotalArea(Shape[] shapes) {
double total = 0;
for (Shape shape : shapes) {
total += shape.calculateArea();
}
return total;
}
// 移动所有形状
public static void moveAllShapes(List<Shape> shapes, double deltaX, double deltaY) {
System.out.println("移动所有形状:");
for (Shape shape : shapes) {
shape.move(deltaX, deltaY);
}
System.out.println();
}
// 找出面积最大的形状
public static Shape findLargestShape(List<Shape> shapes) {
if (shapes.isEmpty()) {
return null;
}
Shape largest = shapes.get(0);
for (Shape shape : shapes) {
if (shape.calculateArea() > largest.calculateArea()) {
largest = shape;
}
}
return largest;
}
// 按类型统计形状数量
public static void countShapesByType(List<Shape> shapes) {
System.out.println("=== 形状类型统计 ===");
int circleCount = 0, rectangleCount = 0, triangleCount = 0;
for (Shape shape : shapes) {
if (shape instanceof Circle) {
circleCount++;
} else if (shape instanceof Rectangle) {
rectangleCount++;
} else if (shape instanceof Triangle) {
triangleCount++;
}
}
System.out.println("圆形数量: " + circleCount);
System.out.println("矩形数量: " + rectangleCount);
System.out.println("三角形数量: " + triangleCount);
System.out.println("总数量: " + shapes.size());
}
}