8. 再谈初始化
上一篇文章有讲过代码块,我们简单回顾一下几个重要的代码块:实例代码块和静态代码块。
我们看这段代码:
//Dog_.java class Dog_ { public String name; public int age; public Dog_(String name, int age) { this.name = name; this.age = age; System.out.println("构造方法执行"); } { System.out.println("实例代码块执行"); } static { System.out.println("静态代码块执行"); } }
//Test.java public class Test { public static void main(String[] args) { Dog_ dog1 = new Dog_("Peter",3); System.out.println("============================"); Dog_ dog2 = new Dog_("Jack",1); } }
🍤 运行结果:
说明:
- 静态代码块先执行,并且只执行一次,在类加载阶段执行
- 当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行
继承关系上的执行顺序:
//Person.java class Person { public String name; public int age; public Person(String name, int age) { this.name = name; this.age = age; System.out.println("Person:构造方法执行"); } { System.out.println("Person:实例代码块执行"); } static { System.out.println("Person:静态代码块执行"); } }
//Student.java class Student extends Person{ public Student(String name,int age) { super(name,age); System.out.println("Student:构造方法执行"); } { System.out.println("Student:实例代码块执行"); } static { System.out.println("Student:静态代码块执行"); } }
//Test1.java public class Test1 { public static void main(String[] args) { Student student1 = new Student("张三",19); System.out.println("==========================="); Student student2 = new Student("李四",20); } }
🍤 运行结果:
通过分析执行结果,得出以下结论:
- 父类静态代码块优先于子类静态代码块执行,且是最早执行
- 父类实例代码块和父类构造方法紧接着执行
- 子类的实例代码块和子类构造方法紧接着再执行
- 第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行
9. protected 关键字
在类和对象章节中,为了实现封装特性,Java中引入了访问限定符,主要限定:类或者类中成员能否在类外或者其他包中被访问。
范围 | private | default | protected | public |
同一包的同一类 | √ | √ | √ | √ |
同一包的不同类 | √ | √ | √ |
不同包中的子类 | √ | √ | ||
不同包中的非子类 | √ |
10. 继承方式
Java中的几种继承方式:
Java中不支持多继承
一般不要出现超过三层的继承关系。如果继承层次太多,就需要考虑对代码进行重构。
如果想从语法上进行限制继承,就可以使用 final 关键字。
11. final 关键字
final关键可以用来修饰变量、成员方法以及类。
1.修饰变量或字段,表示常量(即不能修改)
final int a = 10; a = 20; // 编译出错
2.修饰类:表示此类不能被继承
final public class Animal { ... } public class Bird extends Animal { ... } // 编译出错 Error: 无法从最终com.bit.Animal进行继
平时是用的 String 字符串类,就是用 final 修饰的,不能被继承
3.修饰方法:表示该方法不能被重写
12. 继承与组合
和继承类似,组合也是一种表达类之间关系的方式,也是能够达到代码重用的效果。组合并没有涉及到特殊的语法(诸如 extends 这样的关键字),仅仅是将一个类的实例作为另外一个类的字段。
继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物。
组合表示对象之间是has-a的关系,比如:汽车。
汽车和其轮胎、发动机、方向盘、车载系统等的关系就应该是组合,因为汽车是有这些部件组成的。
// 轮胎类 class Tire{ // ... } // 发动机类 class Engine{ // ... } // 车载系统类 class VehicleSystem{ // ... } class Car{ private Tire tire; // 可以复用轮胎中的属性和方法 private Engine engine; // 可以复用发动机中的属性和方法 private VehicleSystem vs; // 可以复用车载系统中的属性和方法 // ... } // 奔驰是汽车 class Benz extend Car{ // 将汽车中包含的:轮胎、发送机、车载系统全部继承下来 }
组合和继承都可以实现代码复用,应该使用继承还是组合,需要根据应用场景来选择,一般建议:能用组合尽量用 组合。