java 学习笔记(8)Polymorphism & abstract class

                      polymorphism & abstract class

目录:

1.Late Binding 

2. Polymorphism  多态

3. final modifier

4. 详解动态绑定和静态绑定

   4.2 动态绑定:

   4.3 重载和重写的判断。

   4.4 动态绑定是如何实现的?

5. abstract class

   5.1 抽象方法

    5.2 抽象类

6. 继承

7.抽象类和接口的区别

 

1Late Binding 

晚绑定
对于后期绑定,方法的定义实际上在运行时才绑定到方法的调用,而不是在特定调用发生时。

  --------------------------------------------------------------------------------------------------------------------

2. Polymorphism  多态

多态性是指将多个含义与一个方法名相关联的能力。通过后期结合机制。因此,多态性和后期绑定实际上是同一主题

Polymorphism  refers to the ability to associate many meanings to one method name by means of the late binding mechanism. Thus, polymorphism and late binding are really the same topic

  --------------------------------------------------------------------------------------------------------------------

3. final modifier

如果一个函数方法,被这个关键字所修饰,那么这个方法不可以被重写。

如果一个类被这个方法所修饰,那么这个类不可以被继承。

The final Modifier
If you add the modifier final to the definition of a method, it indicates that the method may not be redefined in a derived class. If you add the modifier final to the definition of a class, it indicates that the class may not be used as a base class to derive other classes.

具体写法:

                   

                   

  --------------------------------------------------------------------------------------------------------------------

4. 详解动态绑定和静态绑定

4.1 介绍

在Java中,当你调用一个方法时,可能会在编译时期(compile time)解析(resolve),也可能实在运行时期(runtime)解析,这全取决于到底是一个静态方法(static method)还是一个虚方法(virtual method)

如果是在编译时期解析,那么就称之为静态绑定(static binding),如果方法的调用是在运行时期解析,那就是动态绑定(dynamic binding)或者延迟绑定(late binding)。Java是一门面向对象的编程语言,优势就在于支持多态(Polymorphism)。多态使得父类型的引用变量可以引用子类型的对象。

 

4.2 动态绑定:

如果调用子类型对象的一个虚方法(非private,final or static),编译器将无法找到真正需要调用的方法,因为它可能是定义在父类型中的方法,也可能是在子类型中被重写(override)的方法,这种情形,只能在运行时进行解析,因为只有在运行时期,才能明确具体的对象到底是什么。这也是我们俗称的运行时或动态绑定(runtime or dynamic binding)。

 

另一方面,private static和final方法将在编译时解析,因为编译器知道它们不能被重写,所有可能的方法都被定义在了一个类中,这些方法只能通过此类的引用变量进行调用。这叫做静态绑定或编译时绑定(static or compile time binding)。所有的private,static和final方法都通过静态绑定进行解析。这两个概念的关系,与“方法重载”(overloading,静态绑定)和“方法重写”(overriding,动态绑定)类似动态绑定只有在重写可能存在时才会用到,而重载的方法在编译时期即可确定(这是因为它们总是定义在同一个类里面)

 

总而言之,其区别如下:

①静态绑定在编译时期,动态绑定在运行时期。

②静态绑定只用到类型信息,方法的解析根据引用变量的类型决定,而动态绑定则根据实际引用的的对象决定

③在java中,private static 和 final 方法都是静态绑定,只有虚方法才是动态绑定

④多态是通过动态绑定实现的。

 

4.3 重载和重写的判断。

方法重载:

     1.方法名必须相同。

      2.形式参数个数不同。或者参数类型不同。满足其一即可。

方法重写:

      1. 访问修饰权限一定要大于被重写的方法

      2. 如果该方法被private、static、final修饰,那么给方法不可以被重写。

      3.返回值类型必须相同。

      4.参数列表必须与被重写的方法完全相同。

NB:重载的多个方法都有效。根据参数值的不同,选择不同的函数进行调用。但是重写的方法。在动态绑定之后只有一个有效。

 

4.4 动态绑定是如何实现的?

一个对象的多态方法的地址将被存储在该对象的方法表(method table)里面。在运行时期,调用多态方法的时候,JVM会在此表中搜索方法的名字,从而获取方法的地址。方法表里包含方法的名字和对应的地址(注意,这个地址是动态绑定的)。这个方法表对所有属于这个类的对象而言,都是一样的,所以它会存储在Class对象中(这里对象类型以Integer为例)(在其他的语言中,这样的表又叫做vtables,虚函数表)。需要说明的是,java语言中,如果没有添加任何关键字,则方法默认就是虚方法,任何子类都可以重写它。

方法表并不属于语言的一部分,但是会有很多种不同的实现(不同的JVM提供商可以自由选择实现的细节,只要结果保证一致就ok)。其中,Sun公司的JVM实现,则选择了将方法表入口放在对象的常量池(constant pool)里,你可以使用命令java -verbose foo来查看。(所有的属于同一个类型的对象都将拥有同一个方法表,JVM也可以将其放在别的地方)

下面,将通过一个图表实例来展示,对于某些类(这里以Integer为例)而言,是如何一步步构建方法表的。初始时,表都是空的。运行时,方法表将从最远的祖先类开始,逐步加入这些多态方法。通常,这个最远的祖先是Object类。

                

接下来,这个表中将加入第二远的祖先类的多态方法,如果已经存在,就修改其地址值。此例中,第二远的类是Number类。如果你查看了javadoc,你就会发现Number类并没有重写任何方法,只是额外多了六个方法,因而,将这六个多的方法加入表中。此时,toString项并没有被改变,方法表如下

                       

这个过程一直持续下去,直到所有的父类的多态方法都被合并进这个表里。最后,方法表会被Integer类的多态方法所更新,此时,toString方法会被重写:

                          

方法表中的方法名这一项,只包含最初始的类名,所谓重写,只是修改了地址栏下的值,不会改变方法名的值。所以,如果用javap指令查看多态方法名,只会显示Object.toString,而不是toString或者Integer.toString。

需要说明的是,此处,假如有Number num = new Integer(10),即便方法表里面有了Integer.parseInt方法,我们仍不能通过num来调用parseInt。也就是说,num变量引用了Integer对象,并且与上述方法表关联,但在编译时期时,编译器会根据语法规则,实行访问控制,num不能调用和访问独属于Integer的类方法,只能访问自己拥有访问权限的类方法,而这些方法中的某些方法,在运行过程中,名字未变,映射地址却发生了变化,因而调用的是所引用的子类Integer的实现。这点要弄清楚!

参考:https://www.cnblogs.com/ShaneZhang/p/4972550.html

  --------------------------------------------------------------------------------------------------------------------

5. abstract class

比如,如果我想在employee的class函数中,做如下的定义:

             

但是该方法是存在问题的。主要是因为getPay()函数。比如,employee类的两个子类。按小时计费和按月计费,是两个不同的子类。他们的getPay()函数是不同的。因此在父类中并没有办法。对getPay()函数做确切的定义。因为这两个函数需要在子类中重写。但是如果我还想设置samePay()函数怎么办呢?这时我们需要一个新的关键字。抽象。用这个关键字定义的方法被称之为抽象方法。用这个关键字定义的类被称之为抽象类。

 

5.1 下面我们来看一下抽象方法的作用。

在父类中。定义一个如下的方法。这个方法只有方法的heading,但是却并没有方法的body。在该父类被继承后,子类可以具体的定义该方法。这在编程当中较为常用。

                          

If we add this abstract method  getPay to the class  Employee , then we are free to add the method  samePay to the class  Employee 

 

5.2 抽象类。

5.2.1 介绍

使用abstract修饰的类,叫abstract class

同时我们规定包含抽象方法的那必须是抽象类。该函数没有具体的含义,该类不可以生成具体的对象。

 

5.2.2 对抽象类的三个规定。

1.抽象类不一定含有抽象的函数,对于一个抽象类而言,它可以还有普通函数也可以含有抽象函数。但是还有抽象函数的类必须是抽象类。

2. Java, an abstract method cannot be private. Normally an abstract method is public but protected, and package (default) ccess is allowed

3. 如果一个子类继承了这个抽象的父类,那么这个此类就必须实现这个抽象类中的所有抽象方法。如果子类,并没有全部实现服类的抽象方法。那我这个子类也必须定义为抽象。

 

5.2.3 使用情况。

抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为你不能用它来做任何事情。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

参考:https://zhuanlan.zhihu.com/p/34477202

  --------------------------------------------------------------------------------------------------------------------

6. 继承

接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象。在Java中,定一个接口的形式如下

[public] interface InterfaceName {
}

  接口中可以含有 变量和方法。但是要注意,接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误),而方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。

  要让一个类遵循某组特地的接口需要使用implements关键字,具体格式如下:

class ClassName implements Interface1,Interface2,[....]{
}

  可以看出,允许一个类遵循多个特定的接口。如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有方法。对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法。

  --------------------------------------------------------------------------------------------------------------------

7.抽象类和接口的区别

Java提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于:

  • 接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
  • 类可以实现很多个接口,但是只能继承一个抽象类
  • 类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
  • 抽象类可以在不提供接口方法实现的情况下实现接口。
  • Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。
  • Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者是public。
  • 接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值