实验3 类对象和包.docx
《实验3 类对象和包.docx》由会员分享,可在线阅读,更多相关《实验3 类对象和包.docx(17页珍藏版)》请在冰豆网上搜索。
![实验3 类对象和包.docx](https://file1.bdocx.com/fileroot1/2023-1/23/19af21cf-9a82-49c9-842c-a01486063d8f/19af21cf-9a82-49c9-842c-a01486063d8f1.gif)
实验3类对象和包
实验三类、对象和包
实验目的
通过编程和上机实验理解Java语言是如何体现面向对象编程基本思想,了解类的封装方法,以及如何创建类和对象,了解成员变量和成员方法的特性,了解包的定义和引用,掌握面向对象程序设计的方法。
实验要求
1、编写一个体现面向对象思想的程序;
2、编写一个创建对象和使用对象的方法的程序;
3、编写一个显示当前日期和时间的程序;
4、编写不同成员变量修饰方法的程序;
5、编写不同成员方法修饰方法的程序;
6、编写多个类,在同一包,或不同包,验证包的定义和导入;验证对于public、private、protected及缺省修饰的成员的访问权限;
7、编程验证static成员的性质。
实验内容
1、设计类来描述真实客观世界中的事物,使用类的成员变量来表示事物的属性和状态,使用类的成员方法来提供对成员变量的访问或修改
(1)程序功能:
设计一个用来描述汽车的类,使用类的非静态成员变量来表示汽车的车主姓名、当前的速率和当前方向盘的转向角度,使用类的非静态成员方法来表示改变汽车的速率和停车两个操作。
(2)程序源代码如下。
publicclassEXP3_1{
privateStringownerName;//车主姓名
privatefloatcurSpeed;//当前车速
privatefloatcurDirInDegree;//当前方向盘转向角度
publicEXP3_1(StringownerName){
this.ownerName=ownerName;
}
publicEXP3_1(StringownerName,floatspeed,floatdirInDegree){
this(ownerName);
this.curSpeed=speed;
this.curDirInDegree=dirInDegree;
}
publicStringgetOwnerName(){//提供对车主姓名的访问
returnownerName;
}
publicfloatgetCurDirInDegree(){//提供对当前方向盘转向角度的访问
returncurDirInDegree;
}
publicfloatgetCurSpeed(){//提供对当前车速的访问
returncurSpeed;
}
publicvoidchangeSpeed(floatcurSpeed){//提供改变当前的车速
this.curSpeed=curSpeed;
}
publicvoidstop(){//提供停车
this.curSpeed=0;
}
}
(3)编译源程序。
2、创建类的对象实例,使用实例方法(非静态)来访问或修改实例变量
(1)创建类EXP3_1的对象,在调用类的构造函数时指定对象的变量的初始值,以后再使用对象的方法来访问或修改对象的变量的值。
(2)程序代码如下。
publicclassEXP3_2{
publicstaticvoidmain(String[]args){
EXP3_1car=newEXP3_1("成龙",200f,25f);
System.out.println("车主姓名:
"+car.getOwnerName());
System.out.println("当前车速:
"+car.getCurSpeed());
System.out.println("当前转向角度:
"+car.getCurDirInDegree());
car.changeSpeed(80);
System.out.println("在调用changeSpeed(80)后,车速变为:
"+car.getCurSpeed());
car.stop();
System.out.println("在调用stop()后,车速变为:
"+car.getCurSpeed());
}
}
(3)编译并运行,结果如图3.1所示。
图3.1
3、编写显示当前时间和日期的程序
(3)程序功能:
该程序通过使用一个自定义类Time,实现显示当前日期和时间的功能。
(4)程序代码如下。
importjava.util.Calendar;
classTime{
privateCalendart;
privateinty,m,d,hh,mm,ss;
Time(){
t=Calendar.getInstance();
y=t.get(t.YEAR);
m=t.get(t.MONTH)+1;
d=t.get(t.DATE);
hh=t.get(t.HOUR_OF_DAY);
mm=t.get(t.MINUTE);
ss=t.get(t.SECOND);
}
publicStringgetDate(){
returny+"年"+m+"月"+d+"日";
}
publicStringgetTime(){
returnhh+"时"+mm+"分"+ss+"秒";
}
}
publicclassEXP3_3{
publicstaticvoidmain(String[]args){
Timet=newTime();
System.out.println("当前日期:
"+t.getDate());
System.out.println("当前时间:
"+t.getTime());
}
}
(5)编译并运行,结果如图3.2所示。
图3.2
4、使用修饰符来限定类的成员变量或成员方法的属性
有时需要公开一些变量和方法,有时需要禁止其他对象使用变量和方法,这时可以使用修饰符来实现这个目的。
常用的修饰符如下:
publicprivateprotectedpackagestaticfinaltransientvolatile
不同修饰符的访问控制权限如表3.1所示。
访问权限修饰符
类
子类
包
所有类和包
public
√
√
√
√
protected
√
√
√
package
√
√
private
√
表3.1
(1)程序功能:
通过两个类StaticDemo、EXP3_4说明静态变量/方法与实例变量/方法的区别。
(2)程序源代码如下。
classStaticDemo{
staticintx;
inty;
publicstaticintgetX(){
returnx;
}
publicstaticvoidsetX(intnewX){
x=newX;
}
publicintgetY(){
returny;
}
publicvoidsetY(intnewY){
y=newY;
}
}
publicclassEXP3_4{
publicstaticvoidmain(String[]args){
System.out.println("静态变量x="+StaticDemo.getX());
System.out.println("实例变量y="+StaticDemo.getY());//非法,编译时将出错
StaticDemoa=newStaticDemo();
StaticDemob=newStaticDemo();
a.setX
(1);
a.setY
(2);
b.setX(3);
b.setY(4);
System.out.println("静态变量a.x="+a.getX());
System.out.println("实例变量a.y="+a.getY());
System.out.println("静态变量b.x="+b.getX());
System.out.println("实例变量b.y="+b.getY());
}
}
(3)对上面的源程序进行编译,会出现如图3.3所示的出错提示。
图3.3
(4)将源程序中的出错语句删除或使用解释符//隐藏起来,例如,//System.out.println("实例变量y="+StaticDemo.getY());
(5)重新编译并运行该程序,结果如图3.4所示。
图3.4
5、调用方法时参数传递的练习
在其它语言中,函数调用或过程调用时参数有传值调用和传地址调用之分。
在Java中,方法中的参数传递可以分为传值调用或对象方法调用等方式。
传值调用即传递的参数是基本数据类型,调用方法时在方法中将不能改变参数的值,这意味着只能使用它们。
对象调用是指先调用对象,再调用对象的方法,这种方式可以修改允许存取的成员变量。
所以,如果不想改变参数的值,可以采用传值调用的方法。
如果想改变参数的值,可采用对象调用的方法,间接修改参数的值。
5.1、编写一个传值调用的程序
(1)程序功能:
程序首先给整型变量x和y赋一个初值10,然后使用传值调用方式调用方法ff1对x和y做乘方及输出x和y的乘方值,最后再输出x和y的乘方值。
(2)程序源代码如下。
classEXP3_5{
publicstaticvoidmain(String[]args){
intx=10,y=10;
ff1(x,y);
System.out.println("x="+x+",y="+y);
}
staticvoidff1(intpassX,intpassY){
passX=passX*passX;
passY=passY*passY;
System.out.println("passX="+passX+",passY="+passY);
}
}
(3)编译并运行,结果如图3.5。
图3.5
5.2、编写一个调用对象方法的程序
(1)程序功能:
通过调用对象的方法在方法调用后修改了成员变量的值。
(2)程序源代码如下。
classEXP3_6{
publicstaticvoidmain(String[]args){
Powerp=newPower();
p.ff2(10,10);
System.out.println("方法调用后x="+p.x+",y="+p.y);
}
}
classPower{
intx=10,y=10;
voidff2(intpassX,intpassY){
System.out.println("初始时x="+x+",y="+y);
x=passX*passX;
y=passY*passY;
System.out.println("方法调用中x="+x+",y="+y);
}
}
(3)编译并运行,结果如图3.6。
图3.6
6、编写多个类,在同一包,或不同包,验证包的定义和引用;验证对于public、private、protected及缺省修饰的成员的访问权限
(自行编程)
7、构造方法的重载
classCircle{
privatedoubler;
publicdoublegetArea(){
returnMath.PI*r*r;
}
Circle(){
this
(1);//调用Circle(doublex)方法来初始化
}
Circle(doublex){
r=x;
}
}
classTestCircle{
publicstaticvoidmain(String[]s){
Circlec1=newCircle();
Circlec2=newCircle
(2);
System.out.println(c1.getArea());
System.out.println(c2.getArea());
}
}
8、父类的无参构造方法,对子类很重要。
修改下面的程序,为父类添加无参的构造方法。
importjava.awt.Color;
classGraph{//图形,父类
Graph(Colorc){}
}
classCircleextendsGraph{
privatedoubler;
publicdoublegetArea(){
returnMath.PI*r*r;
}
Circle(){
this
(1);//调用Circle(doublex)方法来初始化
}
Circle(doublex){/*这里编译器报错:
这个构造方法,既没有调用本类的其它构造方法,也没有显式调用父类的构造方法,编译系统将自动为它补充super();作为第一条语句。
即,调用父类的无参构造方法。
但父类Graph中没有无参的Graph()构造方法*/
r=x;
}
}
classTestCircle{
publicstaticvoidmain(String[]s){
Circlec1=newCircle();
Circlec2=newCircle
(2);
System.out.println(c1.getArea());
System.out.println(c2.getArea());
}
}
–结论:
在声明构造方法时,好的声明习惯是:
●不声明任何构造方法
●如果声明,至少声明一个无参构造方法
9、static修饰符。
用它修饰的变量是静态变量(类变量),用它修饰的方法称为静态方法(类方法)。
实例变量、实例方法是非静态的,依赖于具体对象实例。
比如,圆Circle有c1和c2这两个对象,但两个圆的半径是不同的变量。
静态变量(比如,圆对象的数量count)和静态方法属于类,供多个对象共享。
classCircle{
privatedoubler;//每个圆的半径不同,故r应该非静态,属于具体对象实例。
staticintcount=0;//count属于类,静态
publicdoublegetArea(){
returnMath.PI*r*r;
}
Circle(){
this
(1);//调用Circle(doublex)方法来初始化
}
Circle(doublex){
r=x;
count++;//每构造一个对象,count会增1
}
}
classTestCircle{
publicstaticvoidmain(String[]s){
Circlec1=newCircle();
Circlec2=newCircle
(2);
System.out.println(c1.getArea());
System.out.println(c2.getArea());
System.out.println("现在共建立了"+Circle.count+"个Circle对象");
}
}
10、关于静态块static{}的用法。
提示:
(1)加载类时执行,常用来对多个静态变量进行显式初始化(此时还没有对象)。
(2)只执行一次,即便多次加载,也只有在第一次加载时执行。
关于非静态块{}的用法。
提示:
(1)构造方法执行前先执行
(2)常用来对实例变量初始化
classCircle{
doubler;
staticintcount;
static{/*静态块。
在该类被加载时执行。
常用来对静态变量初始化。
此时还没有对象。
*/
System.out.println("这里是显式地对静态变量初始化");
count=0;
}
{/*非静态块。
每当要构造对象,该代码块会抢先在构造方法前执行。
常对实例变量初始化。
如果不构造对象,则该代码块不会执行。
*/
System.out.println("要构造了,这里可以初始化实例变量");
r=5;
}
Circle(){
System.out.println("构造方法运行");
r=1;//这里把r从5改成1
count++;//每新建一个圆对象,count增1
}
}
publicclassTestCircle{
publicstaticvoidmain(String[]s){
System.out.println("main函数开始执行了");
System.out.println("构造前,圆对象的数量是"+Circle.count);
Circlec=newCircle();
System.out.println("构造后,圆对象的数量是"+Circle.count);
System.out.println(c.r);
newCircle();
try{Class.forName("Circle");}//再把类Circle加载一次,静态块不执行。
catch(Exceptione){}
}
}
11、编程练习
题目
定义类Circle。
其属性有半径radius,圆心位置center。
下面分别是Circle.java和TestCircle.java的部分代码。
请将其完善。
下面是Circle.java部分代码
importjava.awt.Point;
classCircle{
privatedoubleradius;
privatePointcenter;
Circle(){
this(1.0);
}
Circle(doubler){
radius=r;
center=newPoint();
}
Circle(intx,inty){//需要你完善
}
Circle(Pointp){//需要你完善
}
Circle(intx,inty,doubler){//需要你完善
}
Circle(Pointp,doubler){//需要你完善
}
publicdoublegetRadius(){
returnradius;
}
publicvoidsetRadius(doubler){
radius=r;
}
publicPointgetCenter(){
returncenter;
}
publicvoidmove(intx,inty){
center.move(x,y);
}
}
下面是TestCircle.java部分代码
importjavax.swing.JFrame;
importjava.awt.event.KeyAdapter;
importjava.awt.event.KeyEvent;
importjava.awt.event.WindowAdapter;
importjava.awt.event.WindowEvent;
publicclassTestCircleextendsJFrame{
Circlecircle=newCircle(100,100,10);
publicstaticvoidmain(String[]args){
newTestCircle().lauch();
}
publicvoidlauch(){
setLocation(200,200);
setSize(200,200);
addWindowListener(newWindowAdapter(){
publicvoidwindowClosing(WindowEvente){
System.exit(0);
}
});
setVisible(true);
addKeyListener(newKeyMonitor());
}
classKeyMonitorextendsKeyAdapter{
publicvoidkeyPressed(KeyEvente){
intkey=e.getKeyCode();
switch(key){
caseKeyEvent.VK_UP:
//下面需要你补充
System.out.println("向上移动后,输出circle位置");
break;
caseKeyEvent.VK_DOWN:
//下面需要你补充
System.out.println("向下移动后,输出circle位置");
break;
caseKeyEvent.VK_LEFT:
//下面需要你补充
System.out.println("向左移动后,输出circle位置");
break;
caseKeyEvent.VK_RIGHT:
//下面需要你补充
System.out.println("向右移动后,输出circle位置");
break;
caseKeyEvent.VK_PAGE_UP:
//radius加1
circle.setRadius(circle.getRadius()+1);
System.out.println("radius="+circle.getRadius());
break;
caseKeyEvent.VK_PAGE_DOWN:
//radius减1
if(circle.getRadius()>1)
circle.setRadius(circle.getRadius()-1);
System.out.println("radius="+circle.getRadius());
break;
}
}
}
}