- Java王者归来:从入门迈向高手
- 洪锦魁
- 1769字
- 2025-02-17 16:14:35
9-2 类的访问权限——封装
学习类至今可以看到我们可以从main()方法直接引用所设计类内的成员变量(属性)和方法,像这种类内的成员变量可以让外部引用的称为公有(public)属性,而可以让外部引用的方法称公有方法。任何类的属性与方法可供外部随意存取,这个设计最大的风险是会有信息安全的疑虑。
程序实例ch9_12.java:这是一个简单的TaipeiBank类,这个类建立对象完成后,会将存款金额(balance)设为0,但是可以在main()方法中随意设置balance,即可以获得目前的存款余额。

执行结果

上述程序设计最大的风险是可以由TaipeiBank类外的main()方法随意改变存款余额,如此造成信息上的不安全。其概念可以参考下图。

为了确保类内的成员变量(属性值)的安全,其实有必要限制外部无法直接存取类内的成员变量(属性值)。这其实就是将类的成员变量隐藏起来,未来如果想要存取被隐藏的成员变量时,须使用此类的方法,外部无法得知类内如何运作,这个概念就是所谓的封装(Encapsulation),有时候也可以称为信息隐藏(Information Hiding)。此时程序设计应如下所示。

9-2-1 类成员的访问控制
至今所设计类内的方法大都是没有加上存取修饰符(Access Modifier),也可称为no modifier,其实可以将访问控制分成4个等级。

上述列表指出类成员有关存取修饰符的权限,下面将分别说明。
(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的访问控制等级。

在本章笔者将针对public与private做说明,有关protected则在未来介绍更多概念时再做解说,可参考14-1-6节。
程序实例ch9_13.java:测试private存取修饰符,重新设计ch9_12.java,将成员变量的balance设为private,此时程序就会有错误产生。

执行结果

上述指出balance是private,所以在main()程序16行设置此值时产生错误。
了解了本节内容后,最后要提醒的是,构造方法(constructor)可以是no modifier访问控制等级,这是本章至今所使用的设计方式。当然也可以将构造方法设为public等级,但是要注意不可将构造方法设为private等级,如果设为private等级new运算符将无法调用,这样就无法设置对象的初始状态。
9-2-2 设计具有封装效果的程序
继续用TaipeiBank的实例说明,程序设计时若是想要类内的成员变量(属性)是安全的,无法由外部随意存取,必须将成员变量设计为private。为了要可以存取这些private的成员变量,必须在TaipeiBank类内设计可以供main()方法内调用的public方法执行存取作业。例如,可以设计下列两个方法,分别是存款和提款。

另外有一点要注意的是,构造方法必须设为public,因为如果设为private,则new就无法调用构造方法。
程序实例ch9_14.java:设计可以存款与提款的TaipeiBank类,在这个程序的main()方法中只能执行调用存款、提款与输出余额方法,至于TaipeiBank类内部如何运作,main()方法中无法得知。

执行结果

最后要留意的是,如果类内设计的方法很明确是只供此类内的其他方法调用,不对外公开也请设为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类型的计算结果。

执行结果
