从接触Java到现在一年多了,随着代码量的累积,愈发的觉得有种迫切的心理,往深处去学习,然后就想着从头开始,借着Java编程思想、Java核心技术、Effective Java以及网络上的文章,对知识进行整合再输出,重新梳理之前囫囵咽下去的知识点,打牢基础的同时也做出一点自己的贡献。
我们都知道,面向对象的几个特性——封装、继承、多态,从字面的来看,封就是隐藏信息,装就是统一提供查看/修改方法,专业点的解释就是将信息隐藏,然后利用抽象的数据结构将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被隐藏在抽象数据类型的内部,尽可能的隐藏内部细节,只暴露一些可供外部接口访问/操作的接口。用户在不知道知道对象内部的实现细节情况下,仍然可以通过接口访问该对象,这样也可以方便我们在用户无感知的情况下做出些修改。
所以通过上面那段话,我们不难总结出来,封装需要我们做以下几件事情:
1.将想隐藏的数据定义为私有的数据域;
2.提供公有的域访问器方法;
3.提供公有的域更改器方法。
对于封装而言,一个对象所封装的是自己的属性和方法,所以它是不需要依赖其他对象就可以完成自己的操作。
使用封装有以下好处:
1.良好的封装可以减少耦合;
2.类内部的接口可以自由修改;
3.可以对成员进行更精确的控制;
4.隐藏信息,实现细节
只是这么说似乎有些抽象,下面我们结合代码解释说明下:
封装的操作步骤与代码实现
1.将想隐藏的数据定义为私有的数据域;——修改属性的可见性(一般为private)
2.提供公有的域访问器方法;——创建getter方法
3.提供公有的域更改器方法。——创建setter方法
public class Employee{
/*
* 对属性的封装
* 一个人的姓名、性别、年龄、薪酬等都是这个人的私有属性
*/
private String name ;
private String sex ;
private int age ;
private int salary;
/*
* setter()、getter()是该对象对外开放的接口,此处省略setter、getter方法
*/
}
在这里,如果我们想隐藏某些数据,只需要去除对应的getter方法即可,外部类就无法获取到对应的数值,隐藏了信息。比如,一个员工的薪酬是私密信息,那么我们把薪酬的getter方法去掉,外界即无法知道员工的薪酬是多少。
所以封装把一个对象的属性私有化后,如果不想被访问,不提供对应的getter方法即可。
下面我们再看一个例子
如果没有getter、setter方法,我们的Employee类初始化的时候就要这么做,
Employee employee= new Employee();
employee.age = 30;
employee.name = "张三";
employee.sex = "男";
现在我们需要修改Employee类,比如讲age修改为String类型,在没有封装的情况下,我们需要对每一处初始化代码都进行修改。但是如果使用了封装,我们不需要修改代码中初始化部分,只需要修改setAge()方法即可。
public class Employee{
/*
* 对属性的封装
* 一个人的姓名、性别、年龄都是这个人的私有属性
*/
private String name ;
private String sex ;
private String age ;
private int salary;
public String getAge() {
return age;
}
public void setAge(int age) {
//转换即可
this.age = String.valueOf(age);
}
/** 省略其他属性的setter、getter **/
}
这样其他地方依然使用employee.setAge(30)不需要改变,但是类型已经改成String了。在这里,我们看到了封装对成员的精确控制。
还是那个例子,我们在初始化的时候可能会
Employee employee= new Employee();
employee.salary= -1000;
这个问题不该发生,薪酬怎么会是负的呢,但是在初始化的时候,我们不能完全杜绝。可是如果我们使用封装的话,就可以避免这个问题,因为我们可以对salary的setter方法做一个限制,比如:
public class Employee{
/*
* 对属性的封装
* 一个人的姓名、性别、年龄、薪酬都是这个人的私有属性
*/
private String name ;
private String sex ;
private int age ;
private int salary;
public int getSalary() {
return salary;
}
public void setSalary(int age) {
if(salary < 0){
System.out.println("ERROR:error age input...."); //提示错误信息
}else{
this.salary= salary;
}
}
/** 省略其他属性的setter、getter **/
}
不仅仅是setter方法,我们也可以通过封装对对象的出口(即getter方法)做出控制,例如性别我们在数据库中都是以1/0方式来存储的,但是在前台又不能展示1/0,所以我们只需要在getter方法里做一些转换即可。
比如:
public String getSexName() {
if("0".equals(sex)){
sexName = "女";
}
else if("1".equals(sex)){
sexName = "男";
}
else{
sexName = "人妖???";
}
return sexName;
}
看完上面几个例子以后,这个时候我们再回头,看最开始那段,封装的优点——
1.良好的封装可以减少耦合;
2.类内部的接口可以自由修改;
3.可以对成员进行更精确的控制;
4.隐藏信息,实现细节
有没有就觉得印象深刻了很多呢。