复用代码是 Java 众多引人注目的功能之一。

Java 可以通过创建类来复用代码,要在使用类的时候不破坏现有代码,有两种方式:

  • 组合:在新的类中使用现有类的对象。
  • 继承:按照现有类的类型来创建新类,无需改变现有类的形式,并为其添加新代码。

组合语法

  • 使用组合技术只需要将对象引用置于新类中。
  • 每个非基本类型的对象都有一个 toString() 方法,而且当编译器需要一个 String 而你传入一个对象时,toString() 会被调用。
  • 类中的对象引用会被默认初始化为 null,如果你对其调用任何方法都会抛出异常,但是可以在不抛出异常的情况下,仍然可以打印一个 null 引用
  • 类中对象引用的初始化位置:
    • 在定义对象的地方
    • 在类的构造器中
    • 惰性初始化,即在要使用该对象的地方进行初始化
    • 实例初始化
  1. class Soap {
  2. private String s;
  3. Soap() {
  4. System.out.println("Soup()");
  5. s = "Constructed";
  6. }
  7. @Override
  8. public String toString() {
  9. return s;
  10. }
  11. }
  12. /**
  13. * Bath
  14. */
  15. public class Bath {
  16. private String s1 = "happy", // 在定义处初始化
  17. s2;
  18. private Soap soap;
  19. private int i;
  20. public Bath() {
  21. System.out.println("Inside Bath()");
  22. soap = new Soap(); // 在构造函数中初四花
  23. }
  24. @Override
  25. public String toString() {
  26. if (s2 == null) {
  27. s2 = "Joy"; // 惰性初始化
  28. }
  29. return s2;
  30. }
  31. {
  32. i = 2; // 实例初始化
  33. }
  34. public static void main(String[] args) {
  35. Bath b = new Bath();
  36. System.out.println(b);
  37. }
  38. }

继承语法

  • 继承是 OOP 语言和 Java 语言不可缺少的部分,当创建一个类时,总是在继承,即使没有显式继承某个类,也会隐式地从 Object 类中继承。
  • 继承由关键词 extends 指定,其形式如class Detergent extends Cleanser{},基类的所有方法和成员都会自动导入到导出类中。
  • 可以为每个类都创建一个 main 方法,这样可以使得每个类的单元测试变得简便。即使某个类只有包访问权限,其public main也可以通过 java className的方式访问到
  • 为了继承,一般是将所有的数据成员都指定为 private,将所有的方法指定为 public。
  • 我们对继承来的方法进行重写,重写之后可以通过 super 关键词访问基类版本的方法,如super.func();
  • Java 会自动在导出类的构造器中插入对基类构造器的调用,其总是在导出类构造器执行之前,即使是在定义处初始化的语句也会在基类构造器执行之后执行。
  • 即使没有为导出类创建构造器,编译器也会在默认构造器中调用基类的构造器
  • 如果没有默认的基类构造器,或者想要调用一个带有参数的基类构造器,就必须使用 super 关键词显式调用基类构造器,调用基类构造器必须是在你导出类构造器的第一条语句

代理

代理是指,我们将一个成员对象置于要构造的类中(像组合),但与此同时我们在新类中暴露该成员对象的所有或部分方法(想继承)。

IDEA自动创建代理的过程:

  • 先在代理类中声明要代理的成员。
  • Alt + Insert快捷键,选中 Delegation
  • 选中要代理的函数即可。
  1. class SpaceShipControls {
  2. void up(int velocity) {}
  3. void down(int velocity) {}
  4. void left(int velocity) {}
  5. void right(int velocity) {}
  6. void back(int velocity) {}
  7. void turboBoost() {}
  8. }
  9. public class SpaceShipDelegation {
  10. SpaceShipControls spaceShipControls = new SpaceShipControls();
  11. public void up(int velocity) {
  12. spaceShipControls.up(velocity);
  13. }
  14. public void down(int velocity) {
  15. spaceShipControls.down(velocity);
  16. }
  17. public void left(int velocity) {
  18. spaceShipControls.left(velocity);
  19. }
  20. public void right(int velocity) {
  21. spaceShipControls.right(velocity);
  22. }
  23. public void back(int velocity) {
  24. spaceShipControls.back(velocity);
  25. }
  26. public void turboBoost() {
  27. spaceShipControls.turboBoost();
  28. }
  29. public static void main(String[] args) {
  30. SpaceShipDelegation spaceShipDelegation = new SpaceShipDelegation();
  31. spaceShipDelegation.left(1);
  32. }
  33. }

结合使用组合继承

  • 可以结合组合和继承来创建复杂的类
  • 编译器会强制你去初始化基类,并且要求在构造器最开始出就要这么做,但是它不会要求你对成员对象进行初始化,因此需要自己注意。
  • Java 中没有 C++ 中的析构函数,就像之前所说的一样,如果我们的类的确需要做一些类似的工作(如关闭文件),我们需要自己实现一个方法来实现,而当涉及到继承时,我们要确保以正确的顺序调用该函数,推荐和C++中析构函数的执行顺序一样编写该函数,即先清理导出类本身,再调用基类的清理函数。
  • 清理函数需要放在 finally 子句中,以防异常的出现,导致清理函数未被执行,可参考练习12
  • 如果 Java 的基类拥有某个已经被多次重载的方法名称时,在导出类中重新定义该方法的名称,不会屏蔽其在基类中的任何版本。这意味着,在导出类中,重载和重新定义(重写)容易混淆在一起,如果不看基类的定义是很难分辨某个方法是否正确的被重新定义了。我们可以使用@Override注解来标识某个方法我们希望其是重写而不是重载,如果一不小心重载了,则会出现编译错误来提醒我们。

在组合与继承之间选择

  • 组合和继承都允许在新的类中放置子对象,组合是显式地这样做,而继承则是隐式地这样做。
  • 组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情况。有时,允许类的用户直接访问新类中组合成分是有意义的。
  • 在继承时,使用某个现有类,开发一个它的特殊版本。通常,这意味着你在使用一个通用类,并为了某种特殊需要而将其特殊化。

向上转型

  • “为新的类提供方法”不是继承中最重要的部分,其重要的方面是用来表现新类和基类之间的关系。简单的说,我们可以认为“导出类是基类的一种类型”,即可以把导出类当成基类来使用
  • 由于导出类转换为基类在继承图上是向上移动的,因为我们将其成为“向上转型”
  • 向上转型是从一个较为专用的类向较为通用的类转变
  • 虽然在教授OOP的过程中多次强调继承,但是我们应该慎用继承。判断是否要使用的继承的一个简单方法就是,判断我们是否要进行向上转型,如果要进行向上转型,则用继承,反之,则用组合。
  1. class Instrument {
  2. public void play() {}
  3. static void tune(Instrument i) {
  4. i.play();
  5. }
  6. }
  7. public class Wind extends Instrument {
  8. public static void main(String[] args) {
  9. Wind wind = new Wind();
  10. Instrument.tune(wind); // 传递参数时,用了向上转型
  11. }
  12. }

final 关键字

final 关键词的含义通常指“无法改变的”,使用这个关键词通常是因为设计和效率的原因。,final 可以用在数据、方法和类上。

final 数据

  • 数据的恒定不变分为两种情况:编译时常量和在运行时初始化并并无法的改变的值。
  • 在 Java 中,这类常量必须是基本数据类型,并且用关键词 final 表示,并在该常量定义时对其初始化,如final int value = 1。通常,编译时常量还是一个static数据,即static final int VALUE_ONE = 1
  • 编译器常量的命名规则是:全用大写字母,单词与单词之间用_隔开
  • 即使一个变量是final,我们也无法确定其是编译时常量,因为初始化没有要求是字面量,即初始化可以通过调用函数实现,如final int value = rand.nextInt(20)
  • 同时一个final数值,如果其是static的,那么它可能是在类导入时初始化的,而他不是static的话,它是在实例化时初始化的。
  • 对于基本变量,final 使数值恒定不变,但是对于对象引用,其只是要求对象引用不变,即不指向新的对象,而对象本身是可以被修改的。
  • Java 允许“空白 final”,即被声明为 final 但是又没有给定初值的域,虽然可以在定义时不给定初值,按时编译器会保证,final 域在使用前都必须被初始化,即如果没有在定义处给定 final 域的初值的话,就必须在每个构造器中对该 final 域进行赋值。
  • Java 允许在参数列表中以声明的方式将参数指明为 final,其含义为,在该函数中无法修改该变量:
    • 参数类型为基本类型:可以读参数,但是不能修改
    • 参数类型为对象类型:无法修改引用

final 方法

  • 可以将一个方法定义成 final,这样可以防止任何继承类修改它的含义(即导出类无法覆盖实现)
  • 在 Java 的早期实现中,对 final 方法的调用会被转为内嵌调用(C++ 中的 inline),但是现在不需要用这样的方式来优化代码了
  • 类中的所有 private 方法都被隐式的指定为 final
  • “覆盖”只有在方法是基类的接口的一部分时才会出现,即必须能将一个对象向上转型为它的基本类型并调用相同的方法,如果一个方法是 private,那么它就不是接口的一部分。

final 类

当将一个类的整体定义为 final 时,就表明该类无法被继承,同时隐式地将所有方法都定义为 final。

初始化及类的加载

  • 每个类的编译代码都存在与他自己独立的文件中。该文件只有在需要使用程序代码的时候才会被加载。
  • 一般来说,只有在“类首次使用才加载”,即加载发生于第一次创建类的对象或第一次使用类中的静态域或静态方法。
  • 在加载导出类是,Java 编译器会注意到它继承于某个基类,因此他会先去加载该基类。
  1. package com.company.ch07;
  2. class Insert {
  3. private int i = 9;
  4. protected int j;
  5. Insert() {
  6. System.out.println("i = " + i + " j = " + j);
  7. j = 39;
  8. }
  9. private static int x1 = printInit("static Insert.x1 init");
  10. static int printInit(String s) {
  11. System.out.println(s);
  12. return 47;
  13. }
  14. }
  15. public class Beetle extends Insert {
  16. private int k = printInit("Beetle.k init");
  17. public Beetle() {
  18. System.out.println("k = " + k);
  19. System.out.println("j = " + j);
  20. }
  21. private static int x2 = printInit("static Beetle.x2 init");
  22. public static void main(String[] args) {
  23. System.out.println("Beetle constructor");
  24. new Beetle();
  25. }
  26. }
  27. // static Insert.x1 init
  28. // static Beetle.x2 init
  29. // Beetle constructor
  30. // i = 9 j = 0
  31. // Beetle.k init
  32. // k = 47
  33. // j = 39

练习

练习1

  1. class Demo {
  2. public Demo() {
  3. System.out.println("Demo");
  4. }
  5. @Override
  6. public String toString() {
  7. return "toString()";
  8. }
  9. }
  10. /**
  11. * Ex1
  12. */
  13. public class Ex1 {
  14. Demo demo;
  15. @Override
  16. public String toString() {
  17. if (demo == null) {
  18. demo = new Demo();
  19. }
  20. return demo.toString();
  21. }
  22. public static void main(String[] args) {
  23. Ex1 ex1 = new Ex1();
  24. System.out.println(ex1);
  25. }
  26. }

练习2

  1. class Cleanser {
  2. private String s = "Cleanser";
  3. public void append(String a) {
  4. s += a;
  5. }
  6. public void dilute() { append(" dilute()"); }
  7. public void apply() { append(" apply()"); }
  8. public void scrub() { append(" scrub()"); }
  9. @Override
  10. public String toString() {
  11. return s;
  12. }
  13. public static void main(String[] args) {
  14. Cleanser cleanser = new Cleanser();
  15. cleanser.dilute(); cleanser.apply(); cleanser.scrub();
  16. System.out.println(cleanser);
  17. }
  18. }
  19. /**
  20. * Detergent
  21. */
  22. public class Detergent extends Cleanser {
  23. @Override
  24. public void scrub() {
  25. append(" Detergent.scrub()");
  26. super.scrub();
  27. }
  28. public void foam() { append(" foam()");}
  29. public static void main(String[] args) {
  30. Detergent detergent = new Detergent();
  31. detergent.dilute();
  32. detergent.apply();
  33. detergent.scrub();
  34. detergent.foam();
  35. System.out.println(detergent);
  36. Cleanser.main(args);
  37. }
  38. }
  39. class NewDetergent extends Detergent {
  40. public void scrub() {
  41. append("NewDetergent");
  42. super.scrub();
  43. }
  44. public void sterilize() {
  45. append("sterilize");
  46. }
  47. public static void main(String[] args) {
  48. NewDetergent newDetergent = new NewDetergent();
  49. newDetergent.dilute();
  50. newDetergent.apply();
  51. newDetergent.scrub();
  52. newDetergent.foam();
  53. newDetergent.sterilize();
  54. System.out.println(newDetergent);
  55. Detergent.main(args);
  56. }
  57. }
  58. // Cleanser dilute() apply()NewDetergent Detergent.scrub() scrub() foam()sterilize
  59. // Cleanser dilute() apply() Detergent.scrub() scrub() foam()
  60. // Cleanser dilute() apply() scrub()

练习3 & 练习4

  1. class Art {
  2. Art() {
  3. System.out.println("Art");
  4. }
  5. }
  6. class Drawing extends Art {
  7. Drawing() {
  8. System.out.println("Drawing");
  9. }
  10. }
  11. /**
  12. * Cartoon
  13. */
  14. public class Cartoon extends Drawing{
  15. // public Cartoon() {
  16. // System.out.println("Cartoon");
  17. // }
  18. public static void main(String[] args) {
  19. new Cartoon();
  20. }
  21. }
  22. // Art
  23. // Drawing

练习5

  1. class A {
  2. A() {
  3. System.out.println("A");
  4. }
  5. }
  6. class B {
  7. B() {
  8. System.out.println("B");
  9. }
  10. }
  11. class C extends A {
  12. B b = new B();
  13. public static void main(String[] args) {
  14. new C();
  15. }
  16. }
  17. // A
  18. // B

练习6

  1. class Game {
  2. Game(int i) {
  3. System.out.println("Game" + i);
  4. }
  5. }
  6. class BoardGame extends Game {
  7. BoardGame(int i) {
  8. super(i);
  9. System.out.println("BoardGame");
  10. }
  11. }
  12. /**
  13. * Chess
  14. */
  15. public class Chess extends BoardGame {
  16. Chess() {
  17. super(11); // 去掉这条语句,会报编译错误
  18. System.out.println("Chess");
  19. }
  20. public static void main(String[] args) {
  21. new Chess();
  22. }
  23. }

练习7

  1. class A {
  2. A(int i) {
  3. System.out.println("A");
  4. }
  5. }
  6. class B {
  7. B(int i) {
  8. System.out.println("B");
  9. }
  10. }
  11. class C extends A {
  12. B b = new B(1);
  13. C() {
  14. super(2);
  15. }
  16. public static void main(String[] args) {
  17. new C();
  18. }
  19. }

练习8

  1. class Game {
  2. Game(int i) {
  3. System.out.println("Game" + i);
  4. }
  5. }
  6. class BoardGame extends Game {
  7. BoardGame() {
  8. super(1);
  9. System.out.println("BoardGame Default");
  10. }
  11. BoardGame(int i) {
  12. super(i);
  13. System.out.println("BoardGame");
  14. }
  15. }

练习9

  1. class Component1 {
  2. Component1() {
  3. System.out.println("Component1");
  4. }
  5. }
  6. class Component2 {
  7. Component2() {
  8. System.out.println("Component2");
  9. }
  10. }
  11. class Component3 {
  12. Component3() {
  13. System.out.println("Component3");
  14. }
  15. }
  16. class Root {
  17. Component1 c1 = new Component1();
  18. Component2 c2 = new Component2();
  19. Component3 c3 = new Component3();
  20. Root() {
  21. System.out.println("Root");
  22. }
  23. }
  24. class Stem extends Root {
  25. Stem() {
  26. System.out.println("Stem");
  27. }
  28. public static void main(String[] args) {
  29. new Stem();
  30. }
  31. }
  32. // Component1
  33. // Component2
  34. // Component3
  35. // Root
  36. // Stem

练习10

  1. class Component1 {
  2. Component1(int i) {
  3. System.out.println("Component1");
  4. }
  5. }
  6. class Component2 {
  7. Component2(int i) {
  8. System.out.println("Component2");
  9. }
  10. }
  11. class Component3 {
  12. Component3(int i) {
  13. System.out.println("Component3");
  14. }
  15. }
  16. class Root {
  17. Component1 c1 = new Component1(1);
  18. Component2 c2 = new Component2(2);
  19. Component3 c3 = new Component3(3);
  20. Root(int i) {
  21. System.out.println("Root");
  22. }
  23. }
  24. class Stem extends Root {
  25. Stem(int j) {
  26. super(j);
  27. System.out.println("Stem");
  28. }
  29. public static void main(String[] args) {
  30. new Stem(2);
  31. }
  32. }

练习11

  1. class DetergentDelegation {
  2. Detergent detergent = new Detergent();
  3. public void append(String a) {
  4. detergent.append(a);
  5. }
  6. public void dilute() {
  7. detergent.dilute();
  8. }
  9. public void apply() {
  10. detergent.apply();
  11. }
  12. public void scrub() {
  13. detergent.scrub();
  14. }
  15. public void foam() {
  16. detergent.foam();
  17. }
  18. public static void main(String[] args) {
  19. Detergent.main(args);
  20. }
  21. }

练习12

  1. package com.company.ch07;
  2. class Component1 {
  3. Component1(int i) {
  4. System.out.println("Component1");
  5. }
  6. void dispose() {
  7. System.out.println("Component1 dispose");
  8. }
  9. }
  10. class Component2 {
  11. Component2(int i) {
  12. System.out.println("Component2");
  13. }
  14. void dispose() {
  15. System.out.println("Component2 dispose");
  16. }
  17. }
  18. class Component3 {
  19. Component3(int i) {
  20. System.out.println("Component3");
  21. }
  22. void dispose() {
  23. System.out.println("Component3 dispose");
  24. }
  25. }
  26. class Root {
  27. Component1 c1 = new Component1(1);
  28. Component2 c2 = new Component2(2);
  29. Component3 c3 = new Component3(3);
  30. Root(int i) {
  31. System.out.println("Root");
  32. }
  33. void dispose() {
  34. System.out.println("root dispose");
  35. c1.dispose();
  36. c2.dispose();
  37. c3.dispose();
  38. }
  39. }
  40. class Stem extends Root {
  41. Stem(int j) {
  42. super(j);
  43. System.out.println("Stem");
  44. }
  45. void dispose() {
  46. System.out.println("Stem dispose");
  47. super.dispose();
  48. }
  49. public static void main(String[] args) {
  50. Stem stem = new Stem(2);
  51. try {
  52. // do something
  53. } finally {
  54. stem.dispose();
  55. }
  56. }
  57. }
  58. // Component1
  59. // Component2
  60. // Component3
  61. // Root
  62. // Stem
  63. // Stem dispose
  64. // root dispose
  65. // Component1 dispose
  66. // Component2 dispose
  67. // Component3 dispose

练习13

  1. class Plate {
  2. Plate(int i) {
  3. System.out.println("Plate");
  4. }
  5. void func(int i) {
  6. System.out.println("func int " + i);
  7. }
  8. void func(double d) {
  9. System.out.println("func double " + d);
  10. }
  11. void func(String s) {
  12. System.out.println("func string " + s);
  13. }
  14. }
  15. class DinnerPlate extends Plate {
  16. DinnerPlate(int i) {
  17. super(i);
  18. System.out.println("DinnerPlate");
  19. }
  20. void func(char c) {
  21. System.out.println("func char " + c);
  22. }
  23. public static void main(String[] args) {
  24. DinnerPlate dinnerPlate = new DinnerPlate(1);
  25. dinnerPlate.func('c');
  26. dinnerPlate.func("hello");
  27. dinnerPlate.func(1);
  28. dinnerPlate.func(1.0);
  29. }
  30. }
  31. // Plate
  32. // DinnerPlate
  33. // func char c
  34. // func string hello
  35. // func int 1
  36. // func double 1.0

练习14

  1. package com.company.ch07;
  2. class Engine {
  3. public void start() {}
  4. public void rev() {}
  5. public void stop() {}
  6. void service() {}
  7. }
  8. class Wheel {
  9. public void inflate(int psi) {}
  10. }
  11. class Window {
  12. public void rollup() {}
  13. public void rolldown() {}
  14. }
  15. class Door {
  16. public Window window = new Window();
  17. public void open() {}
  18. public void close() {}
  19. }
  20. public class Car {
  21. public Engine engine = new Engine();
  22. public Wheel[] wheels = new Wheel[4];
  23. public Door left = new Door(), right = new Door();
  24. public Car() {
  25. for (int i = 0;i < 4; i++) {
  26. wheels[i] = new Wheel();
  27. }
  28. }
  29. public static void main(String[] args) {
  30. Car car = new Car();
  31. car.left.window.rollup();
  32. car.right.window.rolldown();
  33. car.wheels[0].inflate(72);
  34. car.engine.service();
  35. }
  36. }

练习15

  1. package com.company.ch05;
  2. public class Test {
  3. protected void func() {}
  4. }
  1. package com.company.ch07;
  2. import com.company.ch05.*;
  3. public class Ex15 extends Test{
  4. public static void main(String[] args) {
  5. Ex15 ex15 = new Ex15();
  6. ex15.func();
  7. }
  8. }

练习16

  1. class Amphibian {
  2. void func() {
  3. }
  4. static void test(Amphibian amphibian) {
  5. amphibian.func();
  6. }
  7. }
  8. public class Frog extends Amphibian {
  9. public static void main(String[] args) {
  10. Frog frog = new Frog();
  11. Amphibian.test(frog);
  12. }
  13. }

练习17

  1. class Amphibian {
  2. void func() {
  3. System.out.println("Amphibian func");
  4. }
  5. static void test(Amphibian amphibian) {
  6. amphibian.func();
  7. }
  8. }
  9. public class Frog extends Amphibian {
  10. @Override
  11. void func() {
  12. System.out.println("Frog func");
  13. }
  14. public static void main(String[] args) {
  15. Frog frog = new Frog();
  16. Amphibian.test(frog);
  17. }
  18. }
  19. // Frog func

练习18

  1. public class Ex18 {
  2. static Random random = new Random(12);
  3. final int i = random.nextInt(12);
  4. static final int j = random.nextInt(12);
  5. public static void main(String[] args) {
  6. Ex18 ex18 = new Ex18();
  7. System.out.println("ex18.i = " + ex18.i);
  8. System.out.println("ex18.j = " + ex18.j);
  9. Ex18 ex181 = new Ex18();
  10. System.out.println("ex181.i = " + ex181.i);
  11. System.out.println("ex181.j = " + ex181.j);
  12. }
  13. }
  14. // ex18.i = 8
  15. // ex18.j = 6
  16. // ex181.i = 4
  17. // ex181.j = 6

练习19

  1. public class Ex19 {
  2. final int k;
  3. Ex19() {
  4. k = 1; // 必须赋值
  5. // k = 2; // 会报错
  6. }
  7. public static void main(String[] args) {
  8. Ex19 ex19 = new Ex19();
  9. // ex19.k = 1; // 会报错
  10. }
  11. }

练习20

  1. package com.company.ch07;
  2. class WithFinal {
  3. private final void f() {
  4. System.out.println("WithFinal.f()");
  5. }
  6. private void g() {
  7. System.out.println("WithFinal.g()");
  8. }
  9. }
  10. class OverridingPrivate extends WithFinal {
  11. // @Override //加上注解后编译错误
  12. private final void f() {
  13. System.out.println("OverridingPrivate.f()");
  14. }
  15. // @Override //加上注解后编译错误
  16. private void g() {
  17. System.out.println("OverridingPrivate.g()");
  18. }
  19. }
  20. class OverridingPrivate2 extends OverridingPrivate {
  21. // @Override //加上注解后编译错误
  22. public final void f() {
  23. System.out.println("OverridingPrivate2.f()");
  24. }
  25. // @Override //加上注解后编译错误
  26. public void g() {
  27. System.out.println("OverridingPrivate2.g()");
  28. }
  29. }
  30. public class FinalOverridingIllusion extends OverridingPrivate2 {
  31. public static void main(String[] args) {
  32. OverridingPrivate2 overridingPrivate2 = new OverridingPrivate2();
  33. overridingPrivate2.f();
  34. overridingPrivate2.g();
  35. OverridingPrivate overridingPrivate = overridingPrivate2;
  36. // overridingPrivate.f(); 无法调用
  37. // overridingPrivate.g();
  38. WithFinal withFinal = overridingPrivate;
  39. // withFinal.f(); 无法调用
  40. // withFinal.g();
  41. }
  42. }

练习21

  1. package com.company.ch07;
  2. class Final {
  3. final void f() {}
  4. }
  5. public class Ex21 extends Final {
  6. void f() {} // 编译出错
  7. }

练习22

  1. package com.company.ch07;
  2. final class FinalClass {
  3. }
  4. public class Ex22 extends FinalClass { //编译出错
  5. }

练习23

  1. class Insert {
  2. private int i = 9;
  3. protected int j;
  4. Insert() {
  5. System.out.println("i = " + i + " j = " + j);
  6. j = 39;
  7. }
  8. private static int x1 = printInit("static Insert.x1 init");
  9. static int printInit(String s) {
  10. System.out.println(s);
  11. return 47;
  12. }
  13. }
  14. public class Beetle extends Insert {
  15. private int k = printInit("Beetle.k init");
  16. public Beetle() {
  17. System.out.println("k = " + k);
  18. System.out.println("j = " + j);
  19. }
  20. private static int x2 = printInit("static Beetle.x2 init");
  21. public static int x3 = 3;
  22. public static void main(String[] args) {
  23. System.out.println("Beetle constructor");
  24. new Beetle();
  25. }
  26. }
  27. class Ex23 {
  28. public static void main(String[] args) {
  29. new Beetle();
  30. // static Insert.x1 init
  31. // static Beetle.x2 init
  32. // i = 9 j = 0
  33. // Beetle.k init
  34. // k = 47
  35. // j = 39
  36. // or
  37. // System.out.println(Beetle.x3);
  38. // static Insert.x1 init
  39. // static Beetle.x2 init
  40. // 3
  41. }
  42. }

练习24

  1. class Insert {
  2. private int i = 9;
  3. protected int j;
  4. Insert() {
  5. System.out.println("i = " + i + " j = " + j);
  6. j = 39;
  7. }
  8. private static int x1 = printInit("static Insert.x1 init");
  9. static int printInit(String s) {
  10. System.out.println(s);
  11. return 47;
  12. }
  13. }
  14. public class Beetle extends Insert {
  15. private int k = printInit("Beetle.k init");
  16. public Beetle() {
  17. System.out.println("k = " + k);
  18. System.out.println("j = " + j);
  19. }
  20. private static int x2 = printInit("static Beetle.x2 init");
  21. public static int x3 = 3;
  22. public static void main(String[] args) {
  23. System.out.println("Beetle constructor");
  24. new Beetle();
  25. }
  26. }
  27. class Ex24 extends Beetle {
  28. public static void main(String[] args) {
  29. new Ex24();
  30. // static Insert.x1 init
  31. // static Beetle.x2 init
  32. // i = 9 j = 0
  33. // Beetle.k init
  34. // k = 47
  35. // j = 39
  36. }
  37. }
  1. 调用 Ex24 的main函数(静态方法),准备加载 Ex24,但是发现其继承与 Beetle
  2. 准备加载 Beetle,但是发现其继承与 Insert,因此先加载 Insert
  3. Insert 中的静态数据先初始化,所以会输出static Insert.x1 init
  4. Insert 加载并初始化完后,加载 Beetle 并对静态数据进行初始化,所以会输出static Beetle.x2 init
  5. 然后加载 Ex24,加载过程完成,调用 main 函数
  6. new Ex24时,实例化的顺序为 Insert -> Beetle -> Ex24
  7. 所以先输出 Insert 构造函数中的 i = 9 j = 0,之所以 j 为0,是因为int默认值为0
  8. 然后在实例化 Beetle 时,先会执行 实例初始化,即private int k = printInit("Beetle.k init");
  9. 最后才是 Beetle 的构造函数。

    首发与Code & Fun

《 Java 编程思想》CH07 复用类的更多相关文章

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

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

  2. Java编程思想之七复用类

    复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须做更多的事情. 使用类而不破坏程序代码: 在新类中产生现有对象.由于新的类是由现有 ...

  3. Java编程思想学习笔记——类的访问权限

    类的访问权限 Java中,访问权限修饰词用于确定库中哪些类对于该库的使用者是可用的. public class Foo{ } 注意点: 每个文件(编译单元)只能有一个public类. public类的 ...

  4. Java编程思想:File类list()方法

    import java.util.regex.Pattern; import java.io.File; import java.io.FilenameFilter; public class Tes ...

  5. Java编程思想:File类其他方法

    import java.io.File; public class Test { public static void main(String[] args) { MakeDirectories.te ...

  6. Java编程思想:嵌套类

    public class Test { public static void main(String[] args) { // Parcell11.test(); // ClassInterface. ...

  7. Java编程思想:File类getCanonicalFile()方法,listFile()方法

    import java.io.IOException; import java.util.*; import java.util.regex.Pattern; import java.io.File; ...

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

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

  9. 33.JAVA编程思想——JAVA IO File类

    33.JAVA编程思想--JAVA IO File类 RandomAccessFile用于包括了已知长度记录的文件.以便我们能用 seek()从一条记录移至还有一条:然后读取或改动那些记录. 各记录的 ...

  10. Java编程思想 (1~10)

    [注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第一章 对象导论 1.万物皆对象2.程序就是对象的集合3.每个对象都是由其它对象所构成 ...

随机推荐

  1. Phpstorm 2020-01-04试了可用的激活码【亲测可用】WebStrom

    [直接点击试用30天] http://myphp.vip/ 测试时间:2018-10-12可用(v2019.2) 测试时间:2019-12-24可用(v2019.2) 测试时间:2020-01-04可 ...

  2. Linux /etc/network/interfaces

    Linux下/etc/network/interfaces文件用来配置网络接口. 1. 使用动态IP地址 auto eth0 iface eth0 inet dhcp 2. 使用静态IP地址 auto ...

  3. C# WPF联系人列表(1/3)

    微信公众号:Dotnet9,网站:Dotnet9,问题或建议:请网站留言, 如果对您有所帮助:欢迎赞赏. C# WPF联系人列表(1/3) 阅读导航 本文背景 代码实现 本文参考 1.本文背景 聊天软 ...

  4. spring cloud微服务快速教程之(八) Spring Cloud Alibaba--nacos(二)、配置中心

    0-前言 上一篇我们介绍了nacos作为服务注册发现组件的功能,nacos还具有配置中心的功能,而且支持热加载: 在此之前,配置中心有Spring Cloud Config,实际上,用这个有很多风险和 ...

  5. Umi 小白纪实(一)—— 创建项目&常用配置

    umi 是一个企业级 react 应用框架,也是蚂蚁金服的底层前端框架 <蚂蚁金服的前端框架和工程化实践> 一.安装脚手架 在创建项目之前,需要保证有 node 8.10 以上的环境 可以 ...

  6. css字体样式+文本样式

    font-family属性值:具体字体名或者字体集 如果是中文或者有单词之间有空格,需要加双引号 字体集: Serif (有装饰线) Sans-serif (无装饰线) Monospace Cursi ...

  7. 【Git】git使用 - rebase的使用

    官方参考指南: Pro Git Book v2, § rebasing. English Pro Git Book v2, § rebase:衍合. 中文版 (建议还是看一下英文原版,就当熟练英语.) ...

  8. Wannafly Winter Camp 2020 Day 6A Convolution - NTT

    求 \(\sum_{i=1}^n \sum_{j=1}^n 2^{a_ia_j}\) Solution 化简一下 \[ 2^{a_ia_j} = p^{(a_i+a_j)^2-a_i^2-a_j^2} ...

  9. Lucene使用IKAnalyzer分词

    1.分析器    所有分析器最终继承的类都是Analyzer        1.1 默认标准分析器:StandardAnalyzer            在我们创建索引的时候,我们使用到了Index ...

  10. Android数据存储之SD卡文件操作

    赶上智能手机刚问世时有幸用过的小伙伴都知道,那时候的Android系统是把我们自己买的SD卡作为外部存储的,但是不知道从哪天开始,SD卡就被固化到智能手机的内部了,但是我们仍然把它称为外部存储.我想A ...