面向对象编程OOP(2)之继承、封装和多态

1、继承

1.1、概述

       说到继承,我们可以先理解一个词:抽象。抽象拆分理解就是抽出像的部分,就是把某一些事物的共同点抽取出来,从而归纳为某一类。比如:猫和狗抽象出来就是动物,数和草抽象出来就是植物等等。

       那么继承,就是把共同点抽象出来之后变成一个类,而其他具体的事物就通过继承的方式,也拥有这些共同点。同时也可以具备自己特有的属性和方法。比如:猫和狗抽象出来的一个类是动物Animal,动物的共同点比如是吃东西,可以跑步。猫继承自动物,那么它也就拥有吃东西和跑步功能,同时猫还有自己的特性,比如爬树,叫声比较特别等等。

1.2、继承的作用

第一:继承的本质在于抽象。类是对对象的抽象,继承是对某一批类的抽象。

第二:为了提高代码的复用性。子类继承父类,可以拥有父类所有的方法和属性(除了父类的构造方法)

使用关键字extends实现继承,extends的意思是扩展。子类是父类的扩展。

【注】JAVA中类只有单继承没有多继承! 接口可以多继承!

1.3、override方法重写

在子类中可以根据需要对从基类中继承来的方法进行重写。

重写方法必须和被重写方法具有相同方法名称、参数列表和返回类型。

重写方法不能使用比被重写方法更严格的访问权限。(由于多态)

1.3.1 方法重写和方法重载的区别:

很多人问重写和重载什么区别他们两个完全是两回事。除了名字都带一个字之外。

方法重载指的是:同一个类中,一个方法名对应了多个方法(形参列表不同)

方法的重写指的是:子类重写了父类的方法!

 

1.4、Object类

Object类是所有Java类的根基类,如果在类的声明中未使用extends关键字指明其基类,则默认基类为Object

1.4.1 toString方法

Object类中定义有public String toString()方法,其返回值是 String 类型,描述当前对象的有关信息。

在进行String与其它类型数据的连接操作时(如:System.out.println(“info”+person)),将自动调用该对象类的 toString()方法

Object类中toString方法的源代码是:

public String toString() {
   return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

默认是打印:类名+哈希码(根据对象地址计算得出 )

可以根据需要在用户自定义类型中重写toString()方法。比如String类就重写了toString方法,源代码如下:

public String toString() {
     return this;
}

1.4.2 equals方法

Object类中定义有:public boolean equals(Object obj)方法,提供定义对象是否“相等的逻辑。

Object  equals 方法 定义为:x.equals ( y )  x  y是同一个对象的应用时返回 true 否则返回 false

查看Object类中的equals方法源代码可以看出:

public boolean equals(Object obj) {
    return (this == obj);
}

J2SDK提供的一些类,如StringDate等,重写了Objectequals方法,调用这些类的equals方法, x.equals (y) ,xy所引用的对象是同一类对象且属性内容相等时(并不一定是相同对象),返回 true 否则返回 false

String类的equals方法显然是比较数组中的char值是否相等,源代码如下:

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

Date类的equals方法显然是比较Date对象对应的long值是否相等,源代码如下:

    public boolean equals(Object obj) {
        return obj instanceof Date && getTime() == ((Date) obj).getTime();
    }

1.5、super关键字

super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。

除了Object类之外其他所有类的构造方法第一句总是super(…);这也说明了为啥创建子类对象的时候会先初始化父类。

任何类的构造方法中,若是构造方法的第一行代码没有显式的调用super(...);那么Java默认都会调用super(); 所以你这里的super(); 加不加都无所谓。

 

1.6 final的用法

修饰变量:被final修饰的变量不可改变。即初始化一次后,就不能再次被赋值!即,变为常量!

修饰方法:被final修饰的方法不可以被子类重写!

修饰类:被final修饰的类不能被继承!

 

2、封装(encapsulation)

2.1 为何需要封装

我要看电视,只需要按一下开关和换台就可以了。有必要了解电视机内部的结构吗?有必要碰碰显像管吗?我要开车,….

制造厂家为了方便我们使用电视,方便我们开车,把复杂的内部细节全部封装起来,只给我们暴露简单的接口,比如:电源开关、比如:油门。具体怎么内部实现的,我们不需要操心。

需要让用户知道的暴露出来,不需要让用户了解的全部隐藏起来。这就是封装。

白话:该露的露,该藏的藏。

专业:我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。

2.2 封装的意义

便于调用者调用。

良好的封装,便于修改内部代码,提高可维护性。

良好的封装,可进行数据完整性检测,保证数据的有效性。

2.3 使用访问控制符,实现封装

修饰符

同一个类

同一个包中

子类

所有类

private

*

 

 

 

default(即不加修饰符的时候)

*

*

 

 

protected

*

*

*

 

public

*

*

*

*

2.4 如何封装

1.    属性一般使用private.(除非本属性确定会让子类继承并且使用),提供相应的get/set方法来访问相关属性。这些方法通常是public,从而提供对属性的读取操作。  (注意:boolean变量的get方法是用:is开头!)

2.    一些只用于本类的辅助性方法可以用private,希望其他类调用的方法用public。

 

 

3、多态(polymorphism)

       多态性是OOP中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终状态只有在执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和扩展性。

       多态可以让我们不用关心某个对象到底是什么具体类型,就可以使用该对象的某些方法,从而实现更加灵活的编程,提高系统的可扩展性。

       多态性是指允许不同类的对象对同一消息作出不同的响应。

3.1 多态中,引用变量的两种类型

    1、编译时类型(模糊一点,一般是一个父类):由声明时的类型决定。

    2、运行时类型(运行时,具体是哪个子类就是哪个子类):由实际对应的对象类型决定。通过动态绑定调用该对象的方法。动态绑定会使我们的程序编写更加灵活,但是会减慢程序运行速度。这也是JAVAC++/C慢的主要原因之一。

    多态:如果编译时类型和运行时类型不一致,就会造成多态。

3.2 方法绑定(method  binding)

执行调用方法时,系统根据相关信息,能够执行内存地址中代表该方法的代码。分为静态绑定和动态绑定。

3.2.1 静态绑定:

       在编译期完成,可以提高代码执行速度。

3.2.2 动态绑定:

       通过对象调用的方法,采用动态绑定机制。 这虽然让我们编程灵活,但是降低了代码的执行速度。这也是JAVAC/C++速度慢的主要因素之一。 JAVA中除了final类、final方、static方法,所有方法都是JVM在运行期才进行动态绑定的。

注:多态指的是方法的多态,属性是没有多态的。

3.3 多态的使用要点

   1.    多态是方法的多态,属性没有多态性。

    2.    编写程序时,如果想调用运行时类型的方法,只能进行类型转换。不然通不过编译器的检查。但是如果两个没有关联的类进行强制转换,会报:ClassCastException 比如:本来是狗,我把它转成猫。就会报这个异常。

    3.    多态的存在要有3个必要条件:要有继承,要有方法重写,父类引用指向子类对象

3.4 对象的转型(casting)

为什么需要强制转换类型?

    因为引用变量只能调用它编译类型的方法,不能调用它运行类型的方法。这时,我们就需要进行类型的强制转换!

³    一个父类的引用类型变量可以“指向”其子类的对象。

³    一个父类的引用不可以访问其子类对象新增加的成员(属性和方法)。

³    可以使用 引用 变量 instanceof 类名 来判断该引用型变量所“指向”的对象是否属于该类或该类的子类。

³    子类的对象可以当作基类的对象来使用称作向上转型(upcasting),反之称为向下转型(downcasting)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值