encapsulation.md 8.8 KB
Newer Older
沉默王二's avatar
封装  
沉默王二 已提交
1
---
沉默王二's avatar
沉默王二 已提交
2 3 4
title: 聊聊Java封装:Java面向对象核心概念
shortTitle: Java封装
description: 本文详细介绍了Java封装的概念和重要性。封装是Java面向对象编程的核心之一,通过封装可以保护类内部的数据,实现高内聚低耦合。文章将讨论如何通过访问权限控制、类设计等技巧来实现封装,以提高代码质量和可维护性。
沉默王二's avatar
封装  
沉默王二 已提交
5 6 7 8 9 10 11
category:
  - Java 核心
tag:
  - 面向对象编程
head:
  - - meta
    - name: keywords
沉默王二's avatar
沉默王二 已提交
12
      content: Java,封装
沉默王二's avatar
封装  
沉默王二 已提交
13 14
---

沉默王二's avatar
沉默王二 已提交
15
# 5.13 Java封装
沉默王二's avatar
沉默王二 已提交
16 17 18 19

“三妹,准备好了没,我们这节来讲 Java 封装,算是 Java 的三大特征之一,理清楚了,对以后的编程有较大的帮助。”我对三妹说。

“好的,哥,准备好了。”三妹一边听我说,一边迅速地打开了 XMind,看来一边学习一边总结思维导图这个高效的学习方式三妹已经牢记在心了。
沉默王二's avatar
封装  
沉默王二 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33

封装从字面上来理解就是包装的意思,专业点就是信息隐藏,**是指利用抽象将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体**

数据被保护在类的内部,尽可能地隐藏内部的实现细节,只保留一些对外接口使之与外部发生联系。

其他对象只能通过已经授权的操作来与这个封装的对象进行交互。也就是说用户是无需知道对象内部的细节(当然也无从知道),但可以通过该对象对外的提供的接口来访问该对象。

使用封装有 4 大好处:

- 1、良好的封装能够减少耦合。
- 2、类内部的结构可以自由修改。
- 3、可以对成员进行更精确的控制。
- 4、隐藏信息,实现细节。

沉默王二's avatar
沉默王二 已提交
34
首先我们先来看两个类。
沉默王二's avatar
封装  
沉默王二 已提交
35

沉默王二's avatar
沉默王二 已提交
36 37 38
Husband.java

```java
沉默王二's avatar
封装  
沉默王二 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
public class Husband {
    
    /*
     * 对属性的封装
     * 一个人的姓名、性别、年龄、妻子都是这个人的私有属性
     */
    private String name ;
    private String sex ;
    private int age ;
    private Wife wife;
    
    /*
     * setter()、getter()是该对象对外开发的接口
     */
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setWife(Wife wife) {
        this.wife = wife;
    }
}
```

沉默王二's avatar
沉默王二 已提交
83 84 85
Wife.java

```java
沉默王二's avatar
封装  
沉默王二 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
public class Wife {
    private String name;
    private int age;
    private String sex;
    private Husband husband;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setHusband(Husband husband) {
        this.husband = husband;
    }

    public Husband getHusband() {
        return husband;
    }
    
}
```

沉默王二's avatar
沉默王二 已提交
123
可以看得出, Husband 类里面的 wife 属性是没有 `getter()`的,同时 Wife  类的 age 属性也是没有 `getter()`方法的。至于理由我想三妹你是懂的。
沉默王二's avatar
沉默王二 已提交
124 125

没有哪个女人愿意别人知道她的年龄。
沉默王二's avatar
封装  
沉默王二 已提交
126 127 128 129 130 131 132 133 134 135 136

所以封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果不想被外界方法,我们大可不必提供方法给外界访问。

但是如果一个类没有提供给外界任何可以访问的方法,那么这个类也没有什么意义了。

比如我们将一个房子看做是一个对象,里面有漂亮的装饰,如沙发、电视剧、空调、茶桌等等都是该房子的私有属性,但是如果我们没有那些墙遮挡,是不是别人就会一览无余呢?没有一点儿隐私!

因为存在那个遮挡的墙,我们既能够有自己的隐私而且我们可以随意的更改里面的摆设而不会影响到外面的人。

但是如果没有门窗,一个包裹的严严实实的黑盒子,又有什么存在的意义呢?所以通过门窗别人也能够看到里面的风景。所以说门窗就是房子对象留给外界访问的接口。

沉默王二's avatar
沉默王二 已提交
137
通过这个我们还不能真正体会封装的好处。现在我们从程序的角度来分析封装带来的好处。如果我们不使用封装,那么该对象就没有 `setter()``getter()`,那么 Husband 类应该这样写:
沉默王二's avatar
封装  
沉默王二 已提交
138

沉默王二's avatar
沉默王二 已提交
139
```java
沉默王二's avatar
封装  
沉默王二 已提交
140 141 142 143 144 145 146 147 148 149
public class Husband {
    public String name ;
    public String sex ;
    public int age ;
    public Wife wife;
}
```

我们应该这样来使用它:

沉默王二's avatar
沉默王二 已提交
150
```java
沉默王二's avatar
封装  
沉默王二 已提交
151
Husband husband = new Husband();
L
luanheart 已提交
152 153 154
husband.age = 30;
husband.name = "张三";
husband.sex = "男";    //貌似有点儿多余
沉默王二's avatar
封装  
沉默王二 已提交
155 156
```

沉默王二's avatar
沉默王二 已提交
157
但是哪天如果我们需要修改 Husband,例如将 age 修改为 String 类型的呢?你只有一处使用了这个类还好,如果你有几十个甚至上百个这样地方,你是不是要改到崩溃。如果使用了封装,我们完全可以不需要做任何修改,只需要稍微改变下 Husband 类的 `setAge()`方法即可。
沉默王二's avatar
封装  
沉默王二 已提交
158

沉默王二's avatar
沉默王二 已提交
159
```java
沉默王二's avatar
封装  
沉默王二 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
public class Husband {
    
    /*
     * 对属性的封装
     * 一个人的姓名、性别、年龄、妻子都是这个人的私有属性
     */
    private String name ;
    private String sex ;
    private String age ;    /* 改成 String类型的*/
    private Wife wife;
    
    public String getAge() {
        return age;
    }
    
    public void setAge(int age) {
        //转换即可
        this.age = String.valueOf(age);
    }
    
    /** 省略其他属性的setter、getter **/
    
}
```

沉默王二's avatar
沉默王二 已提交
185
其他的地方依然这样引用( `husband.setAge(22)` )保持不变。
沉默王二's avatar
封装  
沉默王二 已提交
186 187 188 189 190 191 192

到了这里我们确实可以看出,**封装确实可以使我们更容易地修改类的内部实现,而无需修改使用了该类的代码**

我们再看这个好处:**封装可以对成员变量进行更精确的控制**

还是那个 Husband,一般来说我们在引用这个对象的时候是不容易出错的,但是有时你迷糊了,写成了这样:

沉默王二's avatar
沉默王二 已提交
193
```java
沉默王二's avatar
封装  
沉默王二 已提交
194 195 196 197 198 199 200 201
Husband husband = new Husband();
husband.age = 300;
```

也许你是因为粗心写成了这样,你发现了还好,如果没有发现那就麻烦大了,谁见过 300 岁的老妖怪啊!

但是使用封装我们就可以避免这个问题,我们对 age 的访问入口做一些控制(setter)如:

沉默王二's avatar
沉默王二 已提交
202
```java
沉默王二's avatar
封装  
沉默王二 已提交
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
public class Husband {
    
    /*
     * 对属性的封装
     * 一个人的姓名、性别、年龄、妻子都是这个人的私有属性
     */
    private String name ;
    private String sex ;
    private int age ;    /* 改成 String类型的*/
    private Wife wife;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age > 120){
            System.out.println("ERROR:error age input....");    //提示錯誤信息
        }else{
            this.age = age;
        }
        
    }
    
    /** 省略其他属性的setter、getter **/
    
}
```

沉默王二's avatar
沉默王二 已提交
232
上面都是对 setter 方法的控制,其实通过封装我们也能够对对象的出口做出很好的控制。例如性别在数据库中一般都是以 1、0 的方式来存储的,但是在前台我们又不能展示 1、0,这里我们只需要在 `getter()`方法里面做一些转换即可。
沉默王二's avatar
封装  
沉默王二 已提交
233

沉默王二's avatar
沉默王二 已提交
234
```java
沉默王二's avatar
封装  
沉默王二 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247
public String getSexName() {
    if("0".equals(sex)){
        sexName = "女";
    }
    else if("1".equals(sex)){
        sexName = "男";
    }
    return sexName;
}
```

在使用的时候我们只需要使用 sexName 即可实现正确的性别显示。同理也可以用于针对不同的状态做出不同的操作。

沉默王二's avatar
沉默王二 已提交
248
```java
沉默王二's avatar
封装  
沉默王二 已提交
249 250 251 252 253 254 255 256 257 258 259
public String getCzHTML(){
    if("1".equals(zt)){
        czHTML = "<a href='javascript:void(0)' onclick='qy("+id+")'>启用</a>";
    }
    else{
        czHTML = "<a href='javascript:void(0)' onclick='jy("+id+")'>禁用</a>";
    }
    return czHTML;
}
```

沉默王二's avatar
沉默王二 已提交
260 261 262
“好了,关于封装我们就暂时就聊这么多吧。”我喝了一口普洱茶后,对三妹说。

“好的,哥,我懂了。”
沉默王二's avatar
封装  
沉默王二 已提交
263 264

> 参考链接:[https://www.cnblogs.com/chenssy/p/3351835.html](https://www.cnblogs.com/chenssy/p/3351835.html),整理:沉默王二
沉默王二's avatar
沉默王二 已提交
265 266 267 268


----

沉默王二's avatar
7600+  
沉默王二 已提交
269
GitHub 上标星 7600+ 的开源知识库《二哥的 Java 进阶之路》第一版 PDF 终于来了!包括Java基础语法、数组&字符串、OOP、集合框架、Java IO、异常处理、Java 新特性、网络编程、NIO、并发编程、JVM等等,共计 32 万余字,可以说是通俗易懂、风趣幽默……详情戳:[太赞了,GitHub 上标星 7600+ 的 Java 教程](https://tobebetterjavaer.com/overview/)
沉默王二's avatar
沉默王二 已提交
270

沉默王二's avatar
沉默王二 已提交
271 272

微信搜 **沉默王二** 或扫描下方二维码关注二哥的原创公众号沉默王二,回复 **222** 即可免费领取。
沉默王二's avatar
沉默王二 已提交
273

沉默王二's avatar
沉默王二 已提交
274
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/gongzhonghao.png)