《Java 核心技术卷1 第10版》学习笔记------ 组织继承:final类和方法【编译器优化:内联( inlining );】

使用 final 关键字阻止继承

有时候,可能希望阻止人们利用某个类定义子类。不允许扩展的类被称为 final 类。如果在定义类的时候使用了 final 修饰符就表明这个类是 final 类。 例如, 假设希望阻止人们定义Executive类的子类,就可以在定义这个类的时候,使用 final 修饰符声明。声明格式如下所示:

public final class Executive extends Manager{
    ...
}


类中的特定方法也可以被声明为 final。 如果这样做,子类就不能覆盖这个方法( final 类中的所有方法自动地成为 final 方法。) 例如:

public class Employee{
    ...
    public final String getName(){
        return name;
    }
    ...
}

注释:前面曾经说过,域也可以被声明为 final。对于 final 域来说,构造对象之后就不允许改变它们的值了。 不过, 如果将一个类声明为 final, 只有其中的方法自动地成为 final,而不包括域

将方法或类声明为 final 主要目的是: 确保它们不会在子类中改变语义。例如, Calendar类中的 getTime 和 setTime 方法都声明为 final。这表明 Calendar 类的设计者负责实现 Date 类与日历状态之间的转换, 而不允许子类处理这些问题。同样地, String 类也是 final 类,这意味着不允许任何人定义 String 的子类。换言之, 如果有一个 String 的引用, 它引用的一定是一个 String 对象, 而不可能是其他类的对象。

有些程序员认为: 除非有足够的理由使用多态性, 应该将所有的方法都声明为 final。事实上,在 C++ 和 C# 中, 如果没有特别地说明, 所有的方法都不具有多态性。这两种做法可能都有些偏激。我们提倡在设计类层次时, 仔细地思考应该将哪些方法和类声明为 final。

在早期的 Java 中,有些程序员为了避免动态绑定带来的系统开销而使用 final 关键字。如果一个方法没有被覆盖并且很短, 编译器就能够对它进行优化处理, 这个过程为称为内联( inlining )。例如,内联调用 e.getName( ) 将被替换为访问 e.name 域。这是一项很有意义的改进, 这是由于 CPU 在处理调用方法的指令时, 使用的分支转移会扰乱预取指令的策略, 所以,这被视为不受欢迎的。然而, 如果 getName 在另外一个类中被覆盖, 那么编译器就无法知道覆盖的代码将会做什么操作, 因此也就不能对它进行内联处理了。

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值