资源描述
1第第4章章 面向对象编程面向对象编程2 主要任务: 理解面向对象编程的基本概念 了解类的封装方法 如何创建类和对象 了解成员变量和成员方法的特性 学习使用OOP方式进行程序设计 24.3 成员变量与封装成员变量与封装l成员变量描述了类和对象的状态,有时也称为属性、数据、域(field)。l对成员变量的操作实际上就是改变类和对象的状态,使之能满足程序的需要。与类相似,成员变量也有很多修饰符,用来控制对成员变量的访问,实现对类和对象的封装。34.3.1成员变量的声明成员变量的声明l 例4.4 显示当前日期和时间,运行结果见图:4import java.awt.Graphics;import java.applet.Applet;import java.util.Calendar;class Time private Calendar t; private int y, m, d, hh, mm, ss;5 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); 6public String getDate() return y+ 年+m+月+d+日; public String getTime() String s=hh+ 时+mm+分+ss+秒; return s; 7public class ShowTime extends Applet Time t=new Time(); public void paint(Graphics g) g.drawString(当前日期:+t.getDate(),50,40); g.drawString(当前时间:+t.getTime(),50,80); 84.3.2 成员变量的修饰成员变量的修饰l成员变量的声明语句有如下格式: public private protected package / 访问控制修饰符 static final transient volatile 91访问控制权限l(1)public 公共变量 由public修饰的变量称为公共变量,可被任何包中的任何类访问,只有在确认任何外部访问都不会带来不良后果的情况下才将成员声明为公共的。公共变量对任何类都是可见的,因此它没有秘密可言,不具有数据保护功能。 l(2)private私有变量 由private修饰的变量称为私有变量,只能被声明它的类所使用,拒绝任何外部类的访问。私有变量是不公开的,它们得到了最好的保护,这是对类进行封装时使用的主要方法。10l(3)protected 受保护变量 由protected修饰的变量称为受保护变量,可被声明它的类和派生的子类以及同一个包中的类访问。 l(4)package包变量 由package修饰的变量称为包变量,在声明时常常省略package关键字,即没有修饰符的成员被视为包成员。包成员可被声明它的类和同一个包中的其它类(包括派生子类)所访问,在其它包中的子类则不能访问父类的包成员。 112static 静态变量lstatic声明的成员变量被视为类的成员变量,而不把它当作实例对象的成员变量。换句话说,静态变量是类固有的,可以直接引用,其它成员变量仅仅被声明,生成实例对象后才存在,才可以被引用。基于这样的事实,也把静态变量称为类变量,非静态变量称为实例变量。相应地,静态方法称为类方法,非静态方法称为实例方法。 12例4.5 静态变量的使用。class StaticDemo static int x; int y; static public int getX() return x; static public void setX(int newX) x = newX; 13 public int getY() return y; public void setY(int newY) y = newY; 14public class ShowDemo public static void main(String args) System.out.println(静态变量x=+StaticDemo.getX(); System.out.println(实例变量y=+StaticDemo.getY(); / 非法,编译时将出错 StaticDemo a= new StaticDemo(); StaticDemo b= new StaticDemo();15 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(); 16对上面的源程序进行编译会出现如图所示结果,不能进行运行该程序。17 将源程序中的出错语句删除或使用解释符/隐藏起来如: /System.out.println(“实例变量y=”+StaticDemo.getY(); / 非法,编译时将出错,再进行编译,即可执行该程序,结果如图所示。18从输出结果中可以得出以下几点结论 :l 类的静态变量可以直接引用,例如在程序中直接使用了StaticDemo.getX(),而非静态变量则不行。类的静态变量相当于某些程序语言的全局变量。l 静态方法只能使用静态变量,不能使用实例变量。 l 类的静态变量只有一个版本,所有实例对象引用的都是同一个版本。 l 对象实例化后,每个实例变量都被制作了一个副本,它们之间互不影响。 193final 最终变量l一旦成员变量被声明为final,在程序运行中将不能被改变。这样的成员变量就是一个常量。例如: final double PI=3.14159;l该语句声明一个常量PI,如果在后面试图重新对它赋值,将产生编译错误。另外,常量名一般用大写字母。常量和直接量一样不占用内存空间。204transient 过渡变量lJava语言目前对transient修饰符没有明确说明,它一般用在对象序列化(object serialization)上,说明成员变量不许被序列化。5volatile 易失变量lvolatile声明的成员变量为易失变量,用来防止编译器对该成员进行某种优化。这是Java语言的高级特性,仅被少数程序员使用。214.4 成员方法成员方法l对象的行为由类的方法实现,其它对象可以调用一个对象的方法,通过消息的传递实现对该对象行为的控制。l下面讨论如何通过方法影响对象的行为。224.4.1 成员方法的设计成员方法的设计l类的设计集中体现在成员方法的设计上。良好的设计可以使类更加强壮,功能更加完善。成员方法的设计应该从类的整体行为出发,能正确响应外部消息,自然地改变对象的状态,并符合相对独立性、结构清晰、可重用性强等编程要求。l来看下面的例子:23例4.6 方法对对象行为的影响,运行结果见图:24import java.awt.*;import java.applet.Applet;class DrawShape private int x, y, shape; public void setPos(int xPos, int yPos) x=xPos; y=yPos; 25 public void setShape(int choice) shape=choice; public void draw(Graphics g) if (shape =1) g.drawRect(x, y, 60, 60); else if (shape =2) g.drawOval(x, y, 60, 60); else g.drawString(形状参数不对!, 20, 120); 26public class M1 extends Applet final int BOX=1, OVAL=2; DrawShape a=new DrawShape(); public void paint(Graphics g) a.setPos(40,20); a.setShape(BOX); a.draw(g); a.setPos(200,60); a.setShape(OVAL); a.draw(g); 274.4.2 成员方法的声明与修饰成员方法的声明与修饰l 成员方法相当于其它语言的函数或过程,是命令语句的集合。成员方法的声明一般放在成员变量的声明之后,声明语句的格式和顺序如下: public private protected package / 访问控制修饰符 static final abstract native synchronized 返回值类型 方法名(参数表)throws 异常类型28不同含义的修饰符 :1final 最终方法l 方法被声明为最终方法后,将不能被子类覆盖,即最终方法能被子类继承和使用但不能在子类中修改或重新定义它。这种修饰可以保护一些重要的方法不被修改,尤其是那些对类的状态和行为有关键性作用的方法被保护以后,可以避免未知情况的发生。l 在OOP中,子类可以把父类的方法重新定义,使之具有新功能但又和父类的方法同名、同参数、同返回值,这种情况称为方法覆盖(override)。292abstract 抽象方法l 一个抽象类可以含有抽象方法。所谓抽象方法是指不能实现的方法,因为它没有方法体,所以抽象方法不能出现在非抽象类中。l 为什么要使用抽象类和抽象方法呢?一个抽象类可以定义一个统一的编程接口,使其子类表现出共同的状态和行为,但各自的细节是不同的。子类共有的行为由抽象类中的抽象方法来约束,而子类行为的具体细节则通过抽象方法的覆盖来实现。这种机制可增加编程的灵活性,也是OOP继承树的衍生基础。303native 本地方法l 用其它语言编写的方法在Java中称为本地方法。如果你有一个用其它语言如C+ 写成的函数,希望在Java中能利用这些资源,你可以编写本地方法。l SDK提供了Java本地接口JNI(Java Native Interface),使得Java虚拟机能运行嵌入在Java程序中的其它语言的代码。这些语言包括C/C+、Fortran、汇编语言等等。l 嵌入外部语言代码出于以下几点考虑:Java系统包不提供对平台依赖性程序的支持时;想利用现有的其它语言资源时;出于运行速度的要求而使用其它语言开发的运行模块。314synchronized 同步方法l 同步方法用于多线程编程。多线程在运行时,可能会同时存取一个数据。为避免数据的不一致性,应将方法声明为同步方法,对数据进行加锁,以保证线程的安全。详细内容请参考第8章。 5throws 异常类型l 程序在运行时可能发生异常现象。每一个异常都对应着一个异常类,如果希望方法忽略某种异常,可将其抛出,使程序得以继续运行。在前面介绍的例中就使用过抛出异常throws IOException(输入/输出异常),有关异常处理的详细内容请参考第6章。326返回值类型l Java要求一个方法必须声明它的返回值类型。如果方法没有返回值就用关键字void作为返回值类型,否则应使用基本数据类型或对象类型说明返回值类型,如下面的语句: public int getX(); void setXY(int x, int y); public String getName(); protected Object clone();l 其中,getX的返回值为int类型,setXY没有返回值,getName的返回值是String类。而clone的返回值则为Object类。337方法名l 方法名可以是任何有效的方法名可以是任何有效的Java标识符。方法标识符。方法名可以和成员变量同名,也可以和成员方法名可以和成员变量同名,也可以和成员方法同名。同一个类中的方法同名现象在同名。同一个类中的方法同名现象在OOP中中称为方法重载(称为方法重载(overload),重载使一个类),重载使一个类的多个方法享有同一个名称,可以减轻程序的多个方法享有同一个名称,可以减轻程序员的负担。员的负担。 8参数表l 方法的调用者正是通过参数表将外部消息传方法的调用者正是通过参数表将外部消息传递给方法加以处理的。在参数表中要声明参递给方法加以处理的。在参数表中要声明参数的类型,并用逗号分隔多个参数。数的类型,并用逗号分隔多个参数。344.4.3 方法体方法体l方法体包含在一对大括号中,即使方法体中没有语句,一对大括号也是必不可少的。使用各种语句结构组成方法主体,实现程序的功能,是设计方法体的目的。下面这段程序是一个处理格式化字符串的方法: public String toString(int arr) int i, n=arr.size(); StringBuffer s=new StringBuffer();35 s.append(); for (i=0; in; i+) s.append (Integer.toString(arri); if (in-1) s.append(,); s.append(); return s.toString();364.4.4 消息传递消息传递l 一个对象和外部交换信息主要靠方法的参数来传递。当然,如果允许的话,外部对象也可以直接存取一个对象的成员变量。出于整体考虑,大部分还是通过参数来传递。在Java中,可传递的参数包括任何数据类型,前面已经使用了基本数据类型的参数传递、数组的传递和对象的传递。 l 在其它语言中,函数调用或过程调用有传值调用和传地址调用之分。 37例4.7 参数传递示例1class P1 public static void main(String args) int x=10, y=10; doPower(x, y); System.out.println(x=+x+, y=+y); static void doPower(int passX, int passY) passX=passX*passX; passY=passY*passY; System.out.println(passX=+passX+, passY=+passY); 38例4.8 参数传递示例2 class P2 public static void main(String args) Power p=new Power(); p.doPower(10,10); System.out.println(x=+p.x+, y=+p.y); class Power int x, y; void doPower(int passX, int passY) x=passX*passX; y=passY*passY; 394.4.5 Java编程小结编程小结l 源程序的文件名和程序中定义的主类名应保持一致,包括字母大小写的匹配。l Java严格区分大小写,例如applet和Applet代表了不同的含义。l 语句以分号结束。l 程序中可加注释,用双斜杠“/”引导,“/* */”可包含多行注释。l 注意设计一般类与主类,一般类可以有多个,主类只能有一个,源程序名与主类名相同。
展开阅读全文