第6章:面向对象编程
作为 Java 开发者,你已经熟悉了面向对象编程的概念。Python 也支持面向对象编程,并且语法更加简洁。本章将详细对比两种语言的面向对象编程特性。
6.1 类的定义
Java 类定义
public class Person {
// 成员变量
private String name;
private int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 成员方法
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 void introduce() {
System.out.println("My name is " + name + " and I am " + age + " years old.");
}
}
Python 类定义
class Person:
"""人员类"""
# 构造方法
def __init__(self, name, age):
self.name = name
self.age = age
# 成员方法
def introduce(self):
"""自我介绍"""
print(f"My name is {self.name} and I am {self.age} years old.")
对比:
| 特性 | Java | Python |
|---|---|---|
| 类定义 | public class ClassName | class ClassName: |
| 构造方法 | 与类名相同的方法 | __init__ 方法 |
| 成员变量 | 必须声明类型 | 动态添加,无需声明 |
| 访问修饰符 | public, private, protected | 无(通过命名约定) |
| this 关键字 | this | self |
| 方法定义 | 必须声明返回类型 | 无需声明返回类型 |
| 代码块 | 大括号包围 | 缩进 |
Python 类示例:
# 基本类定义
class Person:
"""人员类"""
# 类变量
species = "Homo sapiens"
# 构造方法
def __init__(self, name, age):
# 实例变量
self.name = name
self.age = age
# 实例方法
def introduce(self):
"""自我介绍"""
print(f"My name is {self.name} and I am {self.age} years old.")
# 类方法
@classmethod
def get_species(cls):
"""获取物种"""
return cls.species
# 静态方法
@staticmethod
def is_adult(age):
"""判断是否成年"""
return age >= 18
# 创建对象
person = Person("Alice", 25)
# 调用实例方法
person.introduce() # My name is Alice and I am 25 years old.
# 访问实例变量
print(person.name) # Alice
print(person.age) # 25
# 访问类变量
print(Person.species) # Homo sapiens
print(person.species) # Homo sapiens
# 调用类方法
print(Person.get_species()) # Homo sapiens
# 调用静态方法
print(Person.is_adult(18)) # True
print(Person.is_adult(17)) # False
6.2 继承
Java 继承
public class Student extends Person {
private String major;
public Student(String name, int age, String major) {
super(name, age);
this.major = major;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
@Override
public void introduce() {
super.introduce();
System.out.println("I am majoring in " + major + ".");
}
}
Python 继承
class Student(Person):
"""学生类"""
def __init__(self, name, age, major):
super().__init__(name, age)
self.major = major
def introduce(self):
"""自我介绍"""
super().introduce()
print(f"I am majoring in {self.major}.")
对比:
| 特性 | Java | Python |
|---|---|---|
| 继承语法 | extends 关键字 | 括号中指定父类 |
| 调用父类构造方法 | super() | super().__init__() |
| 方法重写 | @Override 注解 | 直接重写方法 |
| 多继承 | 不支持(接口除外) | 支持 |
| 访问父类方法 | super().method() | super().method() |
Python 继承示例:
# 父类
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"My name is {self.name} and I am {self.age} years old.")
# 子类
class Student(Person):
def __init__(self, name, age, major):
super().__init__(name, age)
self.major = major
def introduce(self):
super().introduce()
print(f"I am majoring in {self.major}.")
# 另一个子类
class Employee(Person):
def __init__(self, name, age, company):
super().__init__(name, age)
self.company = company
def introduce(self):
super().introduce()
print(f"I work at {self.company}.")
# 创建对象
student = Student("Alice", 20, "Computer Science")
employee = Employee("Bob", 30, "Google")
# 调用方法
student.introduce()
# My name is Alice and I am 20 years old.
# I am majoring in Computer Science.
employee.introduce()
# My name is Bob and I am 30 years old.
# I work at Google.
# 检查类型
print(isinstance(student, Student)) # True
print(isinstance(student, Person)) # True
print(isinstance(employee, Person)) # True
print(isinstance(student, Employee)) # False
6.3 多继承
Java 多继承
- Java 不支持类的多继承
- 只能通过接口实现多继承
Python 多继承
- Python 支持类的多继承
- 使用 C3 线性化算法解决菱形继承问题
Python 多继承示例:
# 基类 1
class Animal:
def speak(self):
print("Animal speaks")
# 基类 2
class Pet:
def be_friendly(self):
print("Pet is friendly")
# 多继承子类
class Dog(Animal, Pet):
def bark(self):
print("Dog barks")
# 创建对象
dog = Dog()
# 调用父类方法
dog.speak() # Animal speaks
dog.be_friendly() # Pet is friendly
# 调用子类方法
dog.bark() # Dog barks
# 方法解析顺序
print(Dog.__mro__) # 显示方法解析顺序
6.4 封装
Java 封装
- 使用访问修饰符(public, private, protected)
- 提供 getter 和 setter 方法
- 封装成员变量
Python 封装
- 没有访问修饰符
- 使用命名约定:
_variable:单下划线,表示保护成员__variable:双下划线,表示私有成员(会被名称修饰)
- 可以使用 property 装饰器创建属性
对比示例:
| 特性 | Java | Python |
|---|---|---|
| 私有成员 | private 关键字 | __variable(名称修饰) |
| 保护成员 | protected 关键字 | _variable(命名约定) |
| 公共成员 | public 关键字 | 无下划线 |
| Getter/Setter | 显式方法 | @property 装饰器 |
Python 封装示例:
class Person:
def __init__(self, name, age):
self.name = name # 公共属性
self._age = age # 保护属性
self.__salary = 50000 # 私有属性
# Getter 方法
@property
def age(self):
return self._age
# Setter 方法
@age.setter
def age(self, value):
if value >= 0:
self._age = value
else:
raise ValueError("Age cannot be negative")
# 访问私有属性的方法
def get_salary(self):
return self.__salary
def set_salary(self, value):
if value >= 0:
self.__salary = value
else:
raise ValueError("Salary cannot be negative")
# 创建对象
person = Person("Alice", 25)
# 访问公共属性
print(person.name) # Alice
# 访问保护属性(不推荐)
print(person._age) # 25
# 访问私有属性(会报错)
# print(person.__salary) # AttributeError
# 通过方法访问私有属性
print(person.get_salary()) # 50000
# 使用 property
person.age = 30
print(person.age) # 30
# 尝试设置负值(会报错)
# person.age = -5 # ValueError
6.5 多态
Java 多态
- 编译时多态:方法重载
- 运行时多态:方法重写
- 基于继承和接口
Python 多态
- 动态类型,天然支持多态
- 鸭子类型:"如果它走路像鸭子,叫起来像鸭子,那么它就是鸭子"
- 方法重写
- 不需要显式的接口定义
对比示例:
| 特性 | Java | Python |
|---|---|---|
| 方法重载 | 支持(相同方法名,不同参数) | 不支持(后定义的方法会覆盖前一个) |
| 方法重写 | 支持 | 支持 |
| 接口 | 显式定义 | 隐式(鸭子类型) |
| 多态实现 | 基于类型 | 基于行为 |
Python 多态示例:
# 多态示例
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
class Duck(Animal):
def speak(self):
return "Quack!"
# 多态函数
def make_animal_speak(animal):
print(animal.speak())
# 创建对象
dog = Dog()
cat = Cat()
duck = Duck()
# 调用函数(多态)
make_animal_speak(dog) # Woof!
make_animal_speak(cat) # Meow!
make_animal_speak(duck) # Quack!
# 鸭子类型示例
class Car:
def speak(self):
return "Vroom!"
# 即使不是 Animal 的子类,只要有 speak 方法就可以使用
car = Car()
make_animal_speak(car) # Vroom!
6.6 抽象类和接口
Java 抽象类和接口
- 抽象类:使用
abstract关键字,不能实例化,可以有抽象方法和具体方法 - 接口:使用
interface关键字,只能有抽象方法(Java 8+ 可以有默认方法)
Python 抽象类和接口
- 抽象类:使用
abc模块,不能实例化,可以有抽象方法和具体方法 - 接口:没有专门的接口关键字,使用抽象类或鸭子类型
Python 抽象类示例:
from abc import ABC, abstractmethod
class Shape(ABC):
"""形状抽象类"""
@abstractmethod
def area(self):
"""计算面积"""
pass
@abstractmethod
def perimeter(self):
"""计算周长"""
pass
def description(self):
"""描述方法"""
return f"This is a {self.__class__.__name__}"
class Circle(Shape):
"""圆形类"""
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def perimeter(self):
return 2 * 3.14159 * self.radius
class Rectangle(Shape):
"""矩形类"""
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
# 创建对象
circle = Circle(5)
rectangle = Rectangle(4, 6)
# 调用方法
print(circle.area()) # 78.53975
print(circle.perimeter()) # 31.4159
print(circle.description()) # This is a Circle
print(rectangle.area()) # 24
print(rectangle.perimeter()) # 20
print(rectangle.description()) # This is a Rectangle
# 尝试实例化抽象类(会报错)
# shape = Shape() # TypeError
6.7 特殊方法
Python 有许多特殊方法(魔术方法),用于自定义类的行为。
常用特殊方法:
| 方法 | 描述 | 示例 |
|---|---|---|
__init__ | 构造方法 | def __init__(self, name): |
__str__ | 字符串表示 | def __str__(self): |
__repr__ | 正式字符串表示 | def __repr__(self): |
__eq__ | 等于比较 | def __eq__(self, other): |
__lt__ | 小于比较 | def __lt__(self, other): |
__add__ | 加法运算 | def __add__(self, other): |
__len__ | 长度 | def __len__(self): |
__getitem__ | 索引访问 | def __getitem__(self, index): |
__setitem__ | 索引赋值 | def __setitem__(self, index, value): |
__call__ | 使对象可调用 | def __call__(self, *args, **kwargs): |
特殊方法示例:
class Vector:
"""向量类"""
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
"""字符串表示"""
return f"Vector({self.x}, {self.y})"
def __repr__(self):
"""正式字符串表示"""
return f"Vector({self.x}, {self.y})"
def __add__(self, other):
"""向量加法"""
return Vector(self.x + other.x, self.y + other.y)
def __sub__(self, other):
"""向量减法"""
return Vector(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
"""向量乘法"""
return Vector(self.x * scalar, self.y * scalar)
def __eq__(self, other):
"""相等比较"""
return self.x == other.x and self.y == other.y
def __len__(self):
"""向量长度"""
return int((self.x ** 2 + self.y ** 2) ** 0.5)
# 创建对象
v1 = Vector(3, 4)
v2 = Vector(1, 2)
# 调用特殊方法
print(v1) # Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(v1 - v2) # Vector(2, 2)
print(v1 * 2) # Vector(6, 8)
print(v1 == v2) # False
print(len(v1)) # 5
6.8 类的属性和方法
Java 类成员
- 静态变量(类变量)
- 实例变量
- 静态方法
- 实例方法
- 构造方法
- 抽象方法
- 最终方法(final)
Python 类成员
- 类变量
- 实例变量
- 类方法(@classmethod)
- 静态方法(@staticmethod)
- 实例方法
- 特殊方法
- 属性(@property)
对比:
| 成员类型 | Java | Python |
|---|---|---|
| 类变量 | static 关键字 | 类内部定义的变量 |
| 静态方法 | static 关键字 | @staticmethod 装饰器 |
| 类方法 | 无直接对应 | @classmethod 装饰器 |
| 实例方法 | 普通方法 | 普通方法 |
| 属性 | 显式 getter/setter | @property 装饰器 |
6.9 练习
- 类定义练习:定义一个
Car类,包含品牌、型号、年份等属性,以及启动、停止等方法 - 继承练习:定义一个
ElectricCar类,继承自Car类,添加电池容量等属性 - 多态练习:定义一个
Shape抽象类,派生出Circle、Rectangle、Triangle子类,实现面积计算 - 封装练习:定义一个
BankAccount类,使用@property装饰器保护余额属性 - 特殊方法练习:定义一个
Point类,实现__add__、__sub__、__eq__等特殊方法 - 多继承练习:定义一个
Teacher类,继承自Person和Employee类
6.10 小结
- Python 的类定义比 Java 更简洁,不需要访问修饰符
- Python 使用
self而不是this关键字 - Python 支持多继承,而 Java 不支持
- Python 使用命名约定和
@property装饰器实现封装 - Python 基于鸭子类型实现多态,更加灵活
- Python 有丰富的特殊方法,可以自定义类的行为
- Python 的抽象类使用
abc模块实现 - Python 的静态方法和类方法使用装饰器标记
通过本章的学习,你已经了解了 Java 和 Python 在面向对象编程上的主要区别。接下来,我们将学习 Python 的异常处理。