Java多态、封装和继承是面向对象编程的重要概念,它们能够提高代码的可维护性和可扩展性。我将通过代码案例详细介绍这三个概念,并通过一个题目再过一遍,强化理解。
多态是指同一个方法在不同的对象上有不同的表现形式。在Java中,多态可以通过继承和接口实现。
首先,我们定义一个动物类Animal:
public class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
然后,我们定义两个子类Cat和Dog,它们继承自Animal类:
public class Cat extends Animal {
public void makeSound() {
System.out.println("猫发出“喵喵”的声音");
}
}
public class Dog extends Animal {
public void makeSound() {
System.out.println("狗发出“汪汪”的声音");
}
}
接下来,我们创建一个测试类Test,通过多态的方式调用makeSound方法:
public class Test {
public static void main(String[] args) {
Animal animal1 = new Cat();
Animal animal2 = new Dog();
animal1.makeSound(); // 输出:猫发出“喵喵”的声音
animal2.makeSound(); // 输出:狗发出“汪汪”的声音
}
}
在上面的例子中,animal1和animal2都是Animal类型的引用,但是它们分别指向了Cat和Dog对象。当调用makeSound方法时,会根据实际对象的类型来确定调用哪个子类的方法,这就是多态的体现。
根据上述创建的两个对象:本类对象和子类对象,同样都是父类的引用,当我们指向不同的对象时,它们调用的方法也是多态的。
创建本类对象时,调用的方法为本类方法;
创建子类对象时,调用的方法为子类重写的方法或者继承的方法;
使用多态的时候要注意:如果我们在子类中编写一个独有的方法(没有继承父类的方法),此时就不能通过父类的引用创建的子类对象来调用该方法!!!
注意: 继承是多态的基础。
多态方式声明是一种好的习惯。当我们创建的类,使用时,只用到它的超类或接口定义的方法时,我们可以将其索引声明为它的超类或接口类型。
它的好处是,如果某天我们对这个接口方法的实现方式变了,对这个接口又有一个新的实现类,我们的程序也需要使用最新的实现方式,此时只要将对象实现修改一下,索引无需变化。
封装是将数据和方法包装在类中,通过访问修饰符控制对这些数据和方法的访问权限。封装可以隐藏内部实现细节,提供对外的接口。
我们以一个人类Person为例,定义一个私有属性name和一个公有方法getName:
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在上面的例子中,name属性被声明为私有,外部无法直接访问,只能通过公有的getName和setName方法来访问和修改name属性。
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.setName("张三");
System.out.println(person.getName()); // 输出:张三
}
}
在上面的例子中,通过setName方法设置name属性的值,通过getName方法获取name属性的值。这样做的好处是可以对属性的访问进行控制,保证数据的安全性。
继承是指一个类可以继承另一个类的属性和方法。子类可以继承父类的非私有属性和方法,并且可以在子类中添加新的属性和方法。
我们以一个图形类Shape为例,定义一个计算面积的方法area:
public class Shape {
protected double area;
public double getArea() {
return area;
}
}
然后,我们定义一个矩形类Rectangle,它继承自Shape类,并添加新的属性length和width:
public class Rectangle extends Shape {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
public void calculateArea() {
area = length * width;
}
}
接下来,我们创建一个测试类Test,通过Rectangle类计算矩形的面积:
public class Test {
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(5, 8);
rectangle.calculateArea();
System.out.println(rectangle.getArea()); // 输出:40.0
}
}
在上面的例子中,Rectangle类继承了Shape类的area属性和getArea方法,并在calculateArea方法中计算了矩形的面积。通过继承,我们可以复用父类的属性和方法,并且可以在子类中进行扩展。
多态可以提高代码的灵活性和可扩展性,封装可以保证数据的安全性,继承可以复用父类的属性和方法,并进行扩展。理解和掌握这些概念对于编写高质量的面向对象程序非常重要。
假设我们要设计一个简单的图书管理系统,其中有两种类型的图书:小说和教材。每种图书都有编号、名称和作者属性,可以借阅和归还。
请根据上述要求,使用多态、封装和继承的概念设计一个简单的图书管理系统,并实现借阅和归还功能。
public class Book {
private String id;
private String name;
private String author;
private boolean borrowed;
public Book(String id, String name, String author) {
this.id = id;
this.name = name;
this.author = author;
this.borrowed = false;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getAuthor() {
return author;
}
public boolean isBorrowed() {
return borrowed;
}
public void borrow() {
borrowed = true;
}
public void returnBook() {
borrowed = false;
}
}
public class Novel extends Book {
public Novel(String id, String name, String author) {
super(id, name, author);
}
}
public class Textbook extends Book {
public Textbook(String id, String name, String author) {
super(id, name, author);
}
}
public class Library {
private List books;
public Library() {
books = new ArrayList<>();
}
public void addBook(Book book) {
books.add(book);
}
public void borrowBook(String id) {
for (Book book : books) {
if (book.getId().equals(id)) {
if (!book.isBorrowed()) {
book.borrow();
System.out.println("借阅成功!");
} else {
System.out.println("该图书已被借阅!");
}
return;
}
}
System.out.println("未找到该图书!");
}
public void returnBook(String id) {
for (Book book : books) {
if (book.getId().equals(id)) {
if (book.isBorrowed()) {
book.returnBook();
System.out.println("归还成功!");
} else {
System.out.println("该图书未被借阅!");
}
return;
}
}
System.out.println("未找到该图书!");
}
}
public class Test {
public static void main(String[] args) {
Library library = new Library();
Book novel = new Novel("001", "《红楼梦》", "曹雪芹");
Book textbook = new Textbook("002", "《高等数学》", "朱华伟");
library.addBook(novel);
library.addBook(textbook);
library.borrowBook("001"); // 输出:借阅成功!
library.borrowBook("001"); // 输出:该图书已被借阅!
library.returnBook("001"); // 输出:归还成功!
library.returnBook("001"); // 输出:该图书未被借阅!
}
}
在上面的例子中,我设计了一个图书管理系统,其中包含了三个类:Book、Novel、Textbook和Library。
Book类是一个基类,它包含了图书的共有属性和方法,如编号、名称、作者、借阅状态等。Novel和Textbook类是Book类的子类,它们继承了Book类的属性和方法,并且可以根据需要进行扩展。在本例中,我们没有对Novel和Textbook类进行扩展,只是简单地创建了它们的实例。
Library类是图书管理系统的核心类,它包含了一个Book对象的列表,可以添加图书、借阅图书和归还图书。在借阅和归还图书的方法中,我们遍历图书列表,根据图书的编号进行匹配,并根据借阅状态进行相应的操作。
在Test类中,我们创建了一个Library对象,并添加了两本图书。然后,我们分别借阅和归还了一本图书,并输出相应的结果。
通过这个例子,我们可以看到多态、封装和继承的应用。多态使得我们可以使用Book类型的变量来引用不同类型的图书对象,从而实现了对图书的统一管理。封装保证了图书对象的属性只能通过方法进行访问和修改,提高了数据的安全性。继承使得我们可以复用Book类的属性和方法,并在子类中进行扩展。
当然,这只是一个简单的图书管理系统的设计,实际的图书管理系统可能还包含更多的功能和复杂的业务逻辑。但是,通过这个例子,你应该能够理解多态、封装和继承的基本概念,并且能够应用它们来设计和实现面向对象的程序。