简介:Java中的面向对象编程是其核心概念,强调代码的可读性、可维护性及重用性。本次实验通过创建 Student
和 Graduate
类,让学生深入理解和掌握面向对象的特性,包括封装、继承和多态。学生将通过实验操作这些特性,理解类的设计、属性与方法的定义,以及如何通过继承扩展现有类,并实现对象的封装和多态调用。实验旨在通过实践加深对Java面向对象编程的理解,提升编程技能。
1. Java面向对象编程基础
1.1 面向对象编程的核心思想
面向对象编程(OOP)是一种编程范式,它使用“对象”来设计软件。对象可以包含数据(通常称为属性或字段)和代码(通常称为方法)。面向对象编程的概念包括封装、继承和多态性,这些概念共同为软件开发提供了模块化和可重用性的基础。
1.2 Java中对象的创建和使用
在Java中,创建对象的第一步是定义一个类。类是创建对象的蓝图,它定义了对象所持有的属性和行为。例如, Student
类可能包含 name
和 age
属性,以及 study()
和 attendClass()
方法。创建对象的过程涉及使用 new
关键字实例化类:
Student student = new Student("John", 20);
接下来,可以通过点操作符访问对象的方法和属性:
student.study();
System.out.println(student.name);
在Java中,对象是存储在堆内存中的,而类的定义则位于方法区。创建对象的过程涉及内存分配和初始化,而使用对象则涉及到方法调用和属性访问。理解这些基础概念对于掌握面向对象编程至关重要。
2. 类设计与对象蓝图
2.1 类的基本概念
2.1.1 类的定义和对象的创建
在Java中,类是对象的蓝图或模板,它定义了一组属性(也称为成员变量或字段)和方法(也称为函数或行为)。对象是根据这些蓝图创建的实体,每个对象都有自己的状态和行为。
要定义一个类,你需要使用 class
关键字。以下是一个简单的 Student
类的定义示例:
public class Student {
// 类的属性
private String name;
private int age;
// 类的构造方法
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// 类的方法
public void study() {
System.out.println(name + " is studying.");
}
// Getter and Setter methods
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;
}
}
在上面的代码中, Student
类有三个属性: name
、 age
和一个方法 study()
。我们还包含了用于初始化对象状态的构造方法和访问器(getter)以及修改器(setter)方法。
创建类的实例(对象)时,可以使用 new
关键字调用构造函数:
Student student1 = new Student("Alice", 20);
student1.study();
在上面的示例中,我们创建了一个名为 Alice
的 Student
对象,年龄为20岁,并调用了 study()
方法。
2.1.2 类的属性和方法
类的属性(也称为成员变量或字段)是对象的特征,它可以是基本类型(如 int
, char
, double
等)或者引用类型(如 String
, arrays
, other classes
等)。
方法是类内定义的行为,它决定了对象能执行的操作。Java中定义方法的语法如下:
访问修饰符 返回类型 方法名(参数列表) {
// 方法体
}
例如,在 Student
类中, study()
是一个简单的方法,没有参数并返回 void
。
public void study() {
System.out.println(name + " is studying.");
}
在Java中,属性和方法可以有不同的访问修饰符。 public
表示任何人都可以访问, private
表示只能在类内部访问。 protected
和默认(无修饰符)的访问级别提供了不同程度的包内访问。
2.1.3 类的属性和方法的封装
封装是面向对象编程的四个基本原则之一,它要求将对象的状态(属性)隐藏起来,并提供公共的方法来访问和修改这个状态。
封装确保了对象的属性不能被外部直接访问,这有助于防止非法的数据访问和维护数据的完整性。为了实现封装,我们可以将属性声明为 private
,然后通过 public
的getter和setter方法提供对外的访问和修改途径。
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
2.2 对象的生命周期
对象在内存中的生命周期从创建开始,经历使用过程,最后被垃圾收集器回收。对象的生命周期由三个主要阶段组成:对象的初始化、对象的使用和对象的销毁。
2.2.1 对象的初始化
对象的初始化发生在使用 new
关键字创建对象的那一刻。当执行 new
操作时,JVM会执行以下操作:
- 在堆上为对象分配内存。
- 初始化对象的实例变量。
- 调用构造函数来设置对象的状态。
初始化过程是通过构造函数完成的。如果没有显式定义构造函数,Java编译器会提供一个默认的无参构造函数。一旦对象被初始化,它的状态就被设置好了,可以开始使用。
2.2.2 对象的使用
对象的使用涉及调用其方法和访问其属性。对象的状态可以通过方法来修改,从而影响对象的行为。在 Student
类中,我们可以调用 study()
方法来模拟学生学习的行为:
student1.study();
2.2.3 对象的销毁
在Java中,对象的销毁是自动的,由垃圾收集器(GC)负责。垃圾收集器会自动识别不再使用的对象并回收其占用的内存资源。对象被认为不再使用当:
- 没有引用指向它。
- 引用变为不可达(例如,局部变量超出了作用域)。
对象销毁过程可能涉及一些清理操作,比如关闭文件或释放其他资源。这可以通过覆盖 finalize()
方法实现,但通常推荐使用 try-with-resources
语句或其他资源管理技术,因为它们更加可靠。
protected void finalize() throws Throwable {
// 清理资源
super.finalize();
}
尽管 finalize()
方法被设计用来执行清理工作,但不建议依赖它,因为Java的垃圾收集器并不保证何时会调用 finalize()
。正确的方法是使用 try-finally
块或者Java 7引入的try-with-resources语句。
通过本章节的介绍,我们理解了类的基本概念、对象的生命周期以及如何在Java中定义和操作类和对象。下一章节将深入探讨对象的生命周期,包括对象的初始化、使用和销毁过程,并介绍Java中的垃圾收集机制。
3. 封装与访问控制
在面向对象编程的世界里,封装是一种允许我们隐藏对象内部状态和行为细节的机制,而仅将接口暴露给外部世界的技术。封装不仅有助于提高代码的安全性和健壮性,还能使得代码易于理解和维护。访问控制,则是封装中的一项重要组成部分,它决定了类、方法和属性的访问权限。
3.1 封装的意义与实现
3.1.1 封装的基本原理
封装的核心思想是将数据(属性)和操作数据的方法绑定起来,形成一个独立的单元,也就是对象。这样,数据就不会被随意访问和修改,对象的状态只能通过方法来改变,从而保证了数据的安全性。封装的另一个好处是隐藏了实现细节,使得类的使用者无需了解对象内部的实现就能使用对象提供的功能。
3.1.2 封装的语法实现
在Java中,我们通常通过使用访问修饰符来实现封装。常见的访问修饰符有 private
、 protected
、 public
,以及默认访问级别(没有访问修饰符时的访问级别)。通过这些修饰符,我们可以控制类的成员(包括属性和方法)的可访问性:
-
private
:在类的内部可见,外部不可见。 -
default
(无访问修饰符):仅在同一包内的类可见。 -
protected
:在同一包内可见,以及在不同的包中的子类可见。 -
public
:对所有类都可见。
举例来说,我们可以将一个类的内部数据设置为 private
,然后提供 public
的方法来访问和修改这些数据。这样就保证了数据的安全性,同时提供了控制数据访问的能力。
public class Account {
private double balance; // 私有属性,外部不能直接访问
// 构造函数,用于对象创建时设置余额
public Account(double initialBalance) {
if (initialBalance > 0) {
this.balance = initialBalance;
}
}
// 提供方法以安全地修改余额
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
// 提供方法以安全地获取余额
public double getBalance() {
return balance;
}
}
在上述代码中, balance
属性被声明为 private
,这意味着它不能直接从类的外部访问。取而代之的是,我们提供了 deposit()
和 getBalance()
两个公共方法来修改和获取余额,从而实现了对 balance
的封装。
3.2 访问控制级别
3.2.1 私有、公共与保护
在Java中,访问控制分为四种不同的级别,它们分别控制了类成员(属性和方法)的访问权限:
-
private
:限制最严格的访问级别,仅在同一类内部可见。 -
default
(无访问修饰符):同一包内的类可见。 -
protected
:同包内的类可见,并且不同包的子类也可见。 -
public
:最广泛的访问级别,对所有类都可见。
不同的访问控制级别使得我们可以精确控制类的内部和外部对类成员的访问权限,从而帮助我们设计出具有良好封装性的类。
3.2.2 包的访问控制
包(package)是Java中的一个重要的概念,用于管理类和接口的命名空间。包访问控制指的是在同一包内的类之间可以互相访问各自的 default
访问级别的成员。这种机制可以用于简化同一包内类之间的相互作用。
例如,如果我们在同一个包内有两个类 ClassA
和 ClassB
,那么 ClassA
可以访问 ClassB
的 default
访问级别的成员。
package com.example;
class ClassA {
void methodA() {
ClassB objB = new ClassB();
objB.defaultMethodB(); // 可以调用,因为在同一包内
}
}
class ClassB {
void defaultMethodB() {
System.out.println("Default method B is called.");
}
}
通过使用包和访问控制级别,我们能够创建出模块化的代码库,这不仅有助于代码的组织和管理,还可以提升代码的安全性和可维护性。下一节我们将探讨继承的概念及其在代码重用中的作用。
4. 继承与代码重用
继承是面向对象编程中一种强大的机制,它允许新创建的类(子类)继承一个或多个已存在的类(父类)的属性和方法。代码重用是继承的主要好处之一,它有助于减少代码冗余,并促进模块化设计。
4.1 继承的基本概念
4.1.1 类的继承结构
在Java中,类的继承通过关键字 extends
来实现。一个子类继承父类后,可以访问父类中的所有公有(public)和保护(protected)成员,包括字段、方法和嵌套类。Java只支持单继承,即一个类只能有一个直接父类。
示例代码
class Animal {
public void eat() {
System.out.println("I can eat");
}
}
class Dog extends Animal {
// Dog类继承了Animal类
}
public class TestInheritance {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // 输出 "I can eat"
}
}
4.1.2 方法的重写与重载
子类不仅继承父类的方法,还可以重写(override)或重载(overload)它们。重写是子类提供一个特定父类方法的实现,而重载是在同一个类中创建多个同名方法,但参数不同。
示例代码
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
// 重写父类方法
@Override
public void makeSound() {
System.out.println("Dog barks");
}
// 方法重载示例
public void makeSound(int times) {
System.out.println("Dog barks " + times + " times");
}
}
public class TestOverriding {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // 输出 "Dog barks"
dog.makeSound(3); // 输出 "Dog barks 3 times"
}
}
4.2 继承与多态
4.2.1 继承的优缺点
继承的优点包括代码重用和创建一个层次结构。然而,过度使用继承可能导致代码过于复杂,并限制了类的设计灵活性。
表格:继承的优缺点
| 优点 | 缺点 | |------------|------------| | 代码重用 | 僵化的设计 | | 层次化设计 | 增加复杂性 | | 简化开发 | 维护成本高 |
4.2.2 组合与继承的选择
在某些情况下,组合比继承更合适。组合是通过引用其他对象来实现功能,这通常被认为是一种更灵活的设计选择,因为它提供了更好的封装性和更低的耦合度。
Mermaid流程图:继承与组合的选择
graph TD
A[开始] --> B{需要复用代码?}
B -->|是| C{子类设计?}
B -->|否| D{使用组合?}
C -->|是| E[使用继承]
C -->|否| F[重新设计类结构]
D -->|是| G[使用组合]
D -->|否| H[重新设计类结构]
E --> I[结束]
F --> I
G --> I
H --> I
继承与组合各有其适用场景,需要根据具体需求来选择使用哪种方式。在设计类时,应当仔细考虑两者之间的权衡,选择一种符合项目需求且能保持设计灵活性的方法。
5. 多态性的实现与应用
多态性是面向对象编程中的一项核心概念,它允许同一操作作用于不同的对象时,可以有不同的解释和不同的执行结果。在Java等面向对象语言中,多态性通过继承、接口和方法重写来实现。理解并正确使用多态性可以提高程序的可扩展性、可维护性和复用性。
5.1 多态性的定义与作用
5.1.1 多态性在Java中的表现
多态性在Java中主要体现在方法的重写(Override)和重载(Overload)。重写允许子类提供一个特定于自己版本的方法实现,而重载则是指同一个类内可以有多个同名方法,但参数列表不同,根据方法调用时传入的参数类型和数量的不同,选择不同的方法执行。
举例来说,假设有一个基类 Animal
和两个子类 Dog
和 Cat
。 Animal
类有一个 sound()
方法。 Dog
类重写了这个方法,输出"Dog barks",而 Cat
类则输出"Cat meows"。
class Animal {
public void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("Cat meows");
}
}
5.1.2 多态性的代码实践
在Java中,多态性的实现主要依赖于引用变量的类型。当我们使用接口或父类类型的引用变量指向一个对象时,调用的方法取决于对象的实际类型。
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.sound(); // 输出 "Dog barks"
myCat.sound(); // 输出 "Cat meows"
在上述代码中, myDog
和 myCat
虽然是 Animal
类型的引用,但是它们实际指向的 Dog
和 Cat
对象。因此,调用 sound()
方法时,执行的是各自子类重写的版本。
5.2 多态性的高级应用
5.2.1 抽象类与接口的应用
抽象类和接口是实现多态的两种重要手段。
- 抽象类可以通过声明抽象方法来强制子类重写这些方法,从而实现多态。
- 接口定义了一组规范,任何实现了接口的类都需要提供这些方法的具体实现,同样也是多态的一种表现。
5.2.2 设计模式中的多态性
在设计模式中,多态性也扮演了重要角色。比如,策略模式允许在运行时选择不同的算法实现,而不会影响使用算法的客户端。这正是通过多态性实现的。
以下是一个策略模式的简单例子:
// 策略接口定义
interface Strategy {
void execute();
}
// 具体策略A
class ConcreteStrategyA implements Strategy {
public void execute() {
System.out.println("Executing strategy A");
}
}
// 具体策略B
class ConcreteStrategyB implements Strategy {
public void execute() {
System.out.println("Executing strategy B");
}
}
// 上下文类,使用策略
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.execute();
}
}
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new ConcreteStrategyA());
context.executeStrategy(); // 执行策略 A
context.setStrategy(new ConcreteStrategyB());
context.executeStrategy(); // 执行策略 B
}
}
在这个例子中, Context
类的 executeStrategy()
方法根据其持有的 Strategy
对象的不同,执行不同的策略,显示了多态的应用。
通过上述章节的介绍,我们可以看到多态性不仅加深了我们对Java继承和接口实现的理解,还展示了如何在设计模式中应用多态性来提高系统的灵活性。多态性是Java中实现程序设计原则(如开闭原则)的关键技术之一。在下一章节,我们将深入探讨构造函数的使用,以及它如何在Java对象生命周期中发挥作用。
6. 构造函数的使用与作用
6.1 构造函数概述
6.1.1 构造函数的定义与作用
在Java编程中,构造函数是一种特殊的方法,它在创建对象时自动调用,用于初始化对象的状态。构造函数拥有与类相同的名称,并且没有返回类型,连void都没有。构造函数的主要作用是为新创建的对象分配内存,将默认值或显式指定的值赋给对象的属性,并执行其他必要的初始化任务。
一个类可以有多个构造函数,这种特性被称为构造函数重载。通过不同的构造函数重载,可以在创建对象时提供不同的初始化选项,从而实现灵活性和代码的可重用性。
6.1.2 默认构造函数与显式构造函数
当一个类中没有定义任何构造函数时,Java编译器会提供一个默认的无参构造函数。这个默认构造函数会执行对象的默认初始化,比如将基本类型的默认值设置为0或false,并且为对象的引用类型成员分配null。
显式构造函数是指程序员自己定义的构造函数。显式构造函数可以有参数,可以实现复杂的初始化逻辑。显式构造函数可以设置对象属性的初始值,也可以调用其他方法来完成对象的初始化工作。通过显式构造函数,程序员可以更精确地控制对象的创建过程。
public class Person {
private String name;
private int age;
// 显式无参构造函数
public Person() {
this.name = "Unknown";
this.age = 0;
}
// 显式带参构造函数
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
在上述代码中,定义了两个显式的构造函数。第一个构造函数对 name
和 age
属性进行默认初始化,而第二个构造函数则允许在创建 Person
对象时为其指定 name
和 age
值。
6.2 构造函数的高级特性
6.2.1 构造函数重载
构造函数重载是Java中多态性的一种体现,它允许一个类具有多个构造函数,只要它们的参数列表不同即可。通过构造函数重载,类可以根据不同的需求创建具有不同初始状态的对象。
重载构造函数时需要考虑构造函数的参数数量和类型。以下是一个具有构造函数重载的 Car
类示例:
public class Car {
private String make;
private String model;
private int year;
// 无参构造函数
public Car() {
this.make = "Unknown";
this.model = "Unknown";
this.year = 0;
}
// 带参构造函数:3个参数
public Car(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
}
// 带参构造函数:1个参数
public Car(String model) {
this.model = model;
}
}
在上述代码中, Car
类提供了三个不同的构造函数。开发者可以根据需要选择合适的构造函数来创建 Car
对象,例如:
Car car1 = new Car(); // 使用无参构造函数
Car car2 = new Car("Toyota", "Camry", 2021); // 使用带3个参数的构造函数
Car car3 = new Car("Corolla"); // 使用带1个参数的构造函数
6.2.2 静态工厂方法与构造器
在Java中,除了使用构造函数创建对象之外,还可以使用静态工厂方法来创建对象。静态工厂方法是一种提供对象创建的静态方法,它不属于某个特定的类实例,而属于类本身。
静态工厂方法的好处之一是它们有名称,这使得它们能够通过名称来描述它们的作用,而构造函数只能通过参数签名来区分。静态工厂方法也可以返回返回类型的任何子类型的对象,包括未指定的返回类型。
以下是 Rectangle
类使用静态工厂方法的一个示例:
public class Rectangle {
private double width;
private double height;
private Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
// 静态工厂方法
public static Rectangle createSquare(double side) {
return new Rectangle(side, side);
}
}
在这个例子中, createSquare
是一个静态工厂方法,它创建了一个正方形的 Rectangle
对象。使用静态工厂方法可以使得创建过程更加直观和有意义:
Rectangle square = Rectangle.createSquare(10.0);
6.2.3 代码逻辑解读
public static Rectangle createSquare(double side) {
return new Rectangle(side, side);
}
上述代码中, createSquare
方法是一个静态工厂方法,用于创建一个新的 Rectangle
对象,该对象代表一个边长为给定 side
参数值的正方形。方法接受一个 double
类型的参数,这个参数将用于设置正方形的宽度和高度。然后,方法使用这个参数值创建并返回一个新的 Rectangle
对象。
参数 side
在 Rectangle
构造函数中被用作宽度和高度的值,这表示正方形的两维尺寸相等。通过这种方式,可以很方便地通过静态工厂方法创建正方形的 Rectangle
对象实例。
6.2.4 静态工厂方法的优势
静态工厂方法相较于构造函数有以下优势:
- 它们有名称 。这意味着它们可以更精确地描述创建对象的目的,更易于理解。
- 它们不必每次调用时都创建新对象 。这允许实现单例模式或不可变对象,并且可以提高性能,如果需要的话。
- 它们可以返回返回类型的任何子类型的对象 。这为返回对象的类型提供了更多的灵活性。
- 它们在创建对象时可以接受参数,并且可以根据参数的不同返回不同的子类型 。这样可以根据传入参数的不同灵活创建不同类型的对象。
graph TD
A[调用静态工厂方法] --> B{检查参数}
B --> |参数有效| C[返回新对象]
B --> |参数无效| D[抛出异常]
以上是一个简化的流程图,描述了静态工厂方法的处理逻辑。当调用静态工厂方法时,它会首先检查参数的有效性。如果参数有效,就会创建并返回一个新对象。如果参数无效,则抛出异常。
在Java编程中,静态工厂方法是一种非常有用的工具,尤其当涉及到创建不可变对象或需要对构造过程有更精细控制时。
7. Student
与 Graduate
类的实践应用
7.1 类设计的实践
7.1.1 Student
类的设计与实现
在Java中,我们可以通过 class
关键字定义一个 Student
类。此 Student
类将包括学生的基本属性,如学号、姓名以及分数等,还可能包括方法,比如获取学生信息的方法。下面是一个简单的 Student
类设计和实现的例子。
public class Student {
// 属性
private String studentId;
private String name;
private double score;
// 构造函数
public Student(String studentId, String name, double score) {
this.studentId = studentId;
this.name = name;
this.score = score;
}
// getter和setter方法
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
// 获取学生信息的方法
public String getStudentInfo() {
return "Student ID: " + studentId + ", Name: " + name + ", Score: " + score;
}
}
这个类是面向对象设计的基础,它封装了学生的信息,并提供了相应的方法来进行访问和修改。
7.1.2 Graduate
类的继承与扩展
当我们需要创建一个研究生 Graduate
类时,我们可以让 Graduate
类继承自 Student
类,并添加一些额外的属性或方法来反映研究生的特殊性质,例如研究方向。继承允许 Graduate
类复用 Student
类中的代码,同时还可以添加新的功能。下面是一个简单的 Graduate
类的实现。
public class Graduate extends Student {
// 研究生特有的属性
private String researchArea;
// 构造函数
public Graduate(String studentId, String name, double score, String researchArea) {
super(studentId, name, score); // 调用父类构造函数
this.researchArea = researchArea;
}
// getter和setter方法
public String getResearchArea() {
return researchArea;
}
public void setResearchArea(String researchArea) {
this.researchArea = researchArea;
}
// 扩展方法,获取研究生的详细信息
public String getGraduateInfo() {
return super.getStudentInfo() + ", Research Area: " + researchArea;
}
}
通过继承, Graduate
类可以使用 Student
类的所有功能,并且通过扩展提供了额外的信息。这样设计不仅提高了代码的复用性,还降低了维护成本。
7.2 应用多态性和设计模式
7.2.1 实现多态的场景模拟
多态允许我们以统一的方式处理不同的对象类型。在Java中,多态通常是通过接口或继承实现的。我们可以在 Student
和 Graduate
的基础上,创建一个接口,比如 EducationalEntity
,来模拟多态的使用场景。
public interface EducationalEntity {
String getInfo();
}
然后让 Student
和 Graduate
类都实现这个接口。
public class Student implements EducationalEntity {
// ...(省略其它代码)
@Override
public String getInfo() {
return getStudentInfo();
}
}
public class Graduate implements EducationalEntity {
// ...(省略其它代码)
@Override
public String getInfo() {
return getGraduateInfo();
}
}
通过实现接口, Student
和 Graduate
对象都可以通过 EducationalEntity
接口调用 getInfo
方法,这样我们就可以用同样的方式处理这两种类型的对象,实现多态。
7.2.2 设计模式在实践中的应用案例
在Java编程实践中,设计模式可以帮助我们解决特定的设计问题。假设我们需要为学生和研究生提供不同的学费计算方法。我们可以使用工厂模式来创建一个工厂类,根据不同的类型返回不同类型的对象实例。下面是一个简化的应用示例:
public class EducationalFactory {
public static EducationalEntity createEducationalEntity(String type) {
if ("Student".equals(type)) {
return new Student("S001", "Alice", 88.5);
} else if ("Graduate".equals(type)) {
return new Graduate("G001", "Bob", 92.0, "Artificial Intelligence");
} else {
throw new IllegalArgumentException("Invalid type provided");
}
}
}
在这个例子中, EducationalFactory
类提供了一个静态方法 createEducationalEntity
,根据提供的类型参数创建并返回一个 Student
或 Graduate
的实例。这种方式让我们的代码在增加新的教育实体类型时更加灵活,因为我们可以轻松地扩展 EducationalFactory
类,而不需要修改现有的处理学生和研究生对象的代码。
这种应用设计模式的方法,使得代码更加清晰、易于维护,并且可扩展。
简介:Java中的面向对象编程是其核心概念,强调代码的可读性、可维护性及重用性。本次实验通过创建 Student
和 Graduate
类,让学生深入理解和掌握面向对象的特性,包括封装、继承和多态。学生将通过实验操作这些特性,理解类的设计、属性与方法的定义,以及如何通过继承扩展现有类,并实现对象的封装和多态调用。实验旨在通过实践加深对Java面向对象编程的理解,提升编程技能。