![Java王者归来:从入门迈向高手](https://wfqqreader-1252317822.image.myqcloud.com/cover/394/27563394/b_27563394.jpg)
9-2 类的访问权限——封装
学习类至今可以看到我们可以从main()方法直接引用所设计类内的成员变量(属性)和方法,像这种类内的成员变量可以让外部引用的称为公有(public)属性,而可以让外部引用的方法称公有方法。任何类的属性与方法可供外部随意存取,这个设计最大的风险是会有信息安全的疑虑。
程序实例ch9_12.java:这是一个简单的TaipeiBank类,这个类建立对象完成后,会将存款金额(balance)设为0,但是可以在main()方法中随意设置balance,即可以获得目前的存款余额。
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P151_573416.jpg?sign=1739299442-q6uAFvJIzeKnN45CjLtimTRyn9y7DLF7-0-b90ff863de5cda81fa6b792903699255)
执行结果
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P151_573439.jpg?sign=1739299442-UVnDxScIkS9jB80JAe3zi8vY2XI9JqBM-0-03cd79860af227cf577128dd51115169)
上述程序设计最大的风险是可以由TaipeiBank类外的main()方法随意改变存款余额,如此造成信息上的不安全。其概念可以参考下图。
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P152_573844.jpg?sign=1739299442-OQbAVOO7dWT8ia89uCudMYwti4RcWWfA-0-dcc1cb64b077e97d23557460ef0e21d0)
为了确保类内的成员变量(属性值)的安全,其实有必要限制外部无法直接存取类内的成员变量(属性值)。这其实就是将类的成员变量隐藏起来,未来如果想要存取被隐藏的成员变量时,须使用此类的方法,外部无法得知类内如何运作,这个概念就是所谓的封装(Encapsulation),有时候也可以称为信息隐藏(Information Hiding)。此时程序设计应如下所示。
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P152_573847.jpg?sign=1739299442-75t99zppbEI8nixyoVzPMEHpaoQ0zj1P-0-3133a938bb00e50fc2d03159395ec822)
9-2-1 类成员的访问控制
至今所设计类内的方法大都是没有加上存取修饰符(Access Modifier),也可称为no modifier,其实可以将访问控制分成4个等级。
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-T152_759799.jpg?sign=1739299442-lkM2FspYhMtZJNf6X8q1tGsJCX5RrxWA-0-f3c97b3d6f74a3f4adf6684f734a7897)
上述列表指出类成员有关存取修饰符的权限,下面将分别说明。
(1)public:可解释为公开,如果将类的成员变量或方法设为public时,本身类(class)、同一包(package)、子类(subclass)或其他类(world)都可以存取。
(2)protected:可解释为保护,如果将类的成员变量或方法设为protected时,本身类(class)、同一包(package)或子类(subclass)可以存取,其他类(world)则不可以存取。
(3)no modifier:如果类的成员变量或方法没有修饰词no modifier时,本身类(class)、同一包(package) 可以存取。子类(subclass)或其他类(world)则不可以存取。
(4)private:可解释为私有,如果将类的成员变量或方法设为private时,除了本身类(class)可以存取。同一包(package)、子类(subclass)或其他类(world)都不可以存取。
在这里出现了一个新名词——同一包(package),基本上笔者将每一章的程序范例都是放在同一个文件夹,当程序编译后.class都是在相同文件夹,在相同文件夹的类就会被视为同一包。程序若是有多个类,经过编译后此程序的类一定是在相同文件夹下,所以一定是同一包。读者可以发现每个程序的main()方法虽然与我们所建立的类属于不同的类,但是可以在main()方法内存取no modifier的成员变量与方法。
经过上述的解说后,若是再回过头来看程序实例ch9_12.java,可以发现在该程序中,TaipeiBank类内的成员变量与方法都是no modifier的访问控制等级。
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P153_574379.jpg?sign=1739299442-aFNDBVGw95FD8BTIO0XroPs7L925FpBe-0-e704227dfe3cfc42dc9856f3994df893)
在本章笔者将针对public与private做说明,有关protected则在未来介绍更多概念时再做解说,可参考14-1-6节。
程序实例ch9_13.java:测试private存取修饰符,重新设计ch9_12.java,将成员变量的balance设为private,此时程序就会有错误产生。
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P153_759801.jpg?sign=1739299442-bRrVvM2MYeb2ZDJf7jF9BcYrajFmcONC-0-12b11d2b2768bbc40f42cb1e8e9499fc)
执行结果
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P153_574388.jpg?sign=1739299442-KzhyoYiUGn3Hvan703GScPvntNnnbdab-0-0d7a702439fdc7177c0fe28a2df26c6a)
上述指出balance是private,所以在main()程序16行设置此值时产生错误。
了解了本节内容后,最后要提醒的是,构造方法(constructor)可以是no modifier访问控制等级,这是本章至今所使用的设计方式。当然也可以将构造方法设为public等级,但是要注意不可将构造方法设为private等级,如果设为private等级new运算符将无法调用,这样就无法设置对象的初始状态。
9-2-2 设计具有封装效果的程序
继续用TaipeiBank的实例说明,程序设计时若是想要类内的成员变量(属性)是安全的,无法由外部随意存取,必须将成员变量设计为private。为了要可以存取这些private的成员变量,必须在TaipeiBank类内设计可以供main()方法内调用的public方法执行存取作业。例如,可以设计下列两个方法,分别是存款和提款。
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P154_759803.jpg?sign=1739299442-w6SsMwE98H1wc8aOX0grNuZRxdQghklp-0-609f5576d993e0fc45ef149428a4d34f)
另外有一点要注意的是,构造方法必须设为public,因为如果设为private,则new就无法调用构造方法。
程序实例ch9_14.java:设计可以存款与提款的TaipeiBank类,在这个程序的main()方法中只能执行调用存款、提款与输出余额方法,至于TaipeiBank类内部如何运作,main()方法中无法得知。
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P154_574799.jpg?sign=1739299442-uCvHYT3dEsyiHIIqNlEAjClBGEzMidML-0-1eaacf6864cb08a00b0fa9c83fa2ea73)
执行结果
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P154_759806.jpg?sign=1739299442-oJ2osH8E83xuKWGQcB8gcBEfGf850sJB-0-c78e8f08f32a52fb69212b70941aa6de)
最后要留意的是,如果类内设计的方法很明确是只供此类内的其他方法调用,不对外公开也请设为private,这样可以避免被外部误用。
程序实例ch9_15.java:这是一个扩充ch9_14.java的程序,主要是执行汇率计算,假设台币与美金的汇率是1∶30,在换汇的时候银行会收总金额1%的手续费,但是如果目前存款金额大于或等于10000时,手续费将降为总金额的0.8%。这个程序的重点是,在第21~25行建立一个private double cal_rate()方法,只有TaipeiBank类的其他方法才可调用,这个方法的功能是实际计算美金兑换台币的结果,然后会回传double类型的计算结果。在第16~20行建立一个public double usa_to_taiwan()方法,这个方法主要是供外部调用,外界只能看到这一层的使用参数,无法了解内部如何处理,此例是供main()方法调用,这个方法同时也会回传double类型的计算结果。
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P155_759808.jpg?sign=1739299442-yb6hFZZ8mWrhErJcUWMNHXwSYSaq3C5S-0-22d9fb17ff6ecb80e019acb22ac6c0f4)
执行结果
![](https://epubservercos.yuewen.com/9E44AA/15825993204148006/epubprivate/OEBPS/Images/Figure-P155_575223.jpg?sign=1739299442-cPOzu6dy0mYJXxlqt5vwExdrrU6tHhW5-0-5368caba1e770ca875c47365217e2433)