面向对象(上)-封装性的引入
4.7 面相对象特征之一:封装和隐藏
-
为什么需要封装?封装的作用和含义?
我要用洗衣机,只需要按一下开关和洗涤模式即可,不需要了解洗衣机的内部构造和洗衣原理。
-
我们的程序设计追求"高内聚,低耦合"
高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
低耦合:仅对外暴露少量的方法用于使用。
-
隐藏对象内部的复杂性,只对外公开简单的接口。便于外接调用,从而提高系统的可扩展性、可维护性。通俗的说:把该隐藏的隐藏起来,该暴露的暴露出来。
问题的引入
当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。
这里复制操作是受属性的数据类型和存储范围限制,除此之外没有其他制约条件。
但是实际问题中,我们往往需要给属性复制假如额外的限制,就不能只做属性的申明,需要通过方法添加体现。(eg:setLegs、getLegs)
举例:假设我们有一个类描述"狗",其中有个属性legs表示狗腿的数量。如果只要int legs,那么用户有可能传入负数,显然狗腿数量不可能为负数,需要使用方法对传入的数进行限制,且限制用户直接调用"对象.属性"进行赋值。
java
public static void main(String[] args){
Dog dog = new Dog();
// dog.legs = -6; // 编译报错,'legs' has private access in 'com.example.xu_ni_ping.Dog'
dog.setLegs(-6);
dog.getLegs(); // 输出0
dog.setLegs(4);
dog.getLegs(); // 输出4
}
java
public class Dog {
private int legs; // 设置为私有,防止用户调用
// 设置腿的数量
public void setLegs(int l) {
if (l >= 0) {
legs = l;
} else {
legs = 0; // 如果传入的值为负数,就设置为0;
// 或者抛出异常;
}
}
// 获取腿的数量
public int getLegs() {
System.out.println(legs);
return legs;
}
}
封装性的体现
我们需要避免用户在使用"对象.属性"的方式对属性进行赋值,所以我们需要将属性私有化(private),并提供setLegs和getLegs方法。这就体现出了属性以及方法的封装性。
拓展:封装性的体现包含,属性私有化,提供get和set方法;不对外暴露的私有化方法;单例模式等。
权限修饰符
封装性的体现,需要权限修饰符来配合:
java规定的4种权限,从小到大排序:private、default(缺省时默认)、protected、public
| 修饰符 | 类内部 | 同一个包 | 不同包的子类 | 同一个工程 |
|---|---|---|---|---|
| private | yes | |||
| default | yes | yes | ||
| protected | yes | yes | yes | |
| public | yes | yes | yes | yes |
4种权限可以用来修饰类以及类的内部结构(属性、方法、构造器、内部类)
- 对于类:使用default、public;
- 对于类的内部结构(属性、方法、构造器、内部类):private、default、protected、public都行;
封装性举例
例子:创建程序,在其中定义两个类:Person和PersonTest类。定义如下:用setAge()设置人的合法年龄(0-130),用getAge()返回人的年龄。在PersonTest类种的实例化Person类的对象b,调用setAge()和getAge()方法,体现Java封装性

java
public static void main(String[] args){
Person person = new Person();
// person.age = 18; // 'age' has private access in 'com.example.xu_ni_ping.Person'
person.setAge(18);
System.out.println(person.getAge()); // 输出18
person.setAge(-18);
System.out.println(person.getAge()); // 运行报错:java.lang.RuntimeException: 传入的年龄非法!at com.example.xu_ni_ping.Person.setAge(Person.java:15)
}
java
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0 && age <= 130) {
this.age = age;
} else {
throw new RuntimeException("传入的年龄非法!");
}
}
}
快速生成set、get方法:
在类的空白处点击鼠标右键。
选择"Generate"。
选择"Getter and Setter"。
选择需要生成getter和setter方法的字段,点击"OK"即可。
