Thinking in Java 4th chap7笔记-复用类(二)
被初始化。但是空白final在关键字final的使用上提供了更大的灵活性。为此,一个类中final域就可以做到根据对象有所不同,却又保持其恒定不变的特性。[即在不同的构造函数来初始化final]
必须在域的定义处或者每个构造器中用表达式对final进行赋值,这正是final域在使用前总是被初始化的原因。
5.final参数:Java允许在参数列表中以生命的方式将参数声明为final,这意味着你无法在方法中更改参数引用所指向的对象。
->当基本类型的参数被指定为final的时候,你可以读参数,不过却无法修改参数.这一特性主要用来向匿名内部类传递数据;
6.final方法:使用final方法的原因有两个:第一个原因是把方法锁定。以防止任何继承类修改它的含义。确保在继承中使方法行为保持不变,并且不会被覆盖。过去建议使用final方法的原因是效率。在java早期实现中,如果将一个方法指明为final的话,就是同意编译器将针对对该方法的所有调用都转为内嵌调用。当编译器发现一个final方法调用命令时,它会根据自己的谨慎判断,跳过插入程序代码这种正常方式而执行方法调用机制(将参数压入栈,跳至方法代码处并执行,然后跳回并清理栈中的参数,处理返回值),并且以方法体中的实际代码的副本来代替方法调用。这种将消除方法调用的开销。当然,如果一个方法很大, 你的程序代码就会膨胀,因为可能看不到内嵌带来的任何性能上的提高。因为所带来的性能的提高会因为花费于方法内的时间量而被缩减。在最近的Java版本中,特别是hotspot技术可以探测到这种情况,并优化去掉这些效率反而降低的额外的内嵌调用,因此不再需要使用final方法来进行优化了。事实上,这种做法正在逐渐的受到劝阻。在使用javase5/se6的时候,应该让编译器和JVM去处理效率问题,只有在想明确禁止覆盖的时候,才将方法设为final的。
7.final和private关键字,类中所有private方法都隐式的指定为final.由于无法取用private,所以也就无法覆盖它。可以对private方法添加final修饰词,但是这并不能给该方法添加任何额外的意义。如果你试图覆盖private方法(隐含是final的),似乎是奏效的;不过:因为:“覆盖”只是在某方法是基类的接口的一部分才会出现;即,必须将一个对象向上转型为它的基本类型并调用相同的方法。如果某方法为private,它就不是基类接口的一部分。如果在导出类中以相同的名称生成一个方法的话,此时你并没有覆盖该方法,而只是生成了一个新的方法。由于private方法无法触及而且能有效隐藏,所以除了把它看做是因为它归属类的组织结构的原因而存在外,其他任何事物都不需要考虑到它。
8.final类:当将某个类的整体定义为final时,(通常将关键字定义于它的定义之前),就表明了你不打算继承该类,而且也不允许别人这么做。换句话说,出于某种考虑,你对该类的设计不需要任何变动,或出于安全的考虑,你不希望它有子类。
注:final类的域可以根据个人意愿的选择为是或者不是final,无论类是否被定义为final,系统的规则都适用于定义为final的域。然而由于final类禁止继承,所以final类的所有方法都隐式指定是final的,因为无法覆盖他们。final类中可以给方法添加final修饰词,不过不会增添任何意义。
16.
Vector:1.许多方法为final,无法继承并覆盖2.Statck继承Vector,逻辑上不合理3.方法同步 ->ArrayList
Hashtable:1.竟然没有final方法2.同步->HashMap
上面的两个例子说明Java标准程序库也有一些粗糙的设计。
17.每个类的编译代码都存在于它自己的独立文件中。该文件只在需要使用程序代码时才会加载。一般来说,类的代码在初次使用时才加载。这通常是指加载发生于创建类的第一个对象之时,但是当访问static时,也会发生加载。初次使用之处也是static初始化发生之处。所有的static对象和static代码都会在加载时依程序中的顺序,即定义类时的书写顺序而依次初始化。当然,定义为static的东西只会被初始化一次。(构造器也是static方法,尽管static关键字没有显示的写出来,因此更准确的讲,类是在其任何static成员被访问时加载的)
18.总结:
1.继承和组合都能从现有类型生成新类型。组合一般是将现有类型作为新类型底层实现的一部分加以复用,而继承复用的是接口。在使用继承时,由于导出类具有基类接口,因此它可以向上转型至基类,这对多态至关重要。尽管面向对象编程对继承极力强调,但在开始一个设计时,一般应优先选择使用组合或者可能是代理,只有在确实必要时才使用继承。因为组合更具灵活性。此外,通过对成员类型使用继承技术的添加技巧,可以在运行时改变那些成员对象的类型和行为。因此可以在运行时改变组合而成的对象行为。(比如通过某set方法设置为另一个该成员的一个子对象,从而改变其行为)
->如果你的设计过于复杂,通过将现有类拆分为更小的部分而添加更多的对象,通常会有所帮助。
19.部分
源码:
package com.book.chap7.reuse;
/**
*
*详细讲述继承与初始化
*1.Beetle上运行java时,所发生的第一件事情就是访问Beetle的main,一个static方法,于是加载器开始启动并找出Beetle的加载代码,在名为Beetle.class中。在对它进行加载的过程
*中,编译器注意到它有一个基类,由关键字extends获得,于是它继续加载;不管你是否打算产生一个该基类的对象,这都要发生。如果该基类还有其自身的基类,那么第二个机会就会被
*加载,如此类推。接下来,根基类的static初始化,此类为Inspect,即会执行,然后是下一个导出类,以此类推。这种方式很重要,因为导出类的static初始化可能会依赖于基类成员能
*否被正确初始化
*2.到此为止,必要的类都已经加载完毕,对象就可以创建了。首先,对象中的所有基本类型都会被设置为默认值,对象引用被设置为null,这是通过将对象内存设为二进制零值而一举生成
*的。然后基类的构造器会被调用。本例中,是自动被调用的;基类的构造器和导出类的构造器一样,以相同的顺序来经历相同的过程。
*3.基类构造器完成之后,实例变量按此顺序被初始化。最后,构造器的其余部分被执行。
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-4-26
*
*/
public class Beetle extends Inspect
{
private int k = printInit("Beetle.k initialized");
public Beetle()
{
System.out.println("j= " + j