封装机制封装的概念

4.2




4.2.1
封装的概念
封装也称为信息隐藏,是指利用抽象数据类型将数据和基于
数据的操作封装在一起,使其构成一个不可分割的独立实体,数
据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只
保留一些对外接口使之与外部发生联系。系统的其他部分只有通
过包裹在数据外面的被授权的操作来与这个抽象数据类型交流与
交互。也就是说,用户无需知道对象内部方法的实现细节,但可
以根据对象提供的外部接口(对象名和参数)访问该对象。封装具
有下述特征:
第4章 类 与 对 象
(1) 在类的定义中设置访问对象属性(数据成员)及方法(成
员方法)的权限,限制本类对象及其他类的对象使用的范围。
(2) 提供一个接口来描述其他对象的使用方法。
(3) 其他对象不能直接修改本对象所拥有的属性和方法。
第4章 类 与 对 象
封装反映了事物的相对独立性。封装在编程上的作用是使
对象以外的部分不能随意存取对象的内部数据(属性),从而有效
地避免了外部错误对它的“交叉感染”。另一方面,当对象的内
部做了某些修改时,由于它只通过少量的接口对外提供服务,
因此大大减少了内部的修改对外部的影响。
面向对象系统的封装单位是对象,类概念本身也具有封装
的意义,因为对象的特性是由它所属的类说明来描述的。
第4章 类 与 对 象
4.2.2
类的严谨定义
在4.1.5节中,我们已经给出了定义类的一般格式,那时我
们给出的类的结构是:
class 类名
{ 数据成员
成员方法
}
第4章 类 与 对 象
这一结构定义只给出了定义一个类所必不可少的内容,而忽略
了类定义的许多细节。有了封装的概念后,我们就可以进一步
来学习类的严谨定义。类的严谨定义格式如下:
[
类修饰符] class
类名
[extends
父类名] [implements
接口列
表]
{
数据成员
成员方法
}
第4章 类 与 对 象
可以看出,在类的严谨定义格式中,类的说明部分增加了
[类修饰符]、[extends父类名]和[implements 接口列表]三个可选
项。合理地使用这些可选项,就可以充分地展示封装、继承和
信息隐藏等面向对象的特性。由于这部分内容比较庞杂,我们
在这里做一简要说明后,将分别在此后的章节中详细讨论。
● 类修饰符(qualifier):用于规定类的一些特殊性,主要是
说明对它的访问限制。
第4章 类 与 对 象
● extends 父类名: 指明新定义的类是由已存在的父类派生
出来的。这样,这个新定义的类就可以继承一个已存在类——父
类的某些特征。
● implements 接口列表: Java本来只支持单继承,为了给
多重继承的软件开发提供方便,它提供了这一接口机制。
第4章 类 与 对 象
4.2.3
类修饰符
类的修饰符用于说明对它的访问限制,一个类可以没有修
饰符,也可以有public、final、abstract等几种不同的修饰符。
它们的作用是不同的,下面分别予以介绍。
1
.无修饰符的情况
如果一个类前无修饰符,则这个类只能被同一个包里的类
使用。Java规定,同一个程序文件中的所有类都在同一个包中。
这也就是说,无修饰符的类可以被同一个程序文件中的类使
用,但不能被其他程序文件中的其他包中的类使用。
第4章 类 与 对 象
【示例程序c4_4.java】
class pp //无修饰符的类pp
{ int a=45; //pp类的数据成员a
}
public class c4_4 //公共类c4_4
{
public static void main(String[ ] args)
{ pp p1=new pp( );//类c4_4中创建了一个无修饰符类pp的对象p1
System.out.println(p1.a);
}
}
第4章 类 与 对 象
在这个程序中定义了两个类:无修饰符的类pp和公共类
c4_4。它们是同一个程序文件(即同一个包)中的两个类,所
以,在类c4_4中可以创建pp类的对象p1,且对象p1可以引用类
pp的数据成员a。关于数据成员的访问限制,将在4.3节中论述。
第4章 类 与 对 象
2
.public
修饰符
如果一个类的修饰符是public
,则这个类是公共类。公共
类不但可供它所在包中的其他类使用,也可供其他包中的类使
用。在程序中可以用import语句引用其他包中的public类。Java
规定,在一个程序文件中,只能定义一个public
类,其余的类
可以是无修饰符的类,也可以是用final修饰符定义的最终类,
否则编译时会报错。
第4章 类 与 对 象
【示例程序c4_5.java】
class pp
{ c4_5 f1=new c4_5( ); //在pp类中创建了一个c4_5类的对象f1
int add( )
{ //下面的语句访问公共类c4_5的对象f1的数据成员b和c
return(f1.b+f1.c);
}
}
第4章 类 与 对 象
public class c4_5 //定义了一个公共类c4_5
{ int b=20,c=3; //c4_5类的数据成员b和c
public static void main(String[ ] args)
{ pp p1=new pp( );
System.out.println(p1.add( ));
}
}
该程序的运行结果是:
23
第4章 类 与 对 象
在程序c4_5.java中定义了两个类:无修饰符的默认类pp和
公共类c4_5。它们是两个无继承关系的类,但由于类c4_5是公
共类,因此,在类pp中可以创建类c4_5的对象f1,且f1可以引用
类c4_5中的数据成员b和c。在公共类c4_5中创建了一个pp类的
对象p1,对象p1可以引用pp类的成员方法add( )。关于数据成员
的访问限制,将在4.3节中论述。
第4章 类 与 对 象
3
.final
修饰符
用final
修饰符修饰的类被称为最终类。最终类是不能被任
何其他类所继承的。定义最终类的目的有三:
(1) 用来完成某种标准功能。如Java系统定义好的用来实现
网络功能的InetAddress、Socket等类都是final类。将一个类定义
为final类,则可以将它的内容、属性和功能固定下来,与它的类
名形成稳定的映射关系,从而保证引用这个类时所实现的功能
是正确无误的。
第4章 类 与 对 象
(2) 提高程序的可读性。从父类派生子类,再从子类派生子
类,使软件变得越来越复杂。而在必要的层次上设置final类,
可以提高程序的可读性。
(3) 提高安全性。病毒的闯入途径之一是在一些处理关键信
息的类中派生子类,再用子类去代替原来的类。由于用final修
饰符定义的类不能再派生子类,截断了病毒闯入的途径,因而
提高了程序的安全性。
第4章 类 与 对 象
【示例程序c4_6.java】
import java.awt. *;
import java.applet. *;
final class p1 //用final修饰的类p1
{
int i=7;
int j=1;
void f(Graphics g)
{
g.drawString("OK ",20,50);
}
}
第4章 类 与 对 象
// public class c4_6 extends p1 错, 用final修饰的类p1不能有继承类
public class c4_6 extends Applet
{
public void paint(Graphics g)
{ p1 n=new p1( );
n.f(g);
n.i=40;
n.j++;
g.drawString("i="+n.i,20,70);
g.drawString("j="+n.j,20,90);
}
}
第4章 类 与 对 象
图4.5 程序c4_6的运行结果
第4章 类 与 对 象
4
.abstract
修饰符
用abstract
修饰符修饰的类称为抽象类。抽象类刻画了研究
对象的公有行为特征,并通过继承机制将这些特征传送给它的
派生类。其作用在于将许多有关的类组织在一起,提供一个公
共的基类,为派生具体类奠定基础。此外,当一个类中出现一
个或多个用abstract修饰符定义的方法时,则必须在这个类的前
面加上abstract修饰符,将其定义为抽象类。有关抽象类及抽象
方法的详细内容将在4.9节介绍。
第4章 类 与 对 象
5
.类修饰符使用注意事项
可以同时使用两个修饰符来修饰一个类,当使用两个修饰
符修饰一个类时,这些修饰符之间用空格分开,写在关键字
class之前,修饰符的顺序对类的性质没有任何影响。
需要注意的是:一个类可以被修饰为public abstract,也可
以被修饰为public final,但不能被修饰为abstract final,这是因
为abstract类自身没有对象,需要派生子类后再创建子类的对
象,而final类不能派生子类,所以不存在用abstract final两个修
饰符修饰的类。
第4章 类 与 对 象
4.3




4.3.1
数据成员的声明
数据成员是用来描述事物的静态特征的。一般情况下,声明
一个数据成员必须做的事是给出这个数据成员的标识符并指明它
所属的数据类型。在这里我们要指出的是:声明一个数据成员除
了这些必做的事情外,我们还可以用修饰符对数据成员的访问权
限作出限制。这样一来,数据成员的声明就成了如下的形式:
[
修饰符]
数据成员类型
数据成员名表;
第4章 类 与 对 象
其中:修饰符是可选的,它是指访问权限修饰符public、
private、protected和非访问权限修饰符static、final等;数据成员
类型就是诸如int、float等Java允许的各种定义数据类型的关键
字;数据成员名表是指一个或多个数据成员名,即用户自定义
标识符,当同时声明多个数据成员名时,彼此间用逗号分隔。
关于数据成员类型、数据成员名表的内容,我们在前面的
章节中已经多次讨论过,只有修饰符是新出现的内容。因此,
本节只对修饰符中的非访问权限修饰符static、final做一些论述。
至于访问权限修饰符将在5.2.1节中讲解。
第4章 类 与 对 象
4.3.2 static
修饰的静态数据成员
用static修饰符修饰的数据成员是不属于任何一个类的具体
对象,而是属于类的静态数据成员。其特点如下:
(1) 它被保存在类的内存区的公共存储单元中,而不是保存
在某个对象的内存区中。因此,一个类的任何对象访问它时,存
取到的都是相同的数值。
(2) 可以通过类名加点操作符访问它。
(3) static类数据成员仍属于类的作用域,还可以使用public
static、 private static等进行修饰。修饰符不同,可访问的层次也
不同。
第4章 类 与 对 象
【示例程序c4_7.java】 对上述(1)和(2)的示例。
import java.awt.*;
import java.applet.*;
class pc
{
static double ad=8;
}
public class c4_7 extends Applet
{
第4章 类 与 对 象
public void paint(Graphics g)
{ pc m=new pc( );
pc m1=new pc( );
m.ad=0.1; //只对m对象的类的数据成员ad赋了值
g.drawString("m1="+m1.ad,20,50);
g.drawString("Pc="+pc.ad,20,70);
g.drawString("m="+m.ad,20,90);
}
}
运行结果见图4.6。
注意:m1、m和pc三个对象引用的数据成员都具有相同的值。
第4章 类 与 对 象
图4.6 程序c4_7的运行结果
第4章 类 与 对 象
4.3.3
静态数据成员的初始化
静态数据成员的初始化可以由用户在定义时进行,也可以
由静态初始化器来完成。静态初始化器是由关键字static引导的
一对花括号括起的语句块,其作用是在加载类时,初始化类的
静态数据成员。静态初始化器与构造方法不同,它有下述特点:
(1) 静态初始化器用于对类的静态数据成员进行初始化。而
构造方法用来对新创建的对象进行初始化。
(2) 静态初始化器不是方法,没有方法名、返回值和参数表。
(3) 静态初始化器是在它所属的类加载到内存时由系统调用
执行的,而构造方法是在系统用new运算符产生新对象时自动
执行的。
第4章 类 与 对 象
【示例程序c4_8.java】
import java.awt.*;
import java.applet.*;
class cc
{
static int n;
int nn;
static //静态初始化器
{ n=20; } //初始化类的静态数据成员n
第4章 类 与 对 象
cc( ) //类cc的构造方法
{ nn=n++; }
}
public class c4_8 extends Applet
{
public void paint(Graphics g)
{
cc m=new cc( );
cc m1=new cc( );
g.drawString("m1="+m1.nn,20,50);
g.drawString("m="+m.nn,20,90);
}
}
第4章 类 与 对 象
图4.7 程序c4_8的运行结果
第4章 类 与 对 象
4.3.4 Final
修饰的最终数据成员
如果一个类的数据成员用final修饰符修饰,则这个数据成
员就被限定为最终数据成员。最终数据成员可以在声明时进行
初始化,也可以通过构造方法赋值,但不能在程序的其他部分
赋值,它的值在程序的整个执行过程中是不能改变的。所以,
也可以说用final修饰符修饰的数据成员是标识符常量。
用final修饰符说明常量时,需要注意以下几点:
(1) 需要说明常量的数据类型并指出常量的具体值。
(2) 若一个类有多个对象,而某个数据成员是常量,最好将
此常量声明为static,即用static final两个修饰符修饰,这样做可
节省空间。
第4章 类 与 对 象
【示例程序c4_9.java】
import java.awt.*;
import java.applet.*;
class ca
{ static int n=20;
final int nn; //声明nn,但没有赋初值
final int k=40;//声明k并赋初值40
ca( )
{ nn= ++n; }//在构造方法中给nn赋值
}
第4章 类 与 对 象
public class c4_9 extends Applet
{
public void paint(Graphics g)
{ ca m1=new ca( ); //创建对象m1,使其静态数据成员nn的值为21
ca m2=new ca( ); //创建对象m2,使其静态数据成员nn的值为22
// m1.nn=90; //这是一个错误的赋值语句,因为nn是标识符常量
g.drawString("m2.nn="+m2.nn,20,30);
g.drawString("m2.k="+m2.k,20,50);
g.drawString("m1.nn="+m1.nn,20,70);
g.drawString("m1.k="+m1.k,20,90);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值