4.1 类的封装
封装指的是将东西包装在一起,然后以新的完整形式呈现。包含两个意义:
1). 把对象的全部属性和方法结合在一起,形成一个不可分割的独立单位(即对象)。
2). 信息隐藏,即尽可能隐藏对象的内部细节,对外形成一个边界(或者说形成一道屏障),只保留有限的对外接口使之与外部发生联系。
封装的好处之一就是可以隐藏信息。“信息隐藏”是一种强大的技术工具,因为它能降低程序的复杂性。在创建类时,根据完成任务的需要创建许多属性和方法,而只有可被其他人访问的那些属性和方法才对外公开。
实现封装的步骤:
1).修改属性的可见性来限制对属性的访问
2).为每个属性创建一对赋值方法和取值方法,用于对这些属性的访问
3).在赋值和取值方法中,降入对属性的存取限制
package aaa; public class Teacher { private int age; public int getAge() { return age; } public void setAge(int myage) { if(age < 23) { System.out.println("Wrong!"); this.age = 23; } else age = myage; } public void introduceMy() { System.out.println("Hello, everyone, I'm a teacher, " + age + "years old."); } public static void main(String[] args) { Teacher t = new Teacher(); t.setAge(10); t.introduceMy(); } }
4.2 类的继承
通过继承可实现代码复用。Java中所有的类都是通过直接或间接地继承 java.lang.Object类得到的。子类可以重写父类的方法,或命名与父类同名的成员变量。但Java不支持多重继承,即一个类有且仅有一个父类。
4.2.1 继承的实现:
通过extends关键字。子类可以继承父类中访问权限设定为public、protected、default的成员变量和方法,但是不能继承访问权限为private的成员变量和方法。语法如下:
class SubClass [extends SuperClass] { ... // 子类体 }
类继承示例:
package aaa; class Box{ double width; double height; double depth; Box(){ // 无参构造函数 width = -1; height = -1; depth = -1; } Box(double w, double h, double d){ // 有参构造函数 width = w; height = h; depth = d; } double volume() { // 计算体积 return width * height * depth; } } class BoxWeight extends Box{ // BoxWeight 继承父类 Box double weight; BoxWeight(double w, double h, double d, double m){ width = w; height = h; depth = d; weight = m; // 子类特有的属性 } } public class DemoBoxWeight { public static void main(String[] args) { BoxWeight mybox = new BoxWeight(10,20,15,34.3); // 初始化子类对象mybox double vol; vol = mybox.volume(); System.out.println("volume: " + vol); System.out.println("weight: " + mybox.weight); } }
4.2.2 对象初始化的顺序
通常在实现子类的构造方法时,先调用父类的构造方法。在实现子类的 finalize()方法时,最后调用父类的 finalize()方法。即初始化过程总是由高级向低级进行,而资源回收过程则从低级向高级进行。
值得注意的是,当子类中没有显式定义构造方法时,会自动调用父类中无参的构造方法作为自己的构造方法来使用。
4.2.3 this 和 super 的使用
在Java中, this通常指当前对象, super则指父类
1). this 用法
最普遍的情况就是,在方法中某个形参名与当前对象的某个成员有相同的名字。
2). super 用法
当子类继承父类时,其成员变量和方法有可能与父类相同,当需要区分它们时,就可以在子类中使用关键字 super 来实现。
·用来访问父类被隐藏的成员变量。格式为: super.variable
·用来调用父类中被重写的方法。格式为: super.method( [paramlist] );
·用来调用父类的构造方法。格式为: super( [paramlist] );
4.3 类的多态
在Java语言中,多态性体现在两个方面:由方法重载实现的静态多态性(编译时多态)和由方法重写实现的动态多态性(运行时多态)。
1).编译时多态。在编译阶段,具体调用哪个被重载的方法,编辑器会根据参数的不同来静态确定调用相应的方法。
2).运行时多态。由于子类继承了父类所有的属性(私有的除外),所以子类对象可以作为父类对象使用。
4.3.1 方法的重载
当两个方法名称相同而参数项不同时,那么认为此方法被重载,而此过程为“方法重载”。
调用重载方法时,Java将尝试调用一个参数类型和数量与此方法的参数类型和数量相匹配的方法。如果不完全匹配,Java的自动类型转换将解决此问题并调用正确的重载方法。
另外,Java也支持对构造方法的重载,这样一个类就可以有多个同名不同参的构造方法。当用new运算符来创建一个类的对象时,编译器会根据所提供的的参数个数以及类型来区分调用哪个构造方法。
public class DisplayNumber { void display() { System.out.println("无参方法!"); } void display(int num1, int num2) { System.out.println("整型方法,两参数值为:" + num1 + " " + num2); } void display(double count) { System.out.println("浮点方法,参数值为:" + count); } public static void main(String [] args) { DisplayNumber dispObj = new DisplayNumber(); dispObj.display(); dispObj.display(30, 40); dispObj.display(30.5); } }
4.3.2 方法的覆盖
在类层次结构中,当子类的成员变量与父类的成员变量同名时,子类的成员变量会隐藏父类的成员变量;当子类的方法与父类的方法具有相同的名字、参数列表、返回值类型时,子类的方法就叫做重写了父类的方法,当重写的方法被子类的对象调用时,它总是参考在子类中定义的版本,在父类中定义的方法就被隐藏。
class Square { int length; Square(int len) { length = len; } void getPerimter() { System.out.println("正方形的周长为 " + (4 * length)); } } class Rectangle extends Square { int width; Rectangle(int len, int wid) { super(len); width = wid; } void getPerimter() { System.out.println("长方形的周长为: " + (2 * (length + width))); } } public class CalculatePerimeter { public static void main(String [] arge) { Square sqObj = new Square(10); sqObj.getPerimter(); Square rectObj = new Rectangle(10,12); rectObj.getPerimter(); } }