跳至主要內容

聊聊Java封装:Java面向对象核心概念

沉默王二Java 核心面向对象编程约 1986 字大约 7 分钟

5.13 Java封装

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

“好的,哥,准备好了。”三妹一边听我说,一边迅速地打开了 XMind,看来一边学习一边总结思维导图这个高效的学习方式三妹已经牢记在心了。

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

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

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

使用封装有 4 大好处:

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

首先我们先来看两个类。

Husband.java

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;
    }
}

Wife.java

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;
    }
    
}

可以看得出, Husband 类里面的 wife 属性是没有 getter()的,同时 Wife 类的 age 属性也是没有 getter()方法的。至于理由我想三妹你是懂的。

没有哪个女人愿意别人知道她的年龄。

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

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

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

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

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

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

public class Husband {
    public String name ;
    public String sex ;
    public int age ;
    public Wife wife;
}

我们应该这样来使用它:

Husband husband = new Husband();
husband.age = 30;
husband.name = "张三";
husband.sex = "男";    //貌似有点儿多余

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

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 **/
    
}

其他的地方依然这样引用( husband.setAge(22) )保持不变。

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

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

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

Husband husband = new Husband();
husband.age = 300;

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

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

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 **/
    
}

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

public String getSexName() {
    if("0".equals(sex)){
        sexName = "女";
    }
    else if("1".equals(sex)){
        sexName = "男";
    }
    return sexName;
}

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

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;
}

“好了,关于封装我们就暂时就聊这么多吧。”我喝了一口普洱茶后,对三妹说。

“好的,哥,我懂了。”

参考链接:https://www.cnblogs.com/chenssy/p/3351835.htmlopen in new window,整理:沉默王二


GitHub 上标星 10000+ 的开源知识库《二哥的 Java 进阶之路open in new window》第一版 PDF 终于来了!包括Java基础语法、数组&字符串、OOP、集合框架、Java IO、异常处理、Java 新特性、网络编程、NIO、并发编程、JVM等等,共计 32 万余字,500+张手绘图,可以说是通俗易懂、风趣幽默……详情戳:太赞了,GitHub 上标星 10000+ 的 Java 教程open in new window

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