封装十分有用,可以将一些数据信息封装起来,或者隐藏,或者做一些额外的限制操作,而这部分的行为都在内部来进行,对外只保留了适当的接口来提供调用,而类内部的各种信息可以自动修改达到很轻松可控的效果
有一个简单的Girl类
class Girl {
public String name;
public int age;
public int id;
}
类有三个成员变量,分别是姓名,年龄和工号
对于每个新来的员工,都会这样来使用(Girl obj).id来进行操作工号,类型都是int
Girl girl = new Girl();
girl.id = 6666;
如果有一天,公司大幅度扩张,疯狂招人,int工号都不够用了(太疯狂!),担心long有一天也会不够用,直接修改成员变量的类型为String,如此一来就变成这样了
class Girl {
public String name;
public int age;
public String id;
}
这下就尴尬了,其它在调用(Girl obj).id的地方,都会因为数据类型的修改,无法编译通过;还需要一个一个修改或者做转换,多加思索就觉得设计方式就有所欠妥,因为Girl类对于我的使用可扩展性太差,看看封装的效果
一开始的Girl类设计成如下
class Girl {
private String name;
private int age;
private int id;
public String getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
可以看到这种设计方法,将成员变量置为private的,提供public的get和set方法来控制获取和存储操作,此时要用id信息的地方,在这种情形下,存和取的方式如下
Girl girl = new Girl();
girl.setId(6666);
System.out.println(girl.getId());
通过这种方式,能够很安全的对数据进行存和取,或者暂时看不出来封装的优势,再回到上面的问题,假如int工号不够用,要将成员变量修改成String类型,而此时实例调用中setId里面依旧都是int类型,想要兼容现有所有人的用法,很自然的想法就是在setId方法里将传入的int类型做一下类型转换,让getId方法返回String类型,就达到目的了,整个如下
class Girl {
private String name;
private int age;
private String id;
public String getId() {
return id;
}
public void setId(int id) {
this.id = String.valueOf(id);
}
}
public class Main {
public static void main(String[] args) {
Girl girl = new Girl();
girl.setId(6666);
System.out.println(girl.getId());
}
}
仔细酝酿一下就会发现所有通过setId存和getId取的地方,就算传入的是int类型,都不需要做任何修改(如果有其它int类型加减等运算应当自行处理),但就这个例子而言,还有一个问题,都已经说过了,此处的int工号已经无法满足了,虽然转换成了String类型,但setId方法传入的还是int类型,因此新来的员工还是无法适配这里,为了眼前兼容,改成long即可
class Girl {
private String name;
private int age;
private String id;
public String getId() {
return id;
}
public void setId(long id) {
this.id = String.valueOf(id);
}
}
public class Main {
public static void main(String[] args) {
Girl girl = new Girl();
girl.setId(2222222222L);
System.out.println(girl.getId());
}
}
通过这个例子,就很通俗易懂地发现封装的一些好处,可以自定义地添加一些限制条件,再比如像有些公司,不招聘40岁以上的员工
class Girl {
private String name;
private int age;
private String id;
public String getId() {
return id;
}
public void setId(long id) {
this.id = String.valueOf(id);
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 40) {
System.out.println("NO NEED");
} else {
this.age = age;
}
}
}
假如说妹纸的年龄在30到40岁之间是保密的
class Girl {
private String name;
private int age;
private String id;
public String getId() {
return id;
}
public void setId(long id) {
this.id = String.valueOf(id);
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 40) {
System.out.println("NO NEED");
} else if (age > 30) {
System.out.println("Secret");
} else {
this.age = age;
}
}
}
其实,还遗漏了一个比较重要的常识限制,年龄假如有人输入一个非常大的数字,显然就相当于有误的,因此可以做一下判断
class Girl {
private String name;
private int age;
private String id;
public String getId() {
return id;
}
public void setId(long id) {
this.id = String.valueOf(id);
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 200) {
System.out.println("Impossible");
} else if (age > 40) {
System.out.println("NO NEED");
} else if (age > 30) {
System.out.println("Secret");
} else {
this.age = age;
}
}
}
从这些例子可以看出,类里可以自行进行把控,而这些细节对于实例调用的时候是不需要可见的
通过setter能够做一切可以进行的检查操作,还可以跑出Exception异常,始终记着将类成员变量设置为私有,然后提供公有的getter和setter来进行存取操作,可以保证安全性
