重温经典《Thinking in java》第四版之第七章 复用类(四十二)

简介: 重温经典《Thinking in java》第四版之第七章 复用类(四十二)

7.8.2 final方法

使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义。这是出于设计的考虑:想要确保在继承中使方法行为保持不变,并且不会被覆盖。过去建议使用final方法的第二个原因是效率。在Java的早期实现中,如果将一个方法指明为final,就是同意编译器将针对该方法的所有调用都转为内嵌调用。当编译器发现一个final方法调用命令时,它会根据自己的谨慎判断,跳过插入程序代码这种正常方式而执行方法调用机制(将参数压入栈,跳至方法代码处并执行,然后跳回并清理栈中的参数,处理返回值),并且以方法体中的实际代码的副本来替代方法调用。这将消除方法调用开销。当然,如果一个方法很大,你的代码就会膨胀,因而可能看不到内嵌带来的任何性能提高,因为,所带来的性能提高会因为花费于方法内的时间量而被缩减。在现在的Jvm版本中,不再需要使用final方法来进行性能优化了。

 

7.8.3 final类

当将某个类的整体定义为final时,就表明了你不打算继承该类,而且也不允许别人这样做。换句话说,出于某种考虑,你对该类的设计永不需要做任何变动,或者出于安全的考虑,你不希望它有子类。

//: reusing/Jurassic.java // Making an entire class final. classSmallBrain {} 
finalclassDinosaur { 
inti=7; 
intj=1; 
SmallBrainx=newSmallBrain(); 
voidf() {} 
} 
//! class Further extends Dinosaur {} // error: Cannot extend final class ‘Dinosaur’ publicclassJurassic { 
publicstaticvoidmain(String[] args) { 
Dinosaurn=newDinosaur(); 
n.f(); 
n.i=40; 
n.j++; 
    } 
}

///:~

 

7.8.4 有关final的忠告

在设计类时,将方法指明是final的,应该说是明智的。你可能会觉得,没人会想要覆盖你的方法。有时这是对的。但请留意你所做的假设。要预见类是如何被复用的一般是很困难的,特别是对于一个通用类而言更是如此。如果将一个方法指定为final,可能会妨碍其他程序员在项目中通过继承复用你的类,而这只是因为你没有想到它会以那种方式被运用。

 

7.9 初始化及类的加载

在许多传统语言中,程序是作为启动过程的一部分立刻被加载的。然后是初始化,紧接着程序开始运行。这些语言的初始化过程必须小心控制,以确保定义为static的东西,其初始化顺序不会造成麻烦。例如C++中,如果某个static期望另一个static在被初始化之前就能有效地使用它,那么就会出现问题。

Java就不会出现这个问题,因为它采用了一种不同的加载方式。加载是众多变得更加容易的动作之一,因为Java中的所有事物都是对象。请记住,每个类的编译代码都存在于它自己的独立的文件中。该文件只在需要使用程序代码时才会被加载。一般来说,可以说“类的代码在初次使用时才加载。”这通常是指加载发生于创建类的第一个对象之时,但是当访问static域或static方法时,也会发生加载。初始使用之处也是static初始化发生之处。所有static对象和static代码段都会在加载时依程序中的顺序而依次初始化。当然,定义为static的东西只会被初始化一次。

 

7.9.1 继承与初始化

了解包括继承在内的初始化全过程,以对所发生的一切有个全局性的把握,是很有益的。如:

importstaticnet.mindview.util.Print.*; 
classInsect { 
privateinti=9; 
protectedintj; 
Insect() { 
print("i = "+i+", j = "+j); 
j=39; 
    } 
privatestaticintx1=printInit("static Insect.x1 initialized"); 
staticintprintInit(Strings) { 
print(s); 
return47; 
    } 
} 
publicclassBeetleextendsInsect { 
privateintk=printInit("Beetle.k initialized"); 
publicBeetle() { 
print("k = "+k); 
print("j = "+j); 
    } 
privatestaticintx2=printInit("static Beetle.x2 initialized"); 
publicstaticvoidmain(String[] args) { 
print("Beetle constructor"); 
Beetleb=newBeetle(); 
    } 
}
/* Output: static Insect.x1 initialized static Beetle.x2 initialized Beetle constructor i = 9, j = 0 Beetle.k initialized k = 47 j = 39

*///:~

 

7.10 总结

继承和组合都能从现有类型生成新类型。组合一般是将现有类型作为新类型底层实现的一部分来加以复用,而继承复用的是接口。

在使用继承时,由于导出类具有基类接口,因此它可以向上转型至基类,这对于多态来讲至关重要。

尽管面向对象编程对继承极力强调,但在开始一个设计时,一般应优先选择使用组合或者代理,只在确实必要时才使用继承。因为组合更具灵活性。此外,通过对成员类型使用继承技术的添加技巧,可以在运行时改变那些成员对象的类型和行为。因此,可以在运行时改变组合而成的对象的行为。

在设计一个系统时,目标应该是找到或者创建某些类,其中每个类都有具体的用途,而且既不会太大(包含太多的功能而难以复用),也不会太小(不添加其他功能就无法使用)。如果你的设计变得过去复杂,通过将现有类拆分为更小的部分而添加更多的对象,通常会有所帮助。

当你开始设计一个系统时,应该认识到程序开发是一种增量过程,犹如人类的学习一样,这一点很重要。程序开发依赖于实验,你可以尽己所能去分析,但当你开始执行一个项目时,你仍然无法知道所有的答案。如果将项目视作是一种有机的,进化的生命体去培养,而不是打算像盖摩天大楼一样快速见效,就会获得更多的成果和更迅速的回馈。继承与组合正是在面向对象程序设计中使得你可以执行这种实验的最基本的两个工具。

目录
相关文章
|
6天前
|
Java 编译器 ice
【Java开发指南 | 第十五篇】Java Character 类、String 类
【Java开发指南 | 第十五篇】Java Character 类、String 类
27 1
|
4天前
|
自然语言处理 Java API
Java 8的Stream API和Optional类:概念与实战应用
【5月更文挑战第17天】Java 8引入了许多重要的新特性,其中Stream API和Optional类是最引人注目的两个。这些特性不仅简化了集合操作,还提供了更好的方式来处理可能为空的情况,从而提高了代码的健壮性和可读性。
26 7
|
6天前
|
Java
【Java开发指南 | 第十四篇】Java Number类及Math类
【Java开发指南 | 第十四篇】Java Number类及Math类
17 1
|
2天前
|
安全 Java 容器
Java一分钟之-并发编程:线程安全的集合类
【5月更文挑战第19天】Java提供线程安全集合类以解决并发环境中的数据一致性问题。例如,Vector是线程安全但效率低;可以使用Collections.synchronizedXxx将ArrayList或HashMap同步;ConcurrentHashMap是高效线程安全的映射;CopyOnWriteArrayList和CopyOnWriteArraySet适合读多写少场景;LinkedBlockingQueue是生产者-消费者模型中的线程安全队列。注意,过度同步可能影响性能,应尽量减少共享状态并利用并发工具类。
17 2
|
5天前
|
设计模式 算法 Java
Java的前景如何,好不好自学?,万字Java技术类校招面试题汇总
Java的前景如何,好不好自学?,万字Java技术类校招面试题汇总
|
6天前
|
安全 Java 开发者
Java一分钟之-文件与目录操作:Path与Files类
【5月更文挑战第13天】Java 7 引入`java.nio.file`包,`Path`和`Files`类提供文件和目录操作。`Path`表示路径,不可变。`Files`包含静态方法,支持创建、删除、读写文件和目录。常见问题包括:忽略异常处理、路径解析错误和权限问题。在使用时,注意异常处理、正确格式化路径和考虑权限,以保证代码稳定和安全。结合具体需求,这些方法将使文件操作更高效。
11 2
|
6天前
|
安全 Java 开发者
Java一分钟之-Optional类:优雅处理null值
【5月更文挑战第13天】Java 8的`Optional`类旨在减少`NullPointerException`,提供优雅的空值处理。本文介绍`Optional`的基本用法、创建、常见操作,以及如何避免错误,如直接调用`get()`、误用`if (optional != null)`检查和过度使用`Optional`。正确使用`Optional`能提高代码可读性和健壮性,建议结合实际场景灵活应用。
22 3
|
6天前
|
存储 Java 索引
【Java开发指南 | 第十六篇】Java数组及Arrays类
【Java开发指南 | 第十六篇】Java数组及Arrays类
10 3
|
6天前
|
存储 缓存 Java
【Java开发指南 | 第六篇】Java成员变量(实例变量)、 类变量(静态变量)
【Java开发指南 | 第六篇】Java成员变量(实例变量)、 类变量(静态变量)
13 2
|
6天前
|
Java 编译器
【Java开发指南 | 第一篇】类、对象基础概念及Java特征
【Java开发指南 | 第一篇】类、对象基础概念及Java特征
12 4