【Java初阶(六)上】封装 继承 多态

❣博主主页: 33的博客❣
▶文章专栏分类: Java从入门到精通◀
🚚我的代码仓库: 33的代码仓库🚚

目录

  • 1.前言
  • 2.封装
    • 2.1如何实现封装
    • 2.2 访问限定符
    • 2.3包的概念
      • 2.3.1导入包中的类
      • 2.3.2自定义包
  • 3.继承
    • 3.1为什么要继承
    • 3.2继承的概念
    • 3.3继承的语法
    • 3.4父类成员访问
      • 3.4.1子类中访问父类的成员变量
    • 3.5子类构造方法
    • 3.6super和this
    • 3.7继承方式
    • 3.8final 关键字
    • 3.9继承和组合
  • 4.总结

1.前言

对于面向对象程序三大特性:封装、继承、多态。这篇文章将会详细讲解到如何实现封装、继承、多态,以及具体的应用。

本章重点

掌握封装的概念,如何实现封装,包的概念,继承的概念,为什么要继承,继承的相关语法,子类构造方法等等。

2.封装

对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器,USB插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU、显卡、内存等一些硬件元件。因此计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互

2.1如何实现封装

class Student {
    private String name;//用private权限修饰可以实现,此时name只能在当前类中使用
    private int age;
    private String sex;
}

那么这个时候我如果想在其他类值获取被private修饰的成员变量的值,该如何修改呢?其实,只需要设置set和get方法,就可以在其他类中访问了。
快捷生成方式如下:

2.2 访问限定符

Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:

public:可以理解为一个人的外貌特征,谁都可以看得到
default: 对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了
private:只有自己知道,其他人都不知道
protected:子类或者同一类都可以访问

2.3包的概念

在上面四种权限中,我们可以看到多次提到了包,那么什么是包呢?其实包简单来说就是一个文件夹。为了更好的管理类,把多个类收集在一起成为一组,称为软件包有点类似于目录。比如:为了更好的管理电脑中的歌曲,一种好的方式就是将相同属性的歌曲放在相同文件下,也可以对某个文件夹下的音乐进行更详细的分类。

包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。

2.3.1导入包中的类

其实在之前,认识键盘输入的时候,我们已经接触过导入包中的类了:

import java.util.Scanner;

如果我们需要导入util中的其他类也导入,格式如下:

import java.util.*;

虽然导入了util这个文件底下的所有类,但在Java中用到那个类才会导入它。
但这样导入一个包下所有类有弊端l,两个包底下出现了同一个类就不能编译:比如util包和sql包下都有Date类,当调用Date类的时候,编译器也不知道用谁的。

import java.util.*;
import java.sql.*;
Date date1 = new Date();
Date date1 = new Date();

我建议显式的指定要导入的类名. 否则容易出现冲突的情况。

2.3.2自定义包

基本规则

  • 在文件的最上方加上一个 package 语句指定该代码在哪个包中.
  • 包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式例如:(com.baidu.www)
  • 包名要和代码路径相匹配. 例如创建代码(com.baidu.www)的包,那么会存在一个对于路径com/baidu/www
  • 如果一个类没有 package 语句, 则该类被放到一个默认包中
    操作步骤:
    1. 在 IDEA 中先新建一个包: 右键 src -> 新建 -> 包

    2. 在弹出的对话框中输入包名,例如com.baidu.www,下图是按一层一层进行显示

3.继承

3.1为什么要继承

Java中使用类对现实世界中实体来进行描述,类经过实例化之后的产物对象,则可以用来表示现实中的实体,但是现实世界错综复杂,事物之间可能会存在一些关联,那在设计程序是就需要考虑。
比如:狗和猫,它们都是一个动物。

// Dog
 public class Dog{
 string name;
 int age;
 f
 loat weight;
 public void eat(){
 System.out.println(name + "正在吃饭");
 }
 public void sleep(){
 System.out.println(name + "正在睡觉");
 }
void Bark(){
System.out.println(name + "汪汪汪~~~");
 }
 }
 // Cat
 public class Cat{
 string name;
 int age;
 f
 loat weight;
 public void eat(){
 System.out.println(name + "正在吃饭");
 }
 public void sleep()
 {
 System.out.println(name + "正在睡觉");
 }
 void mew(){
 System.out.println(name + "喵喵喵~~~");
 }
 }

观察上面代码,我们会发现它们都存在大量相同的属性和方法

狗:
string name;
int age;
public void eat()
public void sleep()
void Bark()

猫:
string name;
int age;
public void eat()
public void sleep()
void mew()

那能否将这些共性抽取呢?面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。

3.2继承的概念

继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。

上述图示中,Dog和Cat都继承了Animal类,其中:Animal类称为父类/基类或超类,Dog和Cat可以称为Animal的子类/派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。

3.3继承的语法

在Java中要表示类之间的继承关系,需要借助extends关键字,具体如下:

修饰符 class 子类 extends 父类 {
 // ...  
}

注意

  1. 子类会将父类中的成员变量或者成员方法继承到子类中了。
  2. 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了。

3.4父类成员访问

在继承体系中,子类将父类中的方法和字段继承下来了,那在子类中能否直接访问父类中继承下来的成员呢?

3.4.1子类中访问父类的成员变量

1.访问不同名的成员变量

//父类
public class Base {
 int a;
 int b;
 }
 //子类
 public class Derived extends Base{
 int c;
 public void method(){
 a = 10;    // 访问从父类中继承下来的a
 b = 20;    // 访问从父类中继承下来的b
 c = 30;    // 访问子类自己的c
 }
 }

2.访问同名的成员变量

public class Base {
 int a;
 int b;
 int c;
 }
public class Derived extends Base{
    int a;              // 与父类中成员a同名,且类型相同
    char b;             // 与父类中成员b同名,但类型不同
 
    public void method(){
        a = 100;        // 访问父类继承的a,还是子类自己新增的a?
        b = 101;        // 访问父类继承的b,还是子类自己新增的b?
        c = 102;        // 子类没有c,访问的肯定是从父类继承下来的c
        // d = 103;     // 编译失败,因为父类和子类都没有定义成员变量b
    }
 }

那如在同名的情况下,我想访问父类的成员,该怎么办呢?可以使用super关键字

public class Base {
 int a;
 int b;
 int c;
 }
public class Derived extends Base{
    int a;              // 与父类中成员a同名,且类型相同
    char b;             // 与父类中成员b同名,但类型不同
 
    public void method(){
        super.a = 100;        // 访问父类继承的a
        super.b = 101;        // 访问父类继承的b
        c = 102;        // 子类没有c,访问的肯定是从父类继承下来的c
        // d = 103;     // 编译失败,因为父类和子类都没有定义成员变量b
    }
 }

在子类方法中 或者 通过子类对象访问成员时:

  • 如果访问的成员变量子类中有,优先访问自己的成员变量。
  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的。
  • 如果想访问父类成员,可以使用super关键字。
  • 成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。

3.5子类构造方法

父子父子,先有父再有子,即:子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。

//Animal
public  String name;
    public  int age;
    public String color;
    public void eat(){
        System.out.println(this.name+"正在吃饭");
    }

    public Animal(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
//Cat
public class Cat extends Animal{

    public Cat(String name, int age, String color) {
        super(name, age, color);//初始化父类构造方法
    }
    public void mew(){
        System.out.println("喵喵喵~~~");
    }
}

如果我父类没有构造方法,子类也不调用,会报错吗?答案是不会的,因为父类没有构造方法会默认生成一个,此时就会调用生成的构造方法,只不过看不见。
注意

  • 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构
    造方法
  • 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的
    父类构造方法调用,否则编译失败。
  • 在子类构造方法中,super(…)调用父类构造时,必须是子类构造函数中第一条语句。
  • super(…)只能在子类构造方法中出现一次,并且不能和this同时出现

3.6super和this

super和this都可以在成员方法中用来访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语句,那他们之间有什么区别呢?
【相同点】

  1. 都是Java中的关键字
  1. 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
  2. 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
    【不同点】
  1. this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用。
  2. 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性。
  3. 在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造方法中出现。
  4. 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有。

3.7继承方式

在现实生活中,事物之间的关系是非常复杂,灵活多样,比如:

Java中的几种继承:
单继承:

public class A{
}
public class B extend A{
}

多层继承

public class A{
}
public class B extend A{
}
public class C extend B{
}

注意:Java中不支持多继承,指的是不支持一个类继承多个父类。
但是即使如此, 我们并不希望类之间的继承层次太复杂. 一般我们不希望出现超过三层的继承关系. 如果继承层次太多, 就需要考虑对代码进行重构了。
如果想从语法上进行限制继承, 就可以使用 final 关键字。

3.8final 关键字

final关键可以用来修饰变量、成员方法以及类。
1.修饰变量:表示常量

final int a = 10;//此时a是一个常量不能再改变
  1. 修饰类:表示此类不能被继承
final public class Animal {
 }

3.9继承和组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段。
继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物
组合表示对象之间是has-a的关系,比如:汽车

例如

// 轮胎类
class Tire{
//....
 }
// 发动机类
class Engine{
    // ...
 } 
// 车载系统类
class VehicleSystem{
    // ...
 }
//组合 
class Car{
    private Tire tire;          // 可以复用轮胎中的属性和方法
    private Engine engine;      // 可以复用发动机中的属性和方法
    private VehicleSystem vs;   // 可以复用车载系统中的属性和方法 
    // ...
 } 
// 继承:奔驰是汽车
class Benz extend Car{
    // 将汽车中包含的:轮胎、发送机、车载系统全部继承下来
}

4.总结

本篇文章主要讲了有关封装和继承的相关知识点,在下一篇文章中博主将继续更新多态的相关知识点,感兴趣的同学可以关注博主哦。

下期预告:多态

版权声明:本文为博主作者:PU-YUHAN原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/weixin_69049913/article/details/136969980

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2024年4月10日
下一篇 2024年4月10日

相关推荐