Java基础之类封装、继承、多态

简介: Java基础的封装、继承和多态是OOP的核心。封装通过访问控制(如private)隐藏类的内部细节,提供公共接口供外部交互。例如,`Person`类封装`name`和`age`,通过`getName()`和`setAge()`方法访问。继承允许子类(如`Dog`)继承父类(如`Animal`)的属性和方法,并可扩展或覆盖。多态使得父类引用可指向子类对象,调用方法时根据实际对象类型执行,如不同动物的`makeSound()`。接口实现多态提供了一种定义行为而不必关心实现的方式。向上转型(子类→父类)安全且默认,而向下转型(父类→子类)需类型检查以避免异常。

Java基础之类封装、继承、多态
上篇我们学习了Java的类和对象,类定义了对象的属性和方法,对象可以使用new关键字将类实例化。
今天来看面向对象编程(OOP)的三大基本也是其核心特性: 封装、继承与多态。
封装
在Java中,一个个的包(Package)包含了很多很多的类,每个类中都有各自的属性和行为,我们在使用的时候,可以通过import关键字引入包中的类。
然后实例化对象来调用其中的属性和方法,方法内部对调用者来说是不可见的,这个就是封装的概念。
封装是面向对象编程的基础,它将数据和行为组合在一个包中,并对对象的使用者隐藏了具体的实现细节。
也就是说我们通过定义类(Class)来实现了封装,同时使用private、public等关键字来实现对属性和方法的可访问权限控制。
public class Person {
private String name; // 私有属性,外部不能直接访问
private int age; // 私有属性,外部不能直接访问
// 构造函数
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 公共方法,用于获取name属性
public String getName() {
return name;
}
// 公共方法,用于设置name属性
public void setName(String name) {
this.name = name;
}
// 公共方法,用于获取age属性
public int getAge() {
return age;
}
// 公共方法,用于设置age属性
public void setAge(int age) {
if (age >= 0) { // 设置年龄前进行校验
this.age = age;
} else {
System.out.println("年龄不能为负数");
}
}
// 行为方法
public void introduce() {
System.out.println("我的名字是:" + name + ",我今年" + age + "岁");
}
}
// 使用Person类
public class Main {
public static void main(String[] args) {
Person person = new Person("张三", 25);
person.introduce(); // 输出:我的名字是:张三,我今年25岁
person.setAge(-1); // 输出:年龄不能为负数
}
}
在上面的代码中,Person 类封装了 name 和 age 属性,以及与之相关的方法。通过将属性设置为私有(private),我们防止了外部直接访问这些属性,必须通过公共(public)方法来间接访问和修改,从而保证了数据的完整性和安全性。
这就是类的封装,调用者只需关注调用方法,不需要关注方法内部的实现,而且等到需要修改方法中实现的时候,也不会影响到调用者的代码逻辑。

继承(Inheritance)
继承其实就和现实中父与子的关系一样了,一个子类可以通过继承父类来获取父类的属性和方法。
子类可以有父类没有的拓展的属性和方法,也可以重写覆盖掉父类的方法。
现实中一个儿子只能有一个爹,但是一个爹能有多个儿子。父类和子类也一样,父类可以有多个子类继承,但是子类必须只能有一个父类。
// 父类
public class Animal {
    protected String name; // 保护级别属性,子类可以访问
    public Animal(String name) {
        this.name = name;
    }
    public void makeSound() {
        System.out.println("动物叫声");
    }
}
// 子类
public class Dog extends Animal {
    public Dog(String name) {
        super(name); // 调用父类构造函数
    }
    @Override
    public void makeSound() {
        System.out.println(name + "在汪汪叫");
    }
    public void fetch() {
        System.out.println(name + "在取东西");
    }
}
// 使用继承
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("旺财");
        dog.makeSound(); // 输出:旺财在汪汪叫
        dog.fetch();     // 输出:旺财在取东西
    }
}
Dog 类继承自 Animal 类。Dog 类不仅拥有了 Animal 类的 name 属性和 makeSound 方法,还添加了一个新的方法 fetch。同时,Dog 类覆盖了 makeSound 方法,提供了自己的实现。
这就是继承的概念,父类也叫超类。注意protected关键和private一样也是用来访问控制的,意思是非公共但是子类也可以访问的权限。

多态(Polymorphism)
多态是面向对象编程中的一个核心概念,它允许我们以统一的接口来处理不同类型的对象。
在Java中,多态通常通过继承和接口实现。
上面我们知道了多个子类可以通过继承父类来继承父类的属性和方法,然后对父类的方法进行不同的覆盖实现。
多态的原理就是基于类的继承关系:当子类继承父类时,子类会继承父类的所有公有(public)和受保护(protected)的成员变量和方法。
这样,我们就可以使用父类的引用来指向子类的对象,而调用方法时,会根据实际的对象类型来执行相应的方法。
// 父类
class Animal {
    public void makeSound() {
        System.out.println("动物叫声");
    }
}
// 子类
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪叫");
    }
}
// 子类
class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("喵喵叫");
    }
}

// 使用多态
public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal cat = new Cat();
        dog.makeSound(); // 输出:汪汪叫
        cat.makeSound(); // 输出:喵喵叫
    }
}
在上面的例子中,我们定义了一个父类 Animal 和两个子类 Dog 和 Cat。
子类都覆盖了父类的 makeSound 方法。
我们创建了 Animal 类型的引用,但实际上指向了 Dog 和 Cat 的对象。当我们调用 makeSound 方法时,会根据实际的对象类型来执行相应的方法,这就是多态的概念。
同样都是makeSound(),但是不同对象调用后就会有不同的实现,狗是汪汪,猫是喵喵。
还有一种多态的实现,是用接口实现。
接口是什么呢?
接口是一种抽象类型,它允许我们定义一组方法,而不需要实现这些方法。
通过用类来实现接口,类就可以使用接口类型的引用来指向实现接口的类的对象,而调用方法时,会执行类实现的相应方法。
所以接口就相当于一个父类,但是接口不需要像父类一样有自己的实现:
// 这样就定义了一个接口。
interface Flyable {
    //飞
    void fly();
}
// 实现接口的类
class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("鸟儿飞翔");
    }
}
// 实现接口的类
class Airplane implements Flyable {
    @Override
    public void fly() {
        System.out.println("飞机飞行");
    }
}

// 使用多态
public class Main {
    public static void main(String[] args) {
        Flyable bird = new Bird();
        Flyable airplane = new Airplane();
        bird.fly(); // 输出:鸟儿飞翔
        airplane.fly(); // 输出:飞机飞行
    }
}
我们定义了一个接口 Flyable 和两个实现接口的类 Bird 和 Airplane。在 Main 类中,我们创建了 Flyable 类型的引用,但实际上指向了 Bird 和 Airplane 的对象。当我们调用 fly 方法时,会根据实际的对象类型来执行相应的方法。

父类通常用来表示is-a关系,即子类是父类的一种。
接口用来表示can-do关系,即实现接口的类具有某种能力或行为。
子类只能有一个父类,但是实现类能实现多个接口

向上转型和向下转型的类型转换
上面实现多态的这种将子类对象引用赋值给父类引用的过程其实叫向上转型。当然实现类引用赋值给接口也一样。
这种转型是安全的,因为子类对象一定是父类的一个实例。向上转型会丢失子类特有的方法和属性,但仍然可以访问父类中定义的方法和属性。
还有对应的一种是向下转型,将父类对象引用赋值给子类引用的过程。这种转型是不安全的,因为父类对象可能不是子类的一个实例。如果直接进行向下转型,可能会导致 ClassCastException。因此,在向下转型之前,通常需要使用 instanceof 运算符来检查对象是否是子类的实例。
当然我们编写代码的时候一般肯定是知道,所以常用的就是直接强转:
if (animal instanceof Dog) {
    Dog dog = (Dog) animal; // 向下转型,前提是animal确实是Dog类型的实例
} else {
    // 不是Dog类型的实例,不能进行向下转型
}
向上转型和向下转型是多态性的两个方面。
向上转型是隐式的,通常在继承和接口实现中自动发生。
向下转型是显式的,需要使用强制类型转换,并且在使用前应该进行类型检查,以确保类型转换的安全性。
END
目录
相关文章
|
5天前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
2天前
|
Java API
Java的日期类都是怎么用的
【10月更文挑战第1天】本文介绍了 Java 中处理日期和时间的三个主要类:`java.util.Date`、`java.util.Calendar` 和 `java.time` 包下的新 API。`Date` 类用于表示精确到毫秒的瞬间,可通过时间戳创建或获取当前日期;`Calendar` 抽象类提供丰富的日期操作方法,如获取年月日及时区转换;`java.time` 包中的 `LocalDate`、`LocalTime`、`LocalDateTime` 和 `ZonedDateTime` 等类则提供了更为现代和灵活的日期时间处理方式,支持时区和复杂的时间计算。
26 14
|
7天前
|
安全 Java 数据安全/隐私保护
Java 封装怎么理解
封装是Java中的一种重要机制,它将对象的状态(数据)和行为(方法)打包在一起并控制外部访问权限,以保护数据不被随意修改。封装的主要目的包括数据保护、接口设计和增强模块性。通过使用`private`、`protected`及`public`等访问控制修饰符,结合getter和setter方法,可以有效隐藏对象内部实现细节。下面是一个简单的`BankAccount`类示例,展示了如何通过封装保护类的内部状态,确保数据安全和一致性,简化类的使用。理解封装有助于编写高质量代码和设计优秀程序架构。
|
7天前
|
Java 数据安全/隐私保护
Java 封装详解
在 Java 中,封装是面向对象编程的关键特性,通过将对象的状态(数据)和行为(方法)结合并利用访问控制保护数据,防止外部随意访问和修改。主要特点包括访问控制(如 `private` 和 `protected`)、数据隐藏及方法暴露(如 getter 和 setter)。封装的优点在于保护数据、隐藏实现细节、易于维护以及提高代码可读性。下面是一个简单的 `Person` 类封装示例,展示了如何通过 getter 和 setter 控制对类内部状态的访问,并进行合法性检查。总结而言,封装有助于构建清晰、易用且可维护的代码结构,是编写高质量 Java 程序的重要原则。
|
6天前
|
安全 Java 编译器
java访问类字段
java访问类字段
|
8天前
|
Java
java的class类
java的class类
18 5
|
6天前
|
安全 Java 开发者
Java修饰符与封装:理解访问权限、行为控制与数据隐藏的重要性
Java中的修饰符和封装概念是构建健壯、易维护和扩展的Java应用程序的基石。通过合理利用访问权限修饰符和非访问修饰符,开发者能够设计出更加安全、灵活且高效的代码结构。封装不仅是面向对象编程的核心原则之一,也是提高软件项目质量和可维护性的关键策略。
10 1
|
8天前
|
Java
Java 多态趣解
在一个阳光明媚的午后,森林中的动物们举办了一场别开生面的音乐会。它们组成了一支乐队,每种动物都有独特的演奏方式。通过多态的魅力,狗、猫和青蛙分别展示了“汪汪”、“喵喵”和“呱呱”的叫声,赢得了观众的阵阵掌声。熊指挥着整个演出,每次调用 `perform()` 方法都能根据不同的动物对象唤起对应的 `makeSound()` 方法,展现了 Java 多态性的强大功能,让整场音乐会既有趣又充满表现力。
|
8天前
|
Java
Java 的继承
在一个森林中,各种动物共存,如狗和猫。为了管理和组织这些动物,我们采用面向对象的方法设计模型。首先创建 `Animal` 超类,包含 `name` 和 `age` 属性及 `makeSound()` 和 `displayInfo()` 方法。接着,通过继承 `Animal` 创建子类 `Dog` 和 `Cat`,重写 `makeSound()` 方法以发出不同的声音。实例化这些子类并使用它们,展示了继承带来的代码重用、扩展性和多态性等优点。这种方式不仅简化了代码,还体现了现实世界的层次结构。
|
2月前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
47 7
下一篇
无影云桌面