Distinct features of OOP

Encapsualation and information hiding(封装与信息隐藏)

信息隐藏是目的,封装是达到这个目的的技术。

封装可以被定义为对对象的内部数据表现形式和实现细节进行隐藏。要想访问封装过的对象中的数据,只有使用已定义的操作这一种办法。通过封装可以强制实施信息隐藏。许多面向对象语言都使用关键字来说明某些方法和属性应被隐藏。但在Java中没有这样的关键字,我们将使用闭包的概念来创建只允许从对象内部访问的方法和属性。这比使用关键字的办法更复杂。

Intreface和Class都用来定义和实现ADT,接口之间可以继承与扩展,同时一个类也可以实现多个接口,从而具备多个接口中的方法,相对应的,一个接口也可以有多个实现类。

Interface主要用于确定ADT规约,而实现ADT则要交予类来完成。

Inheritance and overriding(继承与重写)

继承:将两个或多个类中的共有方法抽取出来封装到另外一个类中,通过 extends 关键字进行连接,这些类与这个新建的类就形成了继承关系。

1. 子类只能使用父类的非私有的成员
2. Java 支持单继承不支持多继承,支持多层继承
3. 子父类出现重名变量或方法,会优先访问子类中的变量和方法,子类中没有才会往父类中找      4. this 和 super
            this :
                类中对属性进行使用,指向当前类的成员变量
                类中对 new 出来的对象使用,指向对象中成员变量
            super:父类对象的引用,指向父类的存储空间标识                                                            5. 如果接口有默认 save 方法,实现类有实现 save 方法,访问时会优先访问实现类中的 save 

重写:继承体系中,子父类出现同样的方法声明

父类私有方法不能被重写,子类只能通过非静态方法重写父类非静态方法,静态方法不能被重写,出现的同名方法只是对父类的这个方法进行了隐藏,不是方法重写,方法重写时,子类的重写方法的访问权限必须大于父类,重写的特点:返回值类型、方法名、参数列表 这三者完全一致

1. 覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;

2. 覆盖的方法的返回值必须和被覆盖的方法的返回一致;

3. 覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;

4. 被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖

Poiymorphism,subtyping and overloading(多态,子类型,重载)

1.多态(polymorphism):

多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。这就是多态性。多态性增强了软件的灵活性和扩展性。

简单来说:发送消息给某个对象,让该对象自行决定响应何种行为。 通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。

多态须具备:

a. 基类 和各个子类

b. 基类 引用, 指向实例化的子类对象.

《计算机图形学》中的绘制逻辑就是多态,实现点线面元素的管理,调用父类的draw方式,最后点线面各子元素去绘制。

3.重载(overload)

a、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float), 但是不能为fun(int, int));

b、不能通过访问权限、返回类型、抛出的异常进行重载;

c、方法的异常类型和数目不会对重载造成影响;

d、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。
 

Static and Dynamic dispatch(静态与动态分派)

Class 文件的编译过程中不包含传统编译中的连接步骤,一切方法调用在 Class 文件里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址。这个特性给 Java 带来了更强大的动态扩展能力,使得可以在类运行期间才能确定某些目标方法的直接引用,称为动态连接,也有一部分方法的符号引用在类加载阶段或第一次使用时转化为直接引用,这种转化称为静态解析

静态解析成立的前提是:方法在程序真正执行前就有一个可确定的调用版本,并且这个方法的调用版本在运行期是不可改变的。换句话说,调用目标在编译器进行编译时就必须确定下来,这类方法的调用称为解析。

在 Java 语言中,符合“编译期可知,运行期不可变”这个要求的方法主要有静态方法私有方法两大类,前者与类型直接关联,后者在外部不可被访问,这两种方法都不可能通过继承或别的方式重写出其他的版本,因此它们都适合在类加载阶段进行解析。

Java 虚拟机里共提供了五条方法调用字节指令,分别是:

  • invokestatic:调用静态方法。
  • invokespecial:调用实例构造器方法、私有方法和父类方法。
  • invokevirtual:调用所有的虚方法。
  • invokeinterface:调用接口方法,会在运行时再确定一个实现此接口的对象。
  • invokedynamic:先在运行时动态解析出调用点限定符所引用的方法,然后再执行该方法,在此之前的4条调用指令,分派逻辑是固化在Java虚拟机内部的,而invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的。

只要能被 invokestatic 和 invokespecial 指令调用的方法,都可以在解析阶段确定唯一的调用版本,符合这个条件的有静态方法、私有方法、实例构造器和父类方法四类,它们在类加载时就会把符号引用解析为该方法的直接引用。这些方法可以称为非虚方法(还包括 final 方法),与之相反,其他方法就称为虚方法(final 方法除外)。这里要特别说明下 final 方法,虽然调用 final 方法使用的是 invokevirtual 指令,但是由于它无法覆盖,没有其他版本,所以也无需对方发接收者进行多态选择。Java 语言规范中明确说明了 final 方法是一种非虚方法。

虚拟机栈中会存放当前方法调用的栈帧,在栈帧中,存储着局部变量表、操作栈、动态连接 、返回地址和其他附加信息。多态的实现过程,就是方法调用动态分派的过程,通过栈帧的信息去找到被调用方法的具体实现,然后使用这个具体实现的直接引用完成方法调用。

以 invokevirtual 指令为例,在执行时,大致可以分为以下几步:

  1. 找到操作数栈顶的第一个元素所指向的对象的实际类型,记作C
  2. 如果在类型C中找到与常量中的描述符和简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束;如果不通过,则返回java.lang.IllegalAccessError异常。
  3. 否则,按照继承关系从下往上依次对C的各个父类进行第2步的搜索和验证过程。
  4. 如果始终没有找到合适的方法,则抛出java.lang.AbstractMethodError异常。

可以看到,如果子类覆盖了父类的方法,则在多态调用中,动态绑定过程会首先确定实际类型是子类,从而先搜索到子类中的方法。这个过程便是方法覆盖的本质。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值