深度刨析2--类和对象

本文介绍了面向对象编程的基本概念,包括封装、继承和多态。封装通过private关键字隐藏实现细节,提供公共接口。继承允许代码复用,减少重复,同时介绍了super关键字的作用。多态则是同一方法根据不同对象表现出不同行为,依赖于动态绑定。文章还讨论了构造方法中避免调用重写方法的原因,以及多态的优缺点。
摘要由CSDN通过智能技术生成

目录


面向对象篇

  1. 面向对象
  2. 封装
  3. 继承
  4. 多态

1.面向对象

1.1.什么是面向对象?

       面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情;人们常说的OOP思想就是面向对象思想。 用面向对象的思想来涉及程序,更符合人 们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。

1.2.面向对象与面向过程

假如你要买手机:

 1.面向过程的买手机方式注重的是买手机的过程,少了一个环节可能都不行

按照该种方式来写代码,将来扩展或者维护起来会比较麻烦

2.而面向对象的买手机方式:就不关注买手机的过程,具体怎么买,怎么激活,这些都交给秘书去     处理,你只要通过对象之间的交互完成即可--->手机,秘书,使用

注意:面向过程和面相对象并不是一门语言,而是解决问题的方法,没有那个好坏之分,都有其专门的应用场景。


2.封装

2.1.什么是封装?

概念:在实现上采用private修饰成员变量和成员方法,这样在类外就不能直接访问了;达到了
对外隐藏实现的细节,只提供公开的方法,来操作你的这些封装好的成员变量和成员方法

简述:公开的方法 和 私有的属性之间结合

看代码:

class Cat {
    //private修饰成员变量
    private String name;
    private int age;
    private String color;

    //提供公开的对应的Getter和Setter方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
}

public class TestDemo {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.setName("喵喵");//设置值
        String name = cat.getName();//获取值
        System.out.println(name);
    }
}

也可以用构造方法来达到这种效果。

封装的另一好处:降低代码的耦合度

在公司里,每个人负责自己的代码部分,如果这样写代码的饿话,某一天,你的同时心情很差,就把name改成myname了,那你的代码部分相应的地方也需要做修改,耦合度就很高,但是封装之后,改成员名就丝毫不影响你的代码,你只需要通过get,set来设置值,获取值即可。


3.继承

3.1.为什么需要继承?什么是继承?

Java 中使用类对现实世界中实体来进行描述,类经过实例化之后的产物对象,则可以用来表示现实中的实体,但是现实世界错综复杂,事物之间可能会存在一些关联,那在设计程序是就需要考虑。
假如我们要定义一个猫类和一个狗类:
那么它们都有名字,年龄,体重...它们都要吃饭,睡觉,打豆豆...
如果分开写代码的话,那我们写出来的代码,将会有很多重复的地方。

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

再谈谈什么是继承:

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

 上图所示:继承之后,你会发现,共同的成员变量只需要在父类中写好即可,子类中只需要关心新增的成员变量。


3.2.继承的语法

Java 中如果要表示类之间的继承关系,需要借助 extends 关键字,看代码:
注意:
1. 子类会将父类中的成员变量或者成员方法继承到子类中了
2. 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继        承了

 3.3.重载

     1.什么是重载:重载针对成员方法,方法重载的三个条件:

      1.方法名相同;   2.方法的参数列表不相同(参数个数,参数类型,不同类型参数的顺序不同);   3.方法的返回值不做要求

重载的好处,比如:当我们要使用同一个自定义方法时, 我们要实现的逻辑相同,但是参数不同,或者参数类型和顺序不同的时候,使用方法的重载避免了再重新定义一个函数名,这样就很方便,而不会说像这样:两个参数的add方法,我给它定义成add1(), 而三个参数的方法,我给它定义成add2().........


3.4.父类成员的访问

1. 子类和父类不存在同名成员变量
     直接访问就好了,继承过来的,可以直接拿来用。
2. 子类和父类成员变量同名

在子类方法中 或者 通过子类对象访问成员时
  • 如果访问的成员变量子类中有,优先访问自己的成员变量。
  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的(不管类型是否有差异),即:子类将父类同名成员隐藏了。

让我们来看一下运行结果证明以下以上三点说法:

 从而得出结论:成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找


3.5. 父类成员方法的访问

1. 成员方法名字不同

父类有,就调用父类的,父类没有,就调用子类的,都没有,编译错误。都是可以直接访问的

2. 成员方法名字相同(这部分举例只涉及重载,后面讲重写的情况)

【说明】 

  • 通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。
  • 通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错;如果父类和子类同名方法的原型一致(重写-面讲),则只能访问到子类的,父类的无法通过派生类对象直接访问到。
   问题:如果子类中存在与父类中相同的成员时,如果不创建父类对象,那如何在子类中访问父        类相同名称的成员呢?这就涉及到super关键字。

 3.6.super

由于设计不好,或者因场景需要,子类和父类中可能会存在相同名称的成员,如果要在子类方法中访问父类同名成员时,该如何操作?直接访问是无法做到的,Java提供了super关键字,该关键字主要作用:在子类方法中访问父类的成员

在子类方法中,如果想要明确访问父类中成员时,借助super关键字即可。

注意事项

1. 只能在非静态方法中使用
2. 在子类方法中,访问父类的成员变量和方法

3.7.super和this的区别

1.相同点:

        a.都是Java中的关键字

        b.只能在类的非静态方法中使用,用来访问非静态成员方法和字段

        c.在构造方法中调用时,必须是 构造方法中的第一条语句,并且不能同时存在

2.不同点

        a.this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父               类继承下来部分成员的引用

        b.在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方               法和属性

        c.this是非静态成员方法的一个隐藏参数,super不是隐藏参数

         d.成员方法中直接访问本类成员时,编译之后会将this还原,即本类非静态成员都是通过this             来访问的;在子类中如果通过super访问父类成员,编译之后在字节码super实际是不存在的

        e.在构造方法中:this(...)用于调用本类构造方法,super(...)用于调用父类构造方法,两种调用             不能同时在构造方法中存在

        f.继承里面构造方法中一定会存在super(...)的调用,用户没有写,编译器也会增加,但是this(...)            用户不写则没有

3.7.final关键字

final 关键可以用来修饰变量、成员方法以及类
1.修饰字段,表示常量(不能被修改)

2.修饰类,表示该类不能被继承(不能派生出子类),也叫密封类;

 3.修饰方法,该方法就不能被重写


4.多态

多态:简而言之,就是一种事物,多种形态

4.1.多态实现条件

1.必须在继承体系下

2.子类必须要对父类中的方法进行重写

3.通过父类的引用调用重写的方法

多态的体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法

多态的思想:同一个方法,因为调用这个方法的引用,引用的对象不同,所执行的行为也不一样


4.2.方法的重写

【重写规则】:

1.方法名称相同;2.方法的返回值相同;3.方法的参数列表相同;

4.非静态方法,非private修饰的方法,非final方法;

5.子类的访问修饰限定符的权限要大于等于父类的;

6.JDK以后,被重写的方法返回值类型可以不同,但是必须是具体父子关系的;

【重写和重载的区别】

区别点重载重写(override)
参数列表必须修改一定不能修改
返回类型可以修改一定不能修改
访问限定符可以修改一定不能做严格的限制(可以降低限制)
即:方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

重写的设计原则 

对于已经投入使用的类,尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容,并且添加或者改动新的内容。
例如:若干年前的手机,只能打电话,发短信,来电显示只能显示号码,而今天的手机在来电显示的时候,不仅仅可以显示号码,还可以显示头像,地区等。在这个过程当中,我们不应该在原来老的类上进行修改,因为原来的 类,可能还在有用户使用 ,正确做法是: 新建一个新手机的类,对来电显示这个方法重写就好了,这样就达到了我 们当今的需求了

4.3.向上转型

什么是向上转型? -->  父类的引用引用了子类的对象

向上转型的三种方式:1.直接赋值 (上图就是直接赋值) 2.方法的参数  3.方法的返回值

2.方法的参数:

3.方法的返回值 


 4.4.动态绑定

什么是动态绑定:通过父类的引用,调用重写的方法,此时会发生动态绑定

动态绑定的三个条件:

1.在继承体系下;2.子类必须要对父类中方法进行重写;3.通过父类的引用调用重写的方法
   

 【分析】

图中代码 animal.eat();为什么是调用子类的eat方法,实际上编译的时候,这里还是调用animal自己的eat方法,但是在运行的时候,就变了调用子类的eat方法了,所以动态绑定又叫运行时绑定

补充:既然有动态绑定,那就有静态绑定(编译期绑定),例如:重载就是静态绑定。

 4.5.向下转型(了解即可)

向下转型:子类的引用引用父类(不安全)

如何解决不安全问题?利用关键字:instanceof

4.6.多态的优缺点

【使用多态的好处】

1. 能够降低代码的 "圈复杂度", 避免使用大量的 if - else

什么叫 " 圈复杂度 " ?
圈复杂度是一种描述一段代码复杂程度的方式 . 一段代码如果平铺直叙 , 那么就比较简单容易理解 . 而如果有很多的条件分支或者循环语句, 就认为理解起来更复杂 .
因此我们可以简单粗暴的计算一段代码中条件语句和循环语句出现的个数 , 这个个数就称为 " 圈复杂度 ". 如果一个方法的圈复杂度太高, 就需要考虑重构 .
不同公司对于代码的圈复杂度的规范不一样 . 一般不会超过 10 .

例如我们现在需要打印的不是一个形状了, 而是多个形状. 如果不基于多态, 实现代码如下:

如果使用使用多态 , 则不必写这么多的 if - else 分支语句 , 代码更简单
2.可扩展能力更强
如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低 .

 

【降低成本】
对于类的调用者来说 (drawShapes 方法 ), 只要创建一个新类的实例就可以了 , 改动成本很低 .
而对于不用多态的情况 , 就要把 drawShapes 中的 if - else 进行一定的修改 , 改动成本更高 .
多态缺陷:代码的运行效率降低

4.7.避免在构造方法中调用重写的方法

 这里为什么是调用子类的func方法?

  • 构造 D 对象的同时, 会调用 B 的构造方法
  • B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func
  • 此时 D 对象自身还没有构造 , 此时 num 处在未初始化的状态 , 值为 0.
【结论】
        结论 : " 用尽量简单的方式使对象进入可工作状态 ", 尽量不要在构造器中调用方法 ( 如果这个方法被子类重写 , 就会触发动态绑定, 但是此时子类对象还没构造完成 ), 可能会出现一些隐藏的但是又极难发现的问题 .
本篇完!
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Master_hl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值