封装继承和多态(详细)
前言:作为一名大四的学生,目前已经实习了半年,如果要是问封装继承和多态,依然有时候说不太清楚,十分羞愧,今天就写下了这篇文章。
封装
通俗来讲就是:就是隐藏对象内部的属性和方法,转而暴露为公共的接口,只需要负责去调用接口,不需要关心内部实现的细节。
1.封装的体现
- 属性的封装
- 方法的封装
- 构造函数的封装
具体提现:
- 属性:使用private修饰符来对成员变量进行修饰
- 方法:使用private修饰符来对方法进行封装
- 构造函数:对构造函数进行private修饰符进行修饰,举例单例模式
根据难易度来区分 只演示第三种情况
public class Singleton {
// 用一个静态私有属性来保存对象
private static Singleton test;
// 建立私有构造方法
private Singleton() {
}
// 建立一个公共方法,用于获取对象
public static Singleton getTest(){
if (Objects.isNull(test)) {
test = new Singleton();
}
return test;
}
}
// 在另一个类中调用
// 通过Singleton中的静态方法获取对象
public class Main {
public static void main(String[] args) {
Singleton test = Singleton.getTest();
}
}
封装的好处:
- 隐藏内部实现细节,只能通过特定的方法去获取数据
- 方便对于代码的修改、以及提高代码的复用度
- 可以任意修改数据的读写权限
继承
1.什么是继承?
继承是子类继承父类的(共有)属性和(共有)方法,
私有属性和方法是不能继承的,如果需要操作私有属性和方法,可以写一个父类写一个公共方法
2.操作私有属性和方法
class Father{
int age = 10;
// 私有属性
private int year = 65;
public int getAge() {
return age;
}
// 公共方法操作私有属性
public int getYear(){
return year;
}
}
class Son extends Father{
}
public static void main(String[] args) {
// 主方法直接操作公共方法
Son son = new Son();
System.out.println(son.getYear());
}
3.继承规则
- 只支持单继承,不支持多继承 也就是说 一个儿子只能有一个爸爸 但是一个爸爸可以有多个儿子
- 子类继承父类以后 ,如果父类之上还有父类 同样也拥有顶级父类的公有属性和公有方法
4.方法重写
4.1 什么是重写
如果一个类继承了一个类,可以根据自己的需要,对父类的继承来的方法进行重写(!如果是方法重写,必须要加@Override 这个注解(阿里开发手册要求!具体原因可以百度)
4.2 重写规则
- 重写以后,当子类对象调用与分类同名,同参数的方法时,优先调用子类重写的方法。
- 子类重写的方法必须要与父类中被重写的方法同名、同参数
- (容易忽视) 子类重写的方法的返回值类型,不能大于父类被重写方法的返回类型
1.父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void。
2.父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以使A类或A类的子类。
3.父类被重写的方法的返回值类型是基本数据类型(比如double),则子类重写的方法的返回值类型必须是相同的基本数据类型。
- 子类重写的方法的访问权限不能低于父类方法的访问权限
- 子类不能重写static方法
5.super关键字
使用super调用父类的属性和方法
5.1 使用方法
- 访问父类构造器 :super() 或者 super(参数)
- 访问父类属性或者方法 super.属性 super.方法名
若想在子类中调用父类的同名属性或者方法时,必须显式的使用super
6. 继承的好处
- 增强代码复用性,减少代码冗余
- 便于功能扩展
多态
1.什么是多态
简单来说就是对象和方法具有多种形态
解释:一个对象可以根据其引用,采取不同的行为方式。在多态这个概念中,最重要的一点是父类的引用指向子类的对象。
两个问题:1. 该引用到底指向哪一个类? 改引用发出的方法到底是哪一个类中的方法? 这些在编译时并不确定,必须在程序运行期间才确定
只看这段话还是觉得非常难懂 我们用代码演示一下
2.代码演示
// 首先我们需要知道 什么叫对象的引用
Animal an = new Animal();
//其中 an就是对象引用 原理请细看 JVM那一部分的知识
// 这是父类
class Father{
int age = 10;
int year = 65;
public int getAge() {
return age;
}
public int getYear(){
return year;
}
@Override
public String toString() {
return "父亲";
}
}
// 这是子类
class Son extends Father{
int age = 110;
int sex = 1;
@Override
public int getAge() {
return age;
}
}
// 当我们在主函数创建对象的时候
public static void main(String[] args) {
Father father = new Son();
System.out.println(father.getAge());
}
// 你可以猜一下 答案 输出结果是什么 答案:110
// 那如果我们子类中的getAge方法删掉 输出又是什么呢
class Son extends Father{
int age = 110;
int sex = 1;
}
// 现在输出就变成了 10
3.原理解释
上面为什么会变成这样呢
这就要解释一下 多态的原理:动态绑定机制
当调用对象方法时,该方法会和对象的内存地址/(运行类型)绑定;调用属性时,没有绑定机制,哪里声明哪里使用。
Father father = new Son(); 其中前面father是引用类型 Son是运行类型
其中,使用引用对象的方法时,会先去检查父类中有没有该方法,没有直接报错。之后如果子类中有重写该方法,优先调用子类中的方法,如果子类没有重写,则去调用父类中的方法。