封装、继承、多态是面向对象的三大特征,继承是实现类重用的重要手段,但是继承会带来一个最大的坏处,那就是破坏
封装。因此接下来介绍组合,组合是实现类重用的重要方式,能提供更好的封装性。
子类扩展父类的时候,可以从父类那里继承得到Field和方法,假设现在我们有足够的权限,那么子类就可以直接复用父
类的Field和方法,但继承在带来高度复用的同时,也带来了一个严重的问题,继承严重的破坏了父类的封装性。在封装
时,我们应该遵守这个原则:每个类都应该封装它内部信息和实现细节,而只暴露必要的方法给其他类使用。但通过继
承关系,子类可以直接访问父类的Field和方法,因此造成子类和父类的严重耦合。也就是说,父类的实现细节对子类不
再透明,子类可以访问父类的Field和方法,并且可以改变父类方法的实现细节,导致子类可以恶意更改父类的方法。
在保证父类有良好的封装性,不会被子类随意更改,我们在设计父类时通常遵循以下规则:
1、尽量隐藏父类的内部数据。尽量把父类的所有Field都设置成private访问类型,不要让子类直接访问父类的Field。
2、不要让子类随意访问、修改父类的方法。如果父类中存在的是一些为辅助其他的工具方法,应该使用private访问控制
符修饰,让子类无法访问该方法;如果父类中的方法需要被外部类调用,则用public修饰,但又不希望子类重写该方法,
可以使用final修饰符;如果希望父类的某个方法被子类重写,但不希望被其他类自由访问,可以使用protected来修饰该
方法。
3、尽量不要在父类构造器中调用将要被子类重写的方法。
至于何时需要从父类派生新的子类?不单单需要保证子类是一个特殊的父类,而且需要具备以下两个条件之一:
1、子类需要额外增加属性,而不仅仅是属性值的改变。
2、子类需要增加自己独有的行为方式,包括增加新的方法或重写父类的方法。
面对继承带来的种种问题,如果只是出于类的复用的目的,并不一定需要使用继承。我们可以使用组合来实现。
如果需要复用一个类,除了把这个类当成基类来继承之外,还可以把该类当成另一个类的组合部分,从而允许新类直接
复用该类的public方法。使用组合可以把旧类对象作为新类的Field嵌入,用来实现新类的功能,因此,通常需要在新类里
使用private修饰被嵌入的旧类对象。比如以下代码:
class Computer{ public void cpu(){ System.out.println("计算机有CPU"); } } class Cpu{ private Computer computer; public Cpu(Computer computer){ this.computer=computer; } public void cpu(){ computer.cpu(); } } public class ComputTest { public static void main(String[] args) { Cpu cpu=new Cpu(new Computer()); cpu.cpu(); } }
总结以上内容,通常情况下,继承关系是从中多个子类里抽象出共有父类的过程,类似于组合关系中从多个整体类里提取嵌入类的过程;继承关系中从父类派生子类的过程,类似于组合关系中把嵌入类对象组合成整体类的过程。总之,继承是一种“是(is-a)”的关系,组合表示的是“有(has-a)”的关系。
在Java中除了使用构造器类对单个对象进行初始化操作外,我们还可以通过初始化块来实现。在一个类中可以有多个初始化块,相同类型的初始化块之间有顺序:前面定义的初始化块先执行,后面定义的初始化块后执行。使用static修饰的初始化块,称为静态初始化块,在初始化块中可以定义局部变量、调用其他对象的方法,以及使用分支、循环语句等。下面程序就定义了初始化块:
class Person{ { int num=25; System.out.println("普通初始化块1"); } static{ int num=45; System.out.println("静态初始化块"); } { int num=25; System.out.println("普通初始化块2"); } public Person(){ System.out.println("无参构造器"); } } public class MainTest { public static void main(String[] args) { new Person(); } }
输出结果如下:
静态初始化块
普通初始化块1
普通初始化块2
无参构造器
从运行结果可以看出,当创建Java对象时,系统总是先调用静态初始化块,之后按顺序执行普通初始化块,最后才执行
构造器。静态初始化块是类相关的,用于对整个类进行初始化处理,静态初始化块也被称为类初始化块,也属于类的静
态成员,因此不能访问非静态成员。
最后值得指出的是:当JVM第一次主动使用某个类时,系统会在类准备阶段为该类的所有静态Field分配内存,在初始化
阶段负责初始化这些静态Field,初始化静态Field就是执行类初始化代码或者声明类Field时指定的初始值。关于类加载请
参看”Java类加载笔记(1)“
转载请注明出处:http://blog.csdn.net/hai_qing_xu_kong/article/details/43876627
情绪控_