前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java核心技术 卷I 基础知识 学习笔记(4)

Java核心技术 卷I 基础知识 学习笔记(4)

作者头像
发布2019-02-25 15:39:41
5000
发布2019-02-25 15:39:41
举报
文章被收录于专栏:WD学习记录WD学习记录

参考:Java核心技术 卷I 基础知识

一个对象变量可以指示多种实际类型的现象被称为多态。在运行时能够自动地选择调用哪个方法的现象被称为动态绑定。

由一个公共超类派生出来的所有类集合被称为继承层次。在继承层次中,通过某个特定类到其祖先的路径被称为该类的继承链。

假设要调用x.f(args),隐式参数x声明为类C的一个对象。下面是调用过程的详细描述:

(1)编译器查看对象的声明类型和方法名。假设调用x.f(param),且隐式参数x声明为C类的对象。需要注意的是,有可能存在多个名字为f,但参数类型不一样的方法。例如:可能存在方法f(int)和方法f(String)。编译器将会一一列举所有C类中名为f的方法和其超类中访问属性为public且名为f的方法(超类的私有方法不可访问)。

至此,编译器以获得所有可能被调用的候选方法。

(2)接下来,编译器将查看调用方法时提供的参数类型。如果在所有的名为f的方法中存在一个与提供的参数类型完全匹配,就选择这个方法。这个过程被称为重载解析。例如:对于调用x.f("Hello")来说,编译器将会挑选f(String),而不是f(int)。由于允许类型转换,所以这个过程可能很复杂。如果编译器没有找到与参数类型匹配的方法,或者发现经过类型转换后有多个方法与之匹配,就会报告一个错误。

至此,编译器已经获得需要调用的方法名字和参数类型。

(3)如果是private、static、final方法或者构造器,那么编译器可以准确地知道应该调用哪个方法,将这种调用方式称为静态绑定。与此对应的是,调用的方法依赖于隐式参数的实际类型,并且在运行时实现动态绑定。

(4)当程序运行,并且采用动态绑定调用方法时,虚拟机已定调用与x所引用对象的实际类型最合适的那个类的方法。假设x的实际类型是D,它是C的子类。如果D类定义了方法f(String),就直接调用它,否则将在D类的超类中寻找f(String),以此类推。

动态绑定有一个非常重要的特定:无需对现存的代码进行修改,就可以对程序进行扩展。

阻止继承:使用final类和方法

final类中的所有方法自动成为final方法、但是其中的域不会。

将方法或类声明为final的主要目的是:确保它们不会再子类中改变语义。

如果一个方法没有被覆盖并且很短,编译器就能够对它进行优化处理,这个过程称为内联。

虚拟机中的即使编译器比传统编译器的处理能力强得多。这种编译器可以准确地知道类之间的继承关系,并能够检测出类中是否真正地存在覆盖给定的方法。如果方法很简短、被频繁调用且没有真正地被覆盖,那么即时编译器就会将这个方法进行内联处理。如果虚拟机加载了另外一个子类,而在这个子类中包含了对内联方法的覆盖,那么优化器将取消对覆盖方法的内联。

抽象方法充当着占位的角色,它们的具体实现在子类中。扩展抽象类可以有两种选择。一种是在抽象类中定义部分抽象类方法或不定义抽象类方法,这样就必须将子类也标记为抽象类,另一种是定义全部的抽象方法,这样一来,子类就不是抽象的了。

类即使不包含抽象方法,也可以将类声明为抽象类。

抽象类不能被实例化。

需要注意的是,可以定义一个抽象类的对象变量,但是它只能引用非抽象子类的对象。

在子类中定义equals方法时,首先调用超类的equals。如果检测失败,对象就不可能相等,如果超类中的域都相等,就需要比较子类中的实例域。

下面给出编写一个完美的equals方法的建议:

(1)显式参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量。

(2)检测this与otherObject是否引用同一个对象

代码语言:javascript
复制
if(this==otherObject) return true;

这条语句只是一个优化,实际上,这是一种经常采用的形式。因为计算这个等式要比一个一个比较类中的所有域所付出的代价小的多。

(3)检测otherObject是否为null,如果为null,返回false。这项检测时很必要的。

代码语言:javascript
复制
if(otherObject==null) return false;

(4)比较this和otherObject是否属于同一个类,如果equals的语义在每个子类中有所改动,就使用getClass检测:

代码语言:javascript
复制
if(getClass()!=otherObject.getClass()) return false;

如果所有子类都有统一的语义,就是用instanceof检测:

代码语言:javascript
复制
if(!(otherObject instanceof ClassName)) return false;

(5)将otherObject转换为相应的类类型变量:

代码语言:javascript
复制
ClassName other=(ClassName) ohterObject;

(6)对所有需要比较的域进行比较了。使用==比较基本类型域,使用equals比较对象域。如果所有的域都匹配,就返回true,否则返回true。

如果在子类中重新定义equals,就要在其中包含调用super.equals(other)。

ArrayList是一个采用类型参数的泛型类。

装箱和拆箱是编译器认可的,而不是虚拟机。编译器在生成类的字节码时,插入必要的方法调用。虚拟机只是执行这些字节码。

参数数量可变的方法,如:

代码语言:javascript
复制
public static double max(double... values){
    double largets=Double.NEGATIVE_INFINITY;
    for(double v: values) if(v>largest) largest=v;
    return largest;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年11月04日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档