重温经典《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 总结

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

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

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

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

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

目录
相关文章
|
1月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
148 57
|
4天前
|
JSON Java Apache
Java基础-常用API-Object类
继承是面向对象编程的重要特性,允许从已有类派生新类。Java采用单继承机制,默认所有类继承自Object类。Object类提供了多个常用方法,如`clone()`用于复制对象,`equals()`判断对象是否相等,`hashCode()`计算哈希码,`toString()`返回对象的字符串表示,`wait()`、`notify()`和`notifyAll()`用于线程同步,`finalize()`在对象被垃圾回收时调用。掌握这些方法有助于更好地理解和使用Java中的对象行为。
|
1月前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
53 8
|
1月前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
73 17
|
1月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
1月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
134 4
|
1月前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
76 2
|
1月前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
58 4
|
1月前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
55 3
|
1月前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
50 5