第5章 java类和对象.docx
《第5章 java类和对象.docx》由会员分享,可在线阅读,更多相关《第5章 java类和对象.docx(22页珍藏版)》请在冰点文库上搜索。
第5章java类和对象
面向对象的术语
每个对象都有可以用来识别的特性(外表和行为)。
面向对象的程序员用对象的概念来看整个世界。
他们寻找对象的外表,对象的行为,以及它们是如何与其他对象交互的。
当开发软件时,他们用代码创建称为对象的实体。
这些代码对象包含特性,就像现实世界的那样。
软件中对象给这些特性起了专用名字:
状态和行为。
1.把状态和行为结合在一起
面向对象编程的一个关键概念是能够把数据和操作数据的函数用一个软件包表示,这样的软件包就称为对象。
2.数据和方法
java中,对象的状态由数据(比如常量和变量)组成,而行为称为方法.
3.封装
把数据隐藏在对象中,使得除了该对象方法以外的任何东西都不能使用这些数据,就被称为封装。
(1)应用于数据
(2)应用于方法的细节实现
意义:
封装能防止对象与其它对象内部细节有关,因为小的改变都会对整个系统造成巨大的破坏。
由于有了封装,可以进行错误修正,代码优化和整个代码重写.
4.接口
方法是功能接口。
5.对象之间的通信
从一个对象向另一个对象发送消息会激发目标对象中的方法.
消息
例:
用电视机的遥控器,将消息“改为5频道”发送给电视机对象。
Television.changeStation(5);
6.分类
类是创建对象的模板,包含对象将要处理的数据和方法。
必须事先定义类,才能创建对象。
Java的类
1.类的定义
(1)定义类:
class类名{
类型实例变量;
……
返回值类型 方法名(参数列表){
方法体
}
……
}
例:
classPoint{
inth;
intv;
}
(2)创建对象:
Pointp1,p2; //p1,p2未指向任何对象,值为null。
p1=newPoint(); //创建对象。
p2=p1;//p2,p1指向同一个对象,p1,p2存放的是对象的引用。
p1=null;//释放对象。
注:
若h,v没有赋初值,则当创建对象时,系统会自动为这些变量赋予默认的值。
(3)传递参数:
例:
classPoint{
inth;
intv;
//newH,newV为形式参数,
//在方法中说明的变量和形参为局部变量,仅当执行该方法时才存在。
publicvoidsetPoint(intnewH,intnewV){
h=newH*2;
v=newV*2;}
pubicintgetH(){
return(h); //从方法返回值
}
pubicintgetV(){
return(v);
}
}
publicclassTwoPoint{
publicstaticvoidmain(String[]args){
inta=3,b=4;
intm=30,n=40;
Pointp1=newPoint();
Pointp2=newPoint();
p1.setPoint(a,b);
p2.setPoint(m,n);
System.out.println(p1.getH(),p1,getV());
System.out.println(p2.getH(),p2.getV());
System.out.println(a+”,”+b);
System.out.println(m+”,”+n);
解释:
p1,p2:
接受消息的对象名;
“.”:
圆点表示法,是对象内部执行方法的标准机制;
setPoint:
消息,接受消息时相应的方法被激发;
a,b,m,n:
参数。
✧使用对象(引用).成员变量来引用对象的成员变量。
✧使用对象(引用).方法(参数列表)来调用对象的方法。
注:
当将参数值传递给方法时,基本类型的参数值,就产生了它的一个拷贝值,拷贝值传递给方法。
结论:
(1)根据不同的实例变量,区分特定的对象。
(2)每个对象都有自己的实例变量,改变一个对象的实例变量,并不影响到另外一个对象的实例变量。
2.如何在内存中区分类和对象
✧类是静态的概念,放在代码区。
✧对象是new出来的,位于堆内存(动态分配,运行时分配),类的每个成员变量在不同的对象中都有不同的值(除了静态变量),而方法只有一份,执行的时候才占用内存。
✧同一类的每个对象有不同的成员变量存储空间。
✧同一类的每个对象共享该类的方法。
类和对象的关系
实例变量和局部变量
1.实例变量在类内定义(默认初始化)
⏹实例变量可以是java语言中任何一种数据类型(包括基本类型和引用类型)。
⏹在定义实例变量时可以对其初始化,如果不对其初始化,java使用默认的值对其初始化。
如下表所示。
⏹实例变量的作用范围为整个类体。
2.局部变量(必须初始化):
(1)在方法体内定义;
(2)方法中的形参。
在同一个作用域内,Java不允许定义两个同名的局部变量。
例:
classPoint{
intx=1,y=1; //实例变量x和y
voiddraw(){
inty=0; //局部变量
for(inty=10;y<100;y++) //错误,循环体内的y和局部变量同名
;
}
}
局部变量可以和实例变量同名,局部变量屏蔽实例变量。
例:
classPoint{
intx,y;
voidinit(intx,inty){
x=x;//错误,不能将参数x的值赋给实例变量x
y=y;
}
}
实例变量属于对象,描述了对象的属性,随着对象的存在而存在;
局部变量随方法的调用而存在,一旦对方法调用结束,局部变量随之消亡。
例:
classLoc{
intx=1;//实例变量
voidprintLocVar(){
intx=25;//局部变量
System.out.println("\nxinprintLocVaris:
"+x);
++x;
System.out.println("xinprintLocVaris:
"+x);
}
voidprintInstanceVar(){
System.out.println("\ninstancevariablexis:
"+x);
x*=10;//实例变量x
System.out.println("instancevariablexis:
"+x);
}
}
publicclassTest{//程序的主类
publicstaticvoidmain(String[]args){
Locobj=newLoc();
intx=5;//局部变量x
System.out.println("xinmainis:
"+x);
obj.printLocVar();
obj.printInstanceVar();
System.out.println("xinmainis:
"+x);
}
}
构造函数
构造函数是java提供的一个特殊的方法。
其功能是在创建对象时初始化对象的实例变量。
●与类具有相同的名字;
●系统将自动调用构造函数。
构造函数的特点:
●构造函数没有返回值,也不能在其前面加上void修饰符。
例:
classPoint{
intx,y;
Point(inta,intb){
x=a;
y=b;
}
}
publicclasstestPoint{
publicstaticvoidmain(String[]args){
Pointp=newPoint(10,20);
System.out.println("x="+p.x+"y="+p.y);
}
}
●如果类中没有定义构造函数,编译器会自动创建一个默认的、不带参数的构造函数。
例:
classPoint{
intx,y;
}
publicclasstestPoint{
publicstaticvoidmain(String[]args){
Pointp=newPoint();
System.out.println("x="+p.x+"y="+p.y);
}
}
练习:
1.创建Student类,构造Student对象,输出对象信息。
2.创建复数类(Complex),构造复数对象,输出对象信息。
3.类、对象的内存分析。
方法重载
方法重载是在一个类中定义两个或多个同名的方法,但方法的参数个数或类型不完全相同。
例:
publicclassTestPoint{
publicstaticvoidmain(String[]args){
Pointp1=newPoint(10,20);
Pointp2=newPoint();
System.out.println("x="+p1.x+"y="+p1.y);
System.out.println("x="+p2.x+"y="+p2.y);
}
}
classPoint{
intx,y;
Point(inta,intb){
x=a;
y=b;
}
Point(){
x=-1;
y=-2;
}
}
注:
1.一旦定义了构造函数,java就不能再调用系统默认的构造函数。
2.方法重载的误区是靠返回值来区别重载。
例:
classPoint{
intdraw(){//方法类型为int
return1;
}
voiddraw(){//方法类型为void
}
}
p.draw();//不能确定调用哪个draw()方法
关键字this
this代表一个特殊的引用,即当前对象。
●指代对象
publicclassTestIntVector{
publicstaticvoidmain(String[]args){
IntVectort1=newIntVector(),
t3=newIntVector(),
t2=t1;
System.out.println(t1.equals(t2));
System.out.println(t3.equals(t2));
}
}
classIntVector{
intv[];
booleanequals(IntVectorother){
if(this==other){
returntrue;
}
returnfalse;
}
}
注:
对象作为参数是按引用传递,也就是说传递对象自身。
✧This指代对象可以用于解决实例变量被局部变量屏蔽的问题。
例:
classPoint{
intx,y;
voidinit(intx,inty){
this.x=x;
this.y=y;
}
}
✧级联调用
例:
publicclassTime{
privateinthour,min,sec;
Time(){
setHour(0);
setMin(0);
setSec(0);
}
TimesetHour(inth){
hour=(h>=0&&h<24)?
h:
0;
returnthis;
}
TimesetMin(intm){
min=(m>=0&&m<60)?
m:
0;
returnthis;
}
TimesetSec(ints){
sec=(s>=0&&s<60)?
s:
0;
returnthis;
}
publicStringtoString(){
returnhour+":
"+min+":
"+sec;
}
}
publicclasstimeToString{
publicstaticvoidmain(String[]args){
Timet=newTime();
System.out.println(t.setHour(19).setMin(22).setSec(30).toString());
}
}
●指代构造函数
在构造函数内部使用this,它用于指代另外一个构造函数。
例:
publicclassPoint{
intx,y;
Point(){
this(-1,-2);
}
Point(inta,intb){
x=a;
y=b;
}
doubledistance(intx,inty){
intdx=this.x-x;
intdy=this.y-y;
returnMath.sqrt(dx*dx+dy*dy);
}
doubledistance(Pointt){
this(t.x,t.y);//this不能用于指代非构造函数
}
}
课堂练习:
1.classTest{
publicintt=4;
publicstaticvoidmain(Stringargs[]){
newTest().numberPlay();
}
voidnumberPlay(){
intt=2;
t=t+5;
this.t=this.t-2;
t=t-this.t;
System.out.print(t+"");
System.out.print(this.t);
}
}
运行结果:
52
2.求两点间距离。
(设计点类,
构造函数重载,
方法重载distance(Pointp),distance(intx,inty)
toString()方法)
继承
继承性是软件重用的一种形式。
继承是将相关类组成层次结构,允许新类从已存在的类中派生,通过保留它们的属性(即实例变量)和方法,并根据自己的要求添加新的属性和方法。
派生出的新类称为子类,子类的直接祖先称为父类,也称为基类,而间接祖先称为超类。
Java支持单继承,不支持多继承。
子类的对象也是其超类的对象。
Java继承的语法:
class类名extends超类名{
……
}
例:
classPoint{
intx,y;
Point(intx,inty){this.x=x;this.y=y;}
Point(){this.x=0;this.y=0;}//Point()一定不能省略(见关键字super)
)
classCircleextendsPoint{
intradius;
Circle(intr,intx,inty){
radius=r;
this.x=x;
this.y=y;
}
}
关键字super
子类不能继承超类的构造函数,但子类构造函数可以通过super调用超类的构造函数。
创建一个子类对象时,首先执行超类构造函数,然后执行子类的构造函数。
例:
classPoint{
intx,y;
Point(intx,inty){
this.x=x;
this.y=y;
}
}
classCircleextendsPoint{
intradium;
Circle(intx,inty,intr){
super(x,y);
radium=r;
}
}
注:
super必须写在子类构造函数的第一行。
1.子类的构造的过程中必须调用其父类的构造方法。
(子类对象中含有父类对象)
2.子类可以在自己的构造方法中使用super(参数列表)调用父类的构造方法。
3.如果子类的构造方法中没有显示地调用父类的构造方法,则系统默认调用父类无参数的构造方法。
4.如果子类构造方法中既没有显式调用父类构造方法,而父类中又没有无参的构造方法,则编译出错。
练习:
classA{
voidprint(Strings){
System.out.println(s);
}
A(){
print("A()");
}
voidf(){
print("A:
f()");
}
}
classBextendsA{
B(){
print("B()");
}
/*
voidf(){
print(“B:
f()”);
}
*/
publicstaticvoidmain(Stringargs[]){
Bb=newB();
b.f();
}
}
分析运行结果:
Sandwich.java
方法的覆盖
定义:
若子类中定义的某个方法的特征与父类中定义的某个方法的特征完全一样,那么就说子类中的这个方法覆盖了父类中相对应的那个方法。
例:
p481.java
总结:
1.方法的覆盖出现在父类与子类之间,并且方法的特征要完全相同。
2.方法的重载可能出现在一个类中,也可能分别出现在父类与子类中,方法的特征一定不完全相同。
方法的动态调用
方法的动态调用:
当运行程序时,基于被存储的对象类型而不是变量类型去选择被调用方法。
基类变量可存储任何派生类对象的引用,因此在程序运行时动态地选择哪种方法执行,程序编译时是无法选择的。
getClass():
返回定义对象的类
getName():
返回类名
在继承的类层次中,通过子类对象调用方法时,将发生如下操作:
1.子类检查是否具有同名和同参数类型的方法,若有就调用该方法。
2.到父类中寻找同名和同参数类型的方法,若有就调用该方法。
由于java支持继承性,所以可以查找父类,直到继承链停止或找到相匹配的方法,若找不到,将产生编译错误。
多态性:
1.方法重载实现了Java的编译时多态,即由编译器在编译时刻确定具体调用哪个被重载的方法。
2.方法覆盖实现了Java的运行时多态,即在程序运行时根据变量引用的具体对象类型动态的选择方法执行。
(条件:
要有继承、要有覆盖、父类引用指向子类对象)
例:
1.p483.java
2.p482.java
多态性不适合于继承链中的实例变量
finalize
java具有垃圾自动回收的能力。
System.gc()进行内存垃圾收集。
protectedvoidfinalize()throwsThrowable
当垃圾收集器确认内存中已不存在对一个对象的引用,该方法被垃圾收集器调用,用于回收对象占用的内存。
子类可以覆盖此方法,用于释放系统资源或执行其他的清除工作。
例:
p413.java
static
static变量:
又称静态变量、类变量(属于整个类)。
1.为该类的所有对象共享。
2.各对象对静态变量的修改会直接影响到其他对象。
3.即使该类没有创建对象,该变量仍然存在。
定义:
static类型变量名;
初始化:
1.在定义时初始化。
如:
staticdoublepi=3.14;
2.可以在静态初始化块中初始化。
如:
p414.java静态初始化块.java
静态初始化块与非静态初始化块的区别:
(1)在类加载时执行一次静态初始化块,且只能初始化类中的静态数据变量。
(2)非静态初始化块在每个对象建立时执行,并能初始化类中的实例变量。
引用:
类名.变量
或对象.变量
static方法:
又称静态方法、类方法。
1.属于整个类
2.静态方法内部不能出现实例变量和其他非静态方法。
3.静态方法中不能使用this和super关键字。
引用:
类名.方法名
关键字final
final数据:
只能被引用,不能被修改。
1.final修饰的局部变量和实例变量必须给出初始值。
2.final修饰的形参表示该参数在方法体内不能被修改。
final方法:
该方法不能被子类覆盖,成为终极方法。
1.可以保持父类中的某方法的行为在被继承时不发生改变。
2.提高运行效率。
3.可以被子类继承和重载。
final类:
该类不能被其他类继承,成为终极类。
组合与继承
软件重用:
继承、对象组合。
例:
p417.java
对象的类型转换
在具有继承关系的父类和子类之间进行对象的类型转换,
1.向上转换
从特殊类型到通用类型的转换。
可能丢失子类中定义的方法和变量。
2.向下转换
例:
publicstaticvoidmain(String[]args){
Pointp=newpoint(1,1);
Circlec;
c=(Circle)p;//类型强制向下转换
}
编译通过,但产生类型转换异常:
classCastException。
在类型转换之前进行对象类型验证,检查某对象是否属于另一个类的实例。
pinstanceofCircle:
判断p所引用的对象是否是Circle类的实例。
抽象类和抽象方法
抽象类:
表示一种抽象概念,不能被实例化一个对象。
继承它的子类可以对其进行具体实现。
作用:
提供一种适当的超类,子类可以通过继承来实现其抽象的方法。
抽象方法:
是指那些具有方法特征,但没有具体程序代码的方法。
抽象类中可以有静态变量、实例变量和非抽象的方法。
例:
abstractclassinstrument{
inti;
abstractvoidplay();
voidprint(){System.out.println(“instrument!
”);}
}
例:
music.javaShape.java
Animal.java
练习:
题目一:
设计一分数类。
要求分数类包括分子和分母两个成员变量,同时类中应包含分数运算的各种方法。
例如,方法应包括两个分数的加、减、乘、除等。
分数的格式应该是:
分子/分母。
最后,编写一个测试程序进行测试。
TestFs.java
题目二:
设计一长方形类。
成员变量包含长度和宽度。
类中除了包含计算周长和面积的方法外,还应该能够用set方法来设置长方形的长度和宽度,以及能够用get方法来获得长方形的长度和宽度。
最后,编写一测试程序来测试所定义的长方形类能否实现预定的功能。
题目三:
500个人围成一圈,数3退1,用面向对象的方法。
CountNum.java
题目四:
类的组合:
设计点类,直线类(计算两点间距离)。