• 面向对象的特点


    面向对象的特点

    封装

    什么是封装?

    ​ 封装表面意思就是封锁和包装;把信息进行隐藏起来;是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。

    好处:

    ​ 调用封装的对象时,只需通过接口来进行操作,无需知道对象内部的细节,最重要的是可以起到保护数据的作用。

    ​ 另外,封装可以隐藏内部实现细节,站在对象外部是看不到内部复杂结构的,对外只提供了简单的安全的操作入口。

    如何封装?

    ​ 在Java语言中可以使用private修饰符,private修饰的数据表示私有的,私有的数据只能在本类中访问。当外界需要进入访问的时候,这时需要对外提供公共的访问入口,让外部程序统一通过这个入口处设立关卡,进行安全控制.

    ​ 对外公开的入口:一般情况下访问对象的某个属性,就两种情况,读取(get)和修改(set);所以,对外访问入口应该有两个,get方法和set方法.

    • 对需要封装的对象进行封装,使用private修饰符进行私有化;
    • 使用get方法和set方法作为外公开入口,访问对象;

    继承

    什么是继承?

    ​ 继承是面向对象的三大特征之一,封装居首位,封装之后形成独立体,独立体之间存在继承关系.继承在现实生活中处处可见的,如:父与子的关系.

    继承时子类会继承父类的特征和行为,使子类对象具有父类的属性,子类继承父类的方法使子类拥有父类相同的方法.

    为什么要使用继承机制?

    ​ 在不同类中可能会有共同的特征和动作,把这些动作和行为写成一个类中,从而可以构成一个通用类,再扩展多个特定类中,这些特定类继承通用类的方法.

    继承使Java中实现重用的重要手段,避免重复,易于维护.

    public class animal {
        private String name;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        void move(){
            System.out.println(name+"移动");
        }
    }
    
    public class fish extends animal {
        private String color;//颜色
        public String getColor() {
            return color;
        }
        public void setColor(String color) {
            this.color = color;
        }
        public static void main(String[] args) {
            //鱼与动物类的继承关系
            fish fish = new fish();
            fish.setName("鲤鱼");
            fish.setColor("红色");
            fish.move();
        }
    }
    

    ​ 继承的作用中除了可以让代码复用外,还有非常重要的两个作用,这是在继承的基础之上衍生出的,方法的覆盖多态机制.

    继承的相关性(特性):

    • B类继承A类,则称A类为超类(superclass),父类,基类;B类则称为子类(subclass),派生类,扩展类.
    • Java只支持单继承,Java不允许多继承;c++支持多继承.
    • Java不支持多继承,但可以产生间接继承的后果.
    • Java规定,子类继承父类,除构造方法和被private修饰的数据不能继承外,剩下都可以继承.
    • Java中的类没有显示的任何继承类,则默认继承Object类,Object类是Java语言提供的根类,也就是说,一个对象与生俱来的就有Object类型中的所有的特征.

    继承也是有些缺点,例如,父类与子类的切合度非常高,父类的改变会影响子类.

    覆盖

    什么是方法覆盖?

    在介绍覆盖之前先回顾一下重载;重载是在同一个类当中,如果功能相似,尽可能将方法名定义相同,这样代码会美观的.

    重载的条件:只要在同一个类当中,方法名相同,参数列表不同(类型,个数,顺序),即构成方法重载.

    覆盖:子类重写父类的方法.

    如何实现方法覆盖呢?

    只有当从父类继承过来的方法无法满足当前子类业务需求的时候,需要把父类中继承过来的方法进行覆盖.或是,父类中继承的方法已经不够用了,子类有必要将方法重写.所以,方法覆盖又称方法重写.

    方法覆盖的条件和注意实现?

    1. 具备的条件:
      • 方法覆盖发生在具有继承关系的父子类之间;
      • 覆盖之后与原方法具有相同的返回值类型,相同的方法名,相同的形式和参数 列表;
    2. 注意事项:
      • 由于覆盖之后的方法与原方法一样,建议是复制粘贴,不建议手写;
      • 私有方法不能被继承,所以不能被覆盖;
      • 构造方法不能被继承,所以不能覆盖;
      • 覆盖之后的方法不能比原方法拥有更低的访问权限,可以更高;
      • 覆盖之后不能比原方法抛出更多的异常,只能一样或更少.
      • 静态方法(被 static 修饰的成员方法)不存在覆盖.

    多态

    什么是多态?

    ​ 多态(Polymorphism)属于面向对象三大特征之一,它的前提是封装形成独立体,独立体之间存在继承关系,从而产生多态机制.

    ​ 多态是同一个行为具有多个不同表现形式或形态的能力.多态就是"同一个行为"发生在"不同对象上"会产生不同的效果.

    在Java中有两种语法,一种是向上转型,一种是向下转型.

    • 向上转型---->子类类型转换为父类类型,简称:自动类型转换
    • 向下转型---->父类类型转换为子类类型,简称:强制类型转换.

    image-20221008214349271

    不管是向下转型还是向上转型,他们之间必须要有继承关系,没有继承关系,转型的时候编译器报错.

    public class Test02 {
        public static void main(String[] args) {
            Animal a1 = new Cat()
            a1.move();
            Animal a2 = new Bird();
            a2.move();
        } 
    }
    

    Animal a1 = new Cat()就是一个向上转型的,自动转型的,本质上Cat就是一个Animal.

    public class Test04 {
        public static void main(String[] args) {
            //向上转型
            Animal a = new Cat();
            //向下转型:为了调用子类对象特有的方法
            Cat c = (Cat)a;
            c.catchMouse();
        } 
    }
    

    Animal a = new Cat()与 Cat c = (Cat)a;这就属于向下转型,强制类转型.

    以上可知:

    只有在访问子类中特有的数据时候,需要先进行向下转型.

    向下转型存在一定风险,如下:

    public class Test05 {
        public static void main(String[] args) {
            Animal a = new Bird();
            Cat c = (Cat)a;
        } 
    }
    

    ​ 本来new的对象是一只小鸟,向上转型表达的是它是动物,但向下转型也应该是一只小鸟,但变成了一只猫了.而这个语法上没有错误,编译器通过了,但会报异常,ClassCastException,翻译为类型转换异常.

    这个原因是小鸟与猫之间没有继承关系的,转型会出现错误.

    instanceof运算符

    instanceof运算符的运算结果是布尔类型,可能是true,也可能是false,本质上是一种假设的判断.可以使用instanceof进行判断.

    这样写就不会发生异常了:

    public class Test05 {
        public static void main(String[] args) {
            Animal a = new Bird();
            if(a instanceof Cat){
                Cat c = (Cat)a;
                c.catchMouse();
            } 
        } 
    }
    

    多态存在的三个必要条件分别是:

    1. 继承
    2. 方法覆盖
    3. 父类引用指向子类对象

    多态显然离不开覆盖机制,多态是因为在编译阶段绑定父类当中的方法,程序运行阶段自动调用子类对象上的方法.如果子类对象上的方法没有进行重写,创建多态就没有意义了.只有方法重写之后,运行时调用子类对象上的方法产生不同的效果,多态形成了.

    方法覆盖与多态机制是捆绑的形式.

    多态在开发中的作用

    在软件开发过程中,有这样的一个开发原则:开闭原则。开闭原则(OCP)是面向对象设计中“可复用设计”的基石,是面向对象设计中最重要的原则之一。它的原文是这样: “Software entities should be open for extension,but closed for modification”。

    开闭原则中“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;开闭原则中“闭”,是指对于原有代码的修改是封闭的,即修改原有的代码对外部的使用是透明的。

    如下例子:

    
    //宠物狗
    public class Dog {
        String name;
        
        public Dog(String name){
            this.name = name;
        }    
        //吃的行为
        public void eat(){
            System.out.println(this.name + "在啃肉骨头!");
        }
    }
    
    //主人
    public class Master {
        //喂养行为
        public void feed(Dog dog){
            //主人喂养宠物,宠物就吃
            System.out.println("主人开始喂食儿");
            dog.eat();
            System.out.println("主人喂食儿完毕");
        } 
    }
    public class Test {
        public static void main(String[] args) {
            //创建狗对象
            Dog dog = new Dog("二哈");
            //创建主人对象
            Master master = new Master();
            //喂养
            master.feed(dog);
        } 
    }
    

    如果在此基础之上,要增加一个Cat类,来表示宠物猫呢?

    //宠物猫
    public class Cat {
        String name;
        public Cat(String name){
            this.name = name;
        }
        //吃的行为
        public void eat(){
            System.out.println(this.name + "在吃鱼!");
        } 
    }
    public class Master {
        //喂养行为
        public void feed(Dog dog){
            //主人喂养宠物,宠物就吃
            System.out.println("主人开始喂食儿");
            dog.eat();
            System.out.println("主人喂食儿完毕");
        }
        //喂养行为
        public void feed(Cat cat){
            //主人喂养宠物,宠物就吃
            System.out.println("主人开始喂食儿");
            cat.eat();
            System.out.println("主人喂食儿完毕");
        } 
    }
    

    而这样做的话,会违背了OCP原则;而多态就可以解决:

    //宠物类
    public class Pet {
        String name;
        //吃的行为
        public void eat(){
        } 
    }
    public class Cat extends Pet{
        
        public Cat(String name){
            this.name = name;
        }
        //吃的行为
        public void eat(){
            System.out.println(this.name + "在吃鱼!");
        } 
    }
    //宠物狗
    public class Dog extends Pet{
        
        public Dog(String name){
            this.name = name;
        }
        
        //吃的行为
        public void eat(){
            System.out.println(this.name + "在啃肉骨头!");
        } 
    }
    //主人
    public class Master {
        //喂养行为
        public void feed(Pet pet){
            //主人喂养宠物,宠物就吃
            System.out.println("主人开始喂食儿");
            pet.eat();
            System.out.println("主人喂食儿完毕");
        }
    }
    public class Test {
        public static void main(String[] args) {
            //创建狗对象
            Dog dog = new Dog("二哈");
            //创建主人对象
            Master master = new Master();
            //喂养
            master.feed(dog);
            //创建猫对象
            Cat cat = new Cat("汤姆");
            //喂养
            master.feed(cat);
        } 
    }
    

    显然Master类和具体的Dog,Cat类解耦合了,依赖性弱了,这就是通常说的面向对象编程,尽量不要面向具体编程面向抽象编程会让你的代码耦合度降低,扩展能力增强,从而符合 OCP 的开发原则。

    总结:

    通过以上内容的学习,我们可以看到多态在开发中联合方法覆盖一起使用,可以降低程序 的耦合度,提高程序的扩展力。在开发中尽可能面向抽象编程,不要面向具体编程。

    所谓多态就是同一个行为作用到不同的对象上,最终的表现结果是不同的,主要的要求就是对象是可以进行灵活切换的,灵活切换的前提就是解耦合,解耦合依赖多态机制。

  • 相关阅读:
    全网最全谷粒商城记录_07、环境-虚拟机网络设置——2、固定IP,Windows和虚拟机ping通方式【简洁】
    【牛客网-前端笔试题】——Javascript专项练习
    【音视频】C语言基础快速复习
    Linux ipc通信(消息对列)
    SpringBoot整合Mongodb
    JSX 样式处理
    蓝桥杯python组--基础训练---求输入的第n个,斐波那契数
    ElasticSearch 8.x 安装及集群搭建
    Spring整合MyBatis
    C/C++ Capstone 引擎源码编译
  • 原文地址:https://www.cnblogs.com/1330316711huzhenyu/p/16773652.html