05 类和对象封装.docx
- 文档编号:8669905
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:10
- 大小:20.84KB
05 类和对象封装.docx
《05 类和对象封装.docx》由会员分享,可在线阅读,更多相关《05 类和对象封装.docx(10页珍藏版)》请在冰豆网上搜索。
05类和对象封装
第5章类和对象---封装
上一章介绍了类、属性、方法及方法传参、构造方法和析构方法、对象实例化、对象成员的引用等核心的语法及语义。
这一章主要介绍面向对象三个主要特性(封装、继承、多态)之一:
封装。
另外介绍几个与面向对象主要特性关系不大,但很常用的JAVA关键字:
package,import,this。
1JAVA关键字package、import和JAR文件
1.1package和import
package意为“包”,包的逻辑含义是“名称空间”,物理含义是文件夹。
什么是“名称空间”?
名称空间可以确定一个对象的唯一名字,比如,很多人叫张三,无法唯一确定张三是谁,如果使用名称空间:
山大.威海分校.信工.计算机.张三,则唯一确定张三的机会很大。
山大.威海分校.信工.计算机就是张三的名称空间。
JAVA为什么要用名称空间?
全世界有数万家公司和数百万JAVA程序员,他们都在写类,而且在互相使用对方写的类,怎样区分这个类是哪家公司、哪个部门、哪个项目写的?
类重名了怎么办?
名称空间可以解决这个问题。
比如某个类MyClass使用了sd.wehhai.ie.MyClass完全名称空间,我们就知道这个类出自何处,而且也不但心与其他名称空间的MyClass重名。
包的物理含义是文件夹,文件夹的层次是与名称空间的层次一一对应的,比如名称空间sd.wehhai.ie对应的文件夹层次是sd\wehhai\ie。
如果在名称空间中创建类,首先要用package声明你使用的名称空间,比如在sd.wehhai.ie中创建MyClass类,则:
packagesd.wehhai.ie
classMyClass{//类体….}
例1:
package操作演示
(1)打开eclipse,创建一个新项目“5-1testpack”;
(2)在该项目下依次建立二个类,Test1,Test2,可以看到这二个类都在(defaultpackage)包中,这是项目默认的包。
(3)在项目中新建一个包sd.wehhai.ie,在该包下新建一个类MyClass,代码如下:
packagesd.weihai.ie;
publicclassMyClass{
publicvoidhello()
{System.out.println("hello!
");}
}
查看项目文件夹,发现有sd\wehhai\ie的层次文件夹。
(4)在(defaultpackage)包中的Test1类中写以下代码:
publicclassTest1{
publicstaticvoidmain(Stringargs[])
{sd.weihai.ie.MyClasst=newsd.weihai.ie.MyClass();
t.hello();
}}
输出结果为hello!
由代码可以看到,当(defaultpackage)包中的类试图使用另一个包sd.wehhai.ie中的类MyClass时,必须要使用全名称空间,这太繁琐了。
解决方法是使用import,在程序的开始,事先导入包,会省缺一些麻烦。
(5)在(defaultpackage)包中的Test2类中写以下代码,程序清爽许多:
importsd.weihai.ie.*;//“*”代表导入该包所有类
publicclassTest2{
publicstaticvoidmain(Stringargs[])
{
MyClasst=newMyClass();//无需全名称空间
t.hello();
}}
(6)在一个包中使用另一个包中的类,最好用import让程序清爽一些。
同一个包中的类互相使用,无需import。
在(defaultpackage)包中写的类,开头也无需声明package。
(7)有些人认为,import类似于C/C++的include,这种说法不恰当。
include导入的库参与编译,而import导入的库只有被程序真正用到的才参与编译,所以你尽可大胆使用import,不会造成目标文件(.class文件)膨胀。
1.2JAR文件
一个大型项目可能有很多包,一个包又有很多类,在课件第1章曾演示过,JAVA为每个类单独编译成一个.class文件,当项目完成后,这么多的.class文件如何发布就成了问题。
很自然的会想到:
应该把这些.class文件压缩打包成一个文件。
JAR文件(该种文件的扩展名是.JAR)是JAVA产品发布常见的文件格式,网络上可下载的JAVA免费或收费产品非常多,从手机、桌面等消费娱乐程序,到服务器端插件等平台、开发工具或开发环境,很多是以JAR发布的。
eclipse支持JAR文件打包,操作方法是:
File菜单—>export—>在弹出对话框中选JARfile即可。
【注:
本小节介绍的内容在JAVA开发中很常用,但与面向对象的核心思想和概念无关。
】
2类的封装
技术只有经过良好的封装才可以出售,原因有二:
●封装可以隐藏技术的复杂细节,使用户容易使用;
●封装可以隐藏技术的核心密秘,使竞争对手不易轻易获取。
封装可以使产品“黑箱化”,只暴露设计者想暴露的,隐藏设计者想隐藏的。
软件产品也不例外,费劲心血开发的JAVA类,想卖得好,又不泄密,就要经过良好的封装。
本小节讨论JAVA语言为类的封装提供的技术手段。
2.1访问控制关键字public/private/protected/缺省的使用
这几个关键字可以修饰类、属性、方法,但不能修饰方法内部的局部变量。
它们主要用于决定属性和方法的可见性,即一个类的属性或方法,只能被本类看见并操作?
还是能被同一包(或不同包)的其它类看见并操作?
修饰类
public和“缺省”可以修饰类,比如:
publicclassA{}
classB{}//缺省
用public修饰的类,可以被其它包(文件夹)的类访问,一个JAVA源程序文件可以写多个类,但只有一个类可以用public修饰,而且该类的类名必须与源程序文件名相同。
用“缺省”修饰的类,只能被该类所在的包的其它类访问。
修饰属性和方法
可见性如下表所示(其中重点是private和public)
当前类
当前包
其它包
所有项目
private
可见
缺省
可见
可见
protected
可见
可见
可见
public
可见
可见
可见
可见
下例演示了属性和方法的可见性(只讨论private和public)。
例2:
明星的生日
publicclassStarBirthday
{
privateintyear=1980;//明星的出生年份保密
publicintmonth=8;//出生月份公开
publicintday=15;//出生日公开
//省略类的其它部分
}
classFans//粉丝类
{
publicstaticvoidmain(String[]args)
{StarBirthdays=newStarBirthday();
inty,m,d;
//y=s.year;外部类不能访问private的year
m=s.month;//可以访问
d=s.day;//可以访问
}
}
实际编程中如何使用上述关键字实现对属性和方法的封装?
重要的是掌握以下设计原则:
原则1:
属性尽可能的private,不暴露给外部对象,操作这些属性,要通过非private的get***()属性方法去读,或set***()属性方法去写。
【如何写属性方法见下一小节】
原则1几乎是JAVA程序在编程风格方面的强制性要求。
原则2:
方法的开放,优先考虑private,最后考虑public.
上述2个原则体现了类的封装原则:
类应该是个黑箱,暴露在外的功能越少越少,即可以简化用户对类的理解,也有利于安全。
2.2属性方法
属性方法是专门用于读写类的属性的方法,JAVA语法中并未定义属性方法,只是程序员的约定俗成:
以get或set起头的方法名叫属性方法,这种方法专门用于读写类的属性,下面用属性方法重写【例2:
明星的生日】
【例3明星的生日—属性过程版】
publicclassStarBirthday
{
privateintyear=1980;//明星的出生年份保密
privateintmonth=8;//出生月份不能直接访问
privateintday=15;//出生日不能直接访问
publicintgetmonth()//属性方法,读month
{returnmonth;}
publicintgetday()//属性方法,读day
{returnday;}
publicintsetday(intd)//属性方法,写day
{if(d<1||d>31)
{day=1;
System.out.println("输入的日期超范围,系统自动改为1");}
elseday=d;
returnday;}
}
classFans//粉丝类
{
publicstaticvoidmain(String[]args)
{StarBirthdays=newStarBirthday();
inty,m,d;
y=s.year;m=s.month;d=s.day;//均不能直接访问
m=s.getmonth();//可以用属性方法间接访问
d=s.getday();//可以用属性方法间接访问
d=s.setday(32);//可以用属性方法间接访问
}}
从本例看到,使用属性方法设置属性有以下好处:
(1)属性的真正名字(year,month,day)被隐藏了,用户只能通过属性方法的名字来间接访问属性,由于类的属性往往是类的核心机密,隐藏属性的真正名字有利于安全。
(2)当用户通过属性方法间接设置属性时,有机会纠正不正常的属性值(比如例题的setday方法),而直接设置属性做不到这一点。
(3)可以通过属性方法,把一个private属性改造成外部对象对其不能读写、只读、只写、可读写:
●如果一个private属性没有相应的属性方法,则不能读写;
●如果一个private属性只有相应的get属性方法,则只读;
●如果一个private属性只有相应的set属性方法,则只写;
●如果一个private属性有相应的set和set属性方法,则可读可写;
正因为属性方法有上述好处,所以在JAVA编程务实中被广泛使用,用属性方法间接访问属性几乎成为强制性的要求。
2.3方法的重载(overload)
(1)语法
在一个类内,允许使用同一个方法名,不同的形式参数个数反复重写同一个方法,如参数个数相同,则参数类型应该不同。
但是不允许用不同的返回类型,相同的参数个数(或相同参数类型)重载方法,也就是说,函数的重载是否合乎语法要求,只看参数类型和个数,不看返回类型。
【例4方法的重载】
//Overload类中,5个重载方法的参数类型或个数均不相同
publicclassOverload{
voidm1()
{System.out.println("第1个重载方法被调用");};
voidm1(intx)
{System.out.println("第2个重载方法被调用");}
voidm1(Strings)
{System.out.println("第3个重载方法被调用");}
voidm1(Strings,intx)
{System.out.println("第4个重载方法被调用");}
voidm1(Strings,intx,inty)
{System.out.println("第5个重载方法被调用");}
}
classOverload_ex
{publicstaticvoidmain(Stringargs[])
{//系统根据不同的参数,自动匹配调用相应的重载方法
Overloadol=newOverload();
ol.m1();
ol.m1(10);
ol.m1("abc");
ol.m1("abc",10);
ol.m1("ab1",10,10);
}}
(2)语义
●方法的重载是重要的封装技术,它可以使用户误以为只有一个方法(实际上重载了多个),使用户简化对类的理解,更方便的使用它。
对程序员来讲,重载并不节省写代码的工作量。
●方法的重载同时又是类的多态性的体现,它可以使方法名所代表的概念有不同的实现方式。
所谓多态为“一种概念,多种实现”,多态是面向对象另一个核心特征,后续课程将会介绍。
●方法的重载是编程务实中常用和重要的技术。
比如C++的cout和JAVA的Sysytem.out.println()都是重载函数,它们不是一个,而是多个同名函数。
2.4构造方法重载
构造方法也可以重载,重载的语法规则与普通方法一样。
析构方法不能重载。
重载构造方法可以使对象的初始化有多种选择,具体的例子见本章“3关键字this【例5】”
3关键字this
this指代“当前对象”,语法形式为:
this.对象的属性;
this.对象的方法;
实际上对象的属性和方法调用时,如果不写对象名,都隐含了this,如果可以明确知道“当前对象”是谁,可以省略不写this---大多数情况下都可以省略this,否则不能省略。
this最常用于:
(1)重载的构造方法内部,意为“调用本类已定义的构造方法”
例5:
重载的构造方法内使用this
publicclassBirthday
{
privateintyear,month,day;
Birthday(inty,intm,intd)//构造方法,三参
{year=y;month=m;day=d;}
Birthday()//重载构造方法
{this(1985,6,15);//调用前面已定义的三参构造方法
System.out.println(year+"年"+month+"月"+day+"日");
}}
classBirthday_ex
{publicstaticvoidmain(String[]args)
{Birthdayb=newBirthday();
}}
程序输出:
1985年6月15日
(2)方法内部的代码中,出现了属性与方法的局部变量重名现象,用this区分属性与局部变量。
例6:
用this区分属性与局部变量
publicclassBirthday
{
privateintyear,month,day;
Birthday(intyear,intmonth,intday)//重名
{this.year=year;//this.year为类的属性
//year为方法内的变量
this.month=month;
this.day=day;}
}
}
classBirthday_ex
{publicstaticvoidmain(String[]args)
{Birthdayb=newBirthday(1985,6,15);
}}
【注意:
上一章讲过static方法,static方法体内(包括main方法)不能使用this,因为this指代对象而不是类,static方法不需要实例化对象即可调用,如果方法体内有this,这个this对象可能还没创建出来】
课后习题
简答题
1包的逻辑含义是什么?
物理含义是什么?
2import有什么作用?
3属性方法有什么好处?
4把一个private属性改造成外部对象对其只能读,应该怎么做?
5方法重载的语义是什么?
6了解this的用法
编程题
1上机练习本章例题
2写一个“手机类”,列出其常见属性、方法,并用属性方法、重载方法等技术对其封装
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 05 类和对象封装 对象 封装