写在前面:
转载自:知乎 飞爱学习 作者:一个敲代码的汽车人
原文链接:https://zhuanlan.zhihu.com/p/139018397
这篇主要讲 重载overload 、封装Encapsulation。也是工程化的设计思想的产物。
1 类(Class)、对象(Object)和构造器(Constructor)
1.1 案例
要求设计一个矩形的面积计算器,输入为矩形的高(height)和宽(width),输出为矩形的面积(area)。
1.2 代码
对JAVA的语法有最基本的了解后可以写出如下代码:
class Rectangle{ //创建矩形类
public double height; //定义类的成员变量
public double width;
public Rectangle() { //定义无参构造器--可省略
}
public void calcuArea() { //定义类的方法--面积计算
System.out.println("面积为:"+height*width);
}
}
public class Test{
public static void main(String[] args) {
Rectangle rec=new Rectangle(); //创建矩形对象--调用构造器
rec.height=1; //高度赋值
rec.width=2; //宽度赋值
rec.calcuArea(); //调用面积计算方法
}
}
1.3 代码分析
以上代码包含以下概念:
1、类(Class):类是构造对象的模板或蓝图,其由成员变量和方法构成,前者记录数据,后者记录数据的操作过程。
2、对象(Object):对象是类的实例化,一个类可以有多个对象。
3、构造器(Constructor):构造器是一种特殊的方法,用于对象实例化时的初始化操作。
注意:
- 构造器总是和关键字“new”一起使用。
- 构造器的方法名必须和类名一致!
- 任意一个类都包含至少一个构造器,当没有自定义构造器时,编译器会自动设定为无参构造器;但如果自定义了有参构造器,并需要调用无参构造器时,就必须自己手动写。
- 构造器中,this()用于调用同一类中的其他构造方法;super()用于调用父类的构造方法。都必须位于构造方法中的第一行,且两者不能同时存在。
思考:以上代码虽然实现了基本功能,但其功能不够完善,比如当用户输入的高度和宽度为字符串时,代码就会报错,那怎么才能在不给用户输入添加麻烦的情况下实现功能呢?
2 重载(Overload)
2.1 案例
要求设计一个矩形的面积计算器,输入为矩形的高和宽(数字或者字符串输入,假定用户输入的字符串都是数值型字符串),输出为矩形的面积。
2.2 代码
class Rectangle{
public double height;
public double width;
//定义无参构造器--可省略
public Rectangle() {
}
//定义有参构造器1
public Rectangle(double height,double width) {
this.height=height; //this指代当前对象,用于区分方法中的形参
this.weight=width;
}
//定义有参构造器2
public Rectangle(String height,String width) {
this.height=Double.valueOf(height);
this.weight=Double.valueOf(width);
}
public void calcuArea() {
System.out.println("面积为:"+height*width);
}
}
public class Test{
public static void main(String[] args) {
Rectangle rec=new Rectangle(1,2); //创建矩形对象--调用构造器1
rec.calcuArea(); //调用面积计算方法
Rectangle rec1=new Rectangle("1","2"); //创建矩形对象--调用构造器2
rec1.calcuArea(); //调用面积计算方法
}
}
2.3 代码分析
以上代码包含以下概念:
重载(Overload):指类中多个方法具有相同的名字,但参数类型或返回类型不同的现象。重载的设定是为了方便用户操作,以相同的方法名实现特定的功能,同时匹配不同的参数类型以满足功能的扩展性和需求的多样性。在上面的代码中我们实现了构造器方法的重载,完美解决了用户输入多样性的问题,但重载并不局限于构造器方法,它可以适用于类中的任何方法。
注意:
- 不允许方法名和参数类型相同,但返回类型不同的情况出现,因为程序无法判断返回哪一个。
- 方法的形参类型相同但顺序不同也构成重载,如add(double a,int b)和add(int a,double b)。
思考:以上代码虽然解决了之前提出的问题,但是仍存在一个巨大的安全隐患,即用户可以直接通过“rec.height”和“rec.width”对矩形的高和宽赋值,这会导致两个我们不愿意看到的情景。一是,当用户输入非常规数值(比如-1)时,计算的结果是没有意义的;二是,后期更改程序时难以维护,比如我们后期要将height的变量类型改为String类型,那么就必须更改每一处height赋值的地方(如代码1.2)。那么,如何改进呢?
3 封装(Encapsulation)
3.1 案例
要求设计一个矩形的面积计算器,输入为矩形的高和宽(数值输入),且数值都应大于零,输出为矩形的面积。同时要避免2.3中所述的问题。
3.2 代码
class Rectangle{
private double height; //私有化实例字段
private double width;
public void setHeight(double height) { //定义更改器方法
if (height<0) {
this.height =0;
}
else {
this.height = height;
}
}
public void setWidth(double width) {
if (width<0) {
this.width =0;
}
else {
this.width = width;
}
}
public double getHeight() { //定义访问器方法
return height;
}
public double getWidth() {
return width;
}
public void calcuArea() {
System.out.println("面积为:"+height*width);
}
}
public class Test{
public static void main(String[] args) {
Rectangle rec=new Rectangle();
rec.setHeight(-1); //设定高
rec.setWidth(2); //设定宽
rec.calcuArea();
//读取高和宽
System.out.println("高为:"+rec.getHeight()+" 宽为:"+rec.getWidth());
}
}
3.3 代码分析
以上代码包含以下概念:
封装(Encapsulation):通过私有化类的成员变量,并创建相应的公有化的更改器(即设定成员变量的独立方法,如setHeight)和访问器(即读取成员变量的独立方法,如getHeight)实现对成员变量的封装。
设计用意:
- 成员变量私有化的设计,使用户无法通过“rec.height”和“rec.width”对矩形的高和宽赋值与读取。
- 更改器和访问器公有化的设计,使用户可以随意调用,实现对成员变量的赋值与读取。
- 在更改器中我们可以设定数值规范,避免因用户的错误输入所带来的问题。
- 在后期调试中,我们只需要改写类的成员变量类型及相应的更改器便可,无需修改每个实例化对象的相关代码。
4 参考文献
[1]《Head First Java(第二版·中文版)》
[2]《Java核心技术·卷 I(原书第11版)》
[3] 菜鸟教程:https://www.runoob.com/java/j...
[4] 速学堂:https://www.sxt.cn/Java_jQuer...