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

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

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
目录
相关文章
|
1月前
|
Java
在Java中,接口之间可以继承吗?
接口继承是一种重要的机制,它允许一个接口从另一个或多个接口继承方法和常量。
105 1
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
36 3
|
2月前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
57 2
|
2月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
41 2
|
2月前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
48 1
|
2月前
|
存储 Java 测试技术
Java零基础-多态详解
【10月更文挑战第10天】Java零基础教学篇,手把手实践教学!
37 4
|
2月前
|
Java 编译器 程序员
Java多态背后的秘密:动态绑定如何工作?
本文介绍了Java中多态的实现原理,通过动态绑定和虚拟方法表,使得父类引用可以调用子类的方法,增强了代码的灵活性和可维护性。文中通过具体示例详细解析了多态的工作机制。
79 4
|
3月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
2月前
|
Java 测试技术 编译器
Java零基础-继承详解!
【10月更文挑战第4天】Java零基础教学篇,手把手实践教学!
50 2
|
2月前
|
Java 编译器
在Java中,关于final、static关键字与方法的重写和继承【易错点】
在Java中,关于final、static关键字与方法的重写和继承【易错点】
33 5