7 .2 继承语法
例子:
  1. package com.cy.reusing;
  2.  
  3. import static com.java.util.Print.*;
  4.  
  5. class Cleanser {
  6. private String s = "Cleanser";
  7. public void append(String a) { s += a; }
  8. public void dilute() { append(" dilute()"); }
  9. public void apply() { append(" apply()"); }
  10. public void scrub() { append(" scrub()"); }
  11. public String toString() {
  12. return s;
  13. }
  14. public static void main(String[] args) {
  15. Cleanser x = new Cleanser();
  16. x.dilute(); x.apply(); x.scrub();
  17. print(x);
  18. }
  19. }
  20.  
  21. public class Detergent extends Cleanser {
  22. // Change a method:
  23. public void scrub() {
  24. append(" Detergent.scrub()");
  25. super.scrub(); // Call base-class version
  26. }
  27. // Add methods to the interface:
  28. public void foam() { append(" foam()"); }
  29. // Test the new class:
  30. public static void main(String[] args) {
  31. Detergent x = new Detergent();
  32. x.dilute();
  33. x.apply();
  34. x.scrub();
  35. x.foam();
  36. print(x);
  37. print("Testing base class:");
  38. Cleanser.main(args);
  39. }
  40. }
  41. /* Output:
  42. Cleanser dilute() apply() Detergent.scrub() scrub() foam()
  43. Testing base class:
  44. Cleanser dilute() apply() scrub()
  45. *///:~
Cleanser中所有的方法都必须是public的,这一点非常重要。请记住,如果没有加任何访问
权限修饰词,那么成员默认的访问权限是包访问权限, 它仅允许包内的成员访问。因此,在此
包中,如果没有访问权限修饰词,任何人都可以使用这些方法。例如, Detergent就不成问题。
但是,其他包中的某个类若要从CIeanser中继承,则只能访问public成员。所以,为了继承, 一
般的规则是将所有的数据成员都指定为private ,将所有的方法指定为public (稍后将会学到,
protected成员也可以借助导出类来访问)。当然,在特殊情况下,必须做出调整,但上述方法的
确是一个很有用的规则。
正如我们在scrub()中所见,使用基类中定义的方法及对它进行修改是可行的。在此例中,
你可能想要在新版本中调用从基类继承而来的方法。但是在scrub()中,并不能直接调用scrub() ,
因为这样做将会产生递归,而这并不是你所期望的。为解决此问题, Java用super关键字表示超
类的意思,当前类就是从超类继承来的。为此,表达式super.scrub()将调用基类版本的scrub()
方法.
 
 

7.8 final关键字
7.8.1 final 数据
一个既是static又是final的域只占据一段不能改变的存储空间。
当对对象引用而不是基本类型运用final时, 其含义会有一点令人迷惑。对于基本类型,
final使数值恒定不变; 而用于对象引用, final使引用恒定不.变。一旦引用被初始化指向一个对
象,就无法再把它改为指向另一个对象。然而,对象其自身却是可以被修改的, Java并未提供
使任何对象恒定不变的途径(但可以自己编写类以取得使对象恒定不变的效果)。这一限制同样
适用数组,它也是对象。
 
fínal 参数:
Java允许在参数列表中以声明的方式将参数指明为final。这意味着你无法在方法中更改参数
引用所指向的对象:
  1. package com.cy.reusing;
  2.  
  3. class Gizmo {
  4. public void spin() {}
  5. }
  6.  
  7. public class FinalArguments {
  8. void with(final Gizmo g) {
  9. //! g = new Gizmo(); // Illegal -- g is final
  10. }
  11. void without(Gizmo g) {
  12. g = new Gizmo(); // OK -- g not final
  13. g.spin();
  14. }
  15. // void f(final int i) { i++; } // Can't change
  16. // You can only read from a final primitive:
  17. int g(final int i) {
  18. return i + 1;
  19. }
  20. public static void main(String[] args) {
  21. FinalArguments bf = new FinalArguments();
  22. bf.without(null);
  23. bf.with(null);
  24. }
  25. } ///:~
 
方法f()和g()展示了当基本类型的参数被指明为final时所出现的结果:你可以读参数,但却
无法修改参数.这一特性主要用来向匿名内部类传递数据,我们将在第10章中学习它.
 
7.8.2 final 方法
使用final方法的原因有两个.第一个原因是把方法锁定,以防任何继承类修改它的含义.
这是出于设计的考虑:想要确保在继承中使方法行为保持不变,并且不会被覆盖。
过去建议使用final方法的第二个原因是效率。
类中所有的private方法都隐式地指定为是final的。由于无法取用private方法,所以也就无
法覆盖它.可以对private方法添加final 修饰词,但这并不能给该方法增加任何额外的意义。
这一问题会造成混淆.因为,如果你试图覆盖一个private方法(隐含是final的) ,似乎是奏
效的,而且编译器也不会绘出错误信息:
  1. package com.cy.reusing;
  2.  
  3. import static com.java.util.Print.*;
  4.  
  5. class WithFinals {
  6. // Identical to "private" alone:
  7. private final void f() { print("WithFinals.f()"); }
  8. // Also automatically "final":
  9. private void g() { print("WithFinals.g()"); }
  10. }
  11.  
  12. class OverridingPrivate extends WithFinals {
  13. private final void f() {
  14. print("OverridingPrivate.f()");
  15. }
  16.  
  17. private void g() {
  18. print("OverridingPrivate.g()");
  19. }
  20. }
  21.  
  22. class OverridingPrivate2 extends OverridingPrivate {
  23. public final void f() {
  24. print("OverridingPrivate2.f()");
  25. }
  26. public void g() {
  27. print("OverridingPrivate2.g()");
  28. }
  29. }
  30.  
  31. public class FinalOverridingIllusion {
  32. public static void main(String[] args) {
  33. OverridingPrivate2 op2 = new OverridingPrivate2();
  34. op2.f();
  35. op2.g();
  36. // You can upcast:
  37. OverridingPrivate op = op2;
  38. // But you can't call the methods:
  39. //! op.f();
  40. //! op.g();
  41.  
  42. // Same here:
  43. WithFinals wf = op2;
  44. //! wf.f();
  45. //! wf.g();
  46. }
  47. }
  48. /* Output:
  49. OverridingPrivate2.f()
  50. OverridingPrivate2.g()
  51. *///:~
"覆盖"只有在某方法是基类的接口的一部分时才会出现。即,必须能将一个对象向上转型
为它的基本类型并调用相同的方法(这一点在下一章阐明)。 如果某方法为prlvåte ,它就不是基
类的接口的一部分。它仅是一些隐藏于类中的程序代码,只不过是具有相同的名称而已。但如
果在导出类中以相同的名称生成-个publlc 、protected或包访问权限方法的话,该方法就不会产
生在基类中出现的"仅具有相同名称"的情况。此时你并没有覆盖该方法,仅是生成了一个新
的方法。由于private方法无法触及而且能有效隐藏,所以除了把它看成是因为它所归属的类的
组织结构的原因而存在外,其他任何事物都不需要考虑到它。
 

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

  1. package com.cy.reusing;
  2.  
  3. class SmallBrain {}
  4.  
  5. final class Dinosaur {
  6. int i = 7;
  7. int j = 1;
  8. SmallBrain x = new SmallBrain();
  9. void f() {}
  10. }
  11.  
  12. //! class Further extends Dinosaur {}
  13. // error: Cannot extend final class 'Dinosaur'
  14.  
  15. public class Jurassic {
  16. public static void main(String[] args) {
  17. Dinosaur n = new Dinosaur();
  18. n.f();
  19. n.i = 40;
  20. n.j++;
  21. }
  22. } ///:~
请注意, final类的域可以根据个人的意愿选择为是或不是final。不论类是否被定义为final ,
相同的规则都适用于定义为final的域。然而,由于final类禁止继承,所以final类中所有的方法
都隐式指定为是final的,因为无法覆盖色们。在final类中可以给方法添加final修饰词,但这不
会增添任何意义。
 
7.9 初始化及类的加载
7.9. 1 继承与初始化
了解包括继承在内的初始化全过程,以对所发生的一切有个全局性的把握,是很有益的。
请看下例:
  1. package com.cy.reusing;
  2.  
  3. import static com.java.util.Print.*;
  4.  
  5. class Insect {
  6. private int i = 9;
  7. protected int j;
  8. Insect() {
  9. print("i = " + i + ", j = " + j);
  10. j = 39;
  11. }
  12.  
  13. private static int x1 = printInit("static Insect.x1 initialized");
  14.  
  15. static int printInit(String s) {
  16. print(s);
  17. return 47;
  18. }
  19. }
  20.  
  21. public class Beetle extends Insect {
  22. private int k = printInit("Beetle.k initialized");
  23.  
  24. public Beetle() {
  25. print("k = " + k);
  26. print("j = " + j);
  27. }
  28.  
  29. private static int x2 = printInit("static Beetle.x2 initialized");
  30.  
  31. public static void main(String[] args) {
  32. print("Beetle constructor");
  33. Beetle b = new Beetle();
  34. }
  35. }
  36. /* Output:
  37. static Insect.x1 initialized
  38. static Beetle.x2 initialized
  39. Beetle constructor
  40. i = 9, j = 0
  41. Beetle.k initialized
  42. k = 47
  43. j = 39
  44. *///:~
  在Beetle上运行Java时,所发生的第-件事情就是试图访问Bettle.main() (一个static方法) ,
于是加载器开始启动并找出Beetle类的编译代码(在名为BattIe.class的文件之中)。在对它进行
加载的过程中,编译器注意到它有一个基类(这是由关键字extends得知的) .于是它继续进行加
载。不管你是否打算产生一个该基类的对象,这都要发生(请尝试将对象创建代码注释掉,以
证明这一点)。
  如果该基类还有其自身的基类,那么第二个基类就会被加载,如此类推。接下来,根基类
中的static初始化(在此例中为Insect) 即会被执行,然后是下一个导出类,以此类推。这种方
式很重要,因为导出类的static初始化可能会依赖于基类成员能否被正确初始化。
  至此为止,必要的类都已加载完毕,对象就可以被创建了。首先,对象中所有的基本类型
都会被设为默认值,对象引用被设为null——这是通过将对象内存设为二进制零值而一举生成的。
然后,基类的构造器会被调用。在本例中,它是被自动调用的。但也可以用super来指定对基类
构造器的调用(正如在Beetle()构造器中的第一步操作)。基类构造器和导出类的构造器一样,
以相同的顺序来经历相同的过程。在基类构造器完成之后,实例变量按其次序被初始化。最后,
构造器的其余部分被执行。
 
 
 
 
 
 
----------------

ThinkJava-复用类的更多相关文章

  1. [THINKING IN JAVA]复用类

    7 复用类 7.1 组合 即在一个类中使用另一个类作为成员变量,这是复用了现有程序代码的功能,而非形式. 7.2 继承 关键字:extends,这种复用是形式的复用,是一种可扩展和限制的复用: 复用: ...

  2. java编程思想-复用类总结

    今天继续读<java 编程思想>,读到了复用类一章,看到总结写的很好,现贴上来,给大家分享. 继承和组合都能从现有类型生成新类型.组合一般是将现有类型作为新类型底层实现的一部分来加以复用, ...

  3. Java编程思想学习(五) 复用类

    1.继承与组合 复用类的方法有两种:继承与组合.继承就不多说了,组合就是直接在类中new一个对象. 数组也是对象,使用数组也是组合的一种. 2.初始化基类 当创建一个导出类的对象时,该对象包含一个基类 ...

  4. java复用类

    java复用类英文名叫reusing classes  ,重新使用的类,复用的意思就是重复使用的类,其实现方法就是我们平常使用的组合和继承: 1.组合: has-a 的关系  (自我理解:组合就是我们 ...

  5. Java基础 -- 复用类(组合和继承)

    复用类有两种实现方式. 在新的类中产生现有类的对象,由于新的类是由现有类的对象所组成,所以这种方法称之为组合. 采用继承实现. 一  组合语法 下面创建两个类WaterSource和Sprinkler ...

  6. 【Thinking in java, 4e】复用类

    mark一篇09年的<Thinking in Java>笔记:here --> https://lawrence-zxc.github.io/2009/11/07/thinking- ...

  7. Java基础—复用类

    复用代码是Java众多引人注目的功能之一. 一般而言,实现代码重用java提供了两种方式:组合以及继承. 组合:新的类由现有类的对象所组成.(复用现有代码的功能,而非它的形式) 继承:按照现有类的类型 ...

  8. 《Think in Java》(七)复用类

    Java 中复用代码的方式就是复用类,复用类的方式有: 组合 继承 代理(并没有啥高深的含义,只是在使用类A前,新增了类B,让类B的每个方法去调用类A中对应的方法,也就是说类B代理了类A...不过我还 ...

  9. Java编程思想(四) —— 复用类

    看了老罗罗升阳的专訪,不由自主地佩服,非常年轻,我之前以为和罗永浩一个级别的年龄.也是见过的不是初高中编程的一位大牛之中的一个,专訪之后.发现老罗也是一步一个脚印的人. 别说什么难做,做不了.你根本就 ...

  10. [Java编程思想] 第七章 复用类

    第七章 复用类 第一种方法非常直观:只需在新的类中产生现有类的对象(组合). 第二种方法更细致一些:它按照现有类的类型来创建新类(继承). 7.1 组合语法   只需将对象引用置于新类中即可. cla ...

随机推荐

  1. java web中的多条件查询

    转自:http://blog.csdn.net/xulu_258/article/details/46623317 所谓多条件查询即为用户输入想要查询的条件,然后根据用户输入的条件进行查询. 当用户有 ...

  2. jQuery 禁用select和取消禁用之disabled

    jQuery1.5及以前: 禁用select: $('#groupId').attr('disabled','disabled'); 取消禁用: $('#groupId').removeAttr('d ...

  3. OSI七层网络模型与TCP/IP四层模型介绍

    目录 OSI七层网络模型与TCP/IP四层模型介绍 1.OSI七层网络模型介绍 2.TCP/IP四层网络模型介绍 3.各层对应的协议 4.OSI七层和TCP/IP四层的区别 5.交换机工作在OSI的哪 ...

  4. SQL SERVER 压缩数据库日志文件

    ALTER DATABASE DBNAME SET RECOVERY SIMPLE --设置为简单恢复模式 GO DBCC SHRINKFILE (DBNAME_log, 1) GO ALTER DA ...

  5. 揭秘Keras推荐系统如何建立模型、获取用户爱好

    你是否有过这样的经历?当你在亚马逊商城浏览一些书籍,或者购买过一些书籍后,你的偏好就会被系统学到,系统会基于一些假设为你推荐相关书目.为什么系统会知道,在这背后又藏着哪些秘密呢? 荐系统可以从百万甚至 ...

  6. Swift 编程语言入门教程

    1   简介 今天凌晨Apple刚刚发布了Swift编程语言,本文从其发布的书籍<The Swift Programming Language>中摘录和提取而成.希望对各位的iOS& ...

  7. 重构Tips

    一,重新组织函数1.首先找出局部变量和参数. 1>任何不会被修改的变量都可以当作参数传入.2.去掉临时变量Replace Temp with Query.用查询函数代替临时变量3.Extract ...

  8. 【c++基础】int转string自动补零

    前言 使用to_string函数可以将不同类型的数据转换为string类,请参考here和here.如果string的位数固定,如何进行自动补零呢?请看本文实例! 代码 确定位数,to_string ...

  9. UnicodeDammit

    UnicodeDammit 是BS内置库, 主要用来猜测文档编码. 编码自动检测 功能可以在Beautiful Soup以外使用,检测某段未知编码时,可以使用这个方法: from bs4 import ...

  10. 51Nod:1265 四点共面

    计算几何 修改隐藏话题 1265 四点共面  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出三维空间上的四个点(点与点的位置均不相同),判断这4个点 ...