Java-08 – 封装与接口

总结之前的内容,对象(object)指代某一事物,类(class)指代象的类型。对象可以有状态和动作,即数据成员和方法。
到现在为止,数据成员和方法都是同时开放给内部和外部的。在对象内部,我们利用this来调用对象的数据成员和方法。在对象外部,比如当我们在另一个类中调用对象的时,可以使用 对象.数据成员 和 对象.方法() 来调用对象的数据成员和方法。
我们将要 封装(encapsulation) 对象的成员(成员包括数据成员和方法),从而 只允许从外部调用部分的成员。利用封装,我们可以提高对象的易用性和安全性。

封装与接口

封装(encapsulation)是计算机常见的术语,即保留有限的外部 接口(interface) ,隐藏具体实施细节。一个Java软件产品与一个日常产品相同。一个对象内部可以有许多成员(数据成员和方法)。有一些数据成员和方法只是内部使用。这时,我们会希望有一个给对象“加壳”的机制,从而封装对象。这样,用户可以比较容易学习和使用外部的接口,而不必接触内部成员。

对象成员的封装

Java通过三个关键字来控制对象的成员的 外部可见性(visibility) : public , private , protected

public: 该成员外部可见,即该成员为接口的一部分
private: 该成员外部不可见,只能用于内部使用,无法从外部访问。
protected:涉及继承的概念,放在以后说

我们先来封装以前定义的Human类:

public class Test
{
    public static void main(String[] args)
    {
        Human aPerson = new Human(160);
        System.out.println(aPerson.getHeight());  
        aPerson.growHeight(170);  
        System.out.println(aPerson.getHeight());  
        aPerson.repeatBreath(100);
    }
}
 class Human
{
    /**
     * constructor
     */
    public Human(int h)
    {
        this.height = h;
        System.out.println("I'm born");
    }
    /**
     * accessor
     */
    public int getHeight()
    {
       return this.height;
    }
    /**
     * mutator
     */
    public void growHeight(int h)
    {
        this.height = this.height + h;
    }
 
     /**
      * encapsulated, for internal use
      */
    private void breath()
    {
        System.out.println("hu...hu...");
    }
   /**
    * call breath()
    */
    public void repeatBreath(int rep)
    {
        int i;
        for(i = 0; i < rep; i++) {
            this.breath();
        }
    }
 private int height; // encapsulated, for internal use
}

内部方法并不受封装的影响。Human的内部方法可以调用任意成员,即使是设置为private的height和breath()
外部方法只能调用public成员。当我们在Human外部时,比如Test中,我们只能调用Human中规定为public的成员,而不能调用规定为private的成员。
通过封装,Human类就只保留了下面几个方法作为接口:

getHeight()
growHeight()
repBreath()

如果我们从main中强行调用height:

System.out.println(aPerson.height);
 

将会有如下错误提示:

Test.java:6: height has private access in Human
System.out.println(aPerson.height);
^1 error

Beep, 你触电了! 一个被说明为private的成员,不能被外部调用。
在Java的通常规范中,表达状态的 数据成员 (比如height)要 设置成private 。对数据成员的修改要通过接口提供的方法进行(比如getHeight()和growHeight())。这个规范起到了保护数据的作用。用户不能直接修改数据,必须通过相应的方法才能读取和写入数据。类的设计者可以在接口方法中加入数据的使用规范。


类的封装

在一个.java文件中,有且只能有一个类带有public关键字,比如上面的Test类。所以,从任意其他类中,我们都可以直接调用该类。Human类没有关键字。
更早之前,我们对象的成员也没有关键字。这种没有关键字的情况也代表了一种可见性,我将在包(package)的讲解中深入。

总结

封装,接口
private, public