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

04-09 阅读 0评论

❣博主主页: 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方法,就可以在其他类中访问了。

            快捷生成方式如下:

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


            2.2 访问限定符

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

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

            public:可以理解为一个人的外貌特征,谁都可以看得到

            default: 对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了

            private:只有自己知道,其他人都不知道

            protected:子类或者同一类都可以访问


            2.3包的概念

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

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

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


            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 -> 新建 -> 包

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

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

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


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

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

              上述图示中,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(…)用户不写则没有。

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


                  3.7继承方式

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

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

                  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.总结

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


                  下期预告:多态


免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,人围观)

还没有评论,来说两句吧...

目录[+]