知ing

Java语言程序设计(第三版)

邵丽萍,邵光亚,张后扬 编 / 清华大学出版社

拼命菇凉@ 上传

查看本书

4.1  面向对象基本概念
4.1.1  对象
  对象:相关数据和方法的集合
4.1.2  封装
  封装的含义是把类设计成一个黑箱,使用者只能看见类中定义的公共方法,而看不到方法实现的细节,也不能直接对类的数据进行操作,迫使用户通过接口去访问数据。
  封装是一种信息隐蔽技术,封装的定义为:
  (1)一个清楚的边界;所有对象的内部软件的范围被限定在这个边界内;
  (2)一个接口:这个接口描述该对象和其他对象之间的相互作用;
  (3)受保护的内部实现:这个实现给出了由软件对象提供的功能的细节,实现细节不能在定义这个对象的类的外面访问。
4.1.3  消息
  对象的行为由方法来实现,消息传递是对象之间进行交互的主要方式。
  构成消息的3个要素是:接收消息的对象、接收消息后进行处理的方法和方法所需要的参数。
4.1.4  类
  类是一种复杂的数据类型,是将不同类型的数据和这些数据相关的运算(即方法)封装在一起的集合体。它是对所要处理的问题的抽象描述。
4.1.5  继承
  一个类的上一层称为父类,而下一层称为子类,一个类可以继承其父类的变量和方法,且这种继承具有传递性。
4.1.6  接口
  接口可以看成是为两个不相关的提供交流途径的工具,是一个包含方法定义和常量值的集合。
  Java不支持多继承,子类只能有一个父类,有时需要使用其他类中的方法,但又无法直接继承,这时可以使用接口技术。
  接口不需要建立继承关系,就可以使两个不相关的类进行交互。
  
  体现面向对象思想的程序:见P60
4.2  Java的类与对象
  Java程序的所有数据类型都是用类来实现的,Java语言是建立在类这个逻辑结构之上的,所以Java是一种完全面对象的程序设计语言。类是Java的核心,Java程序都由类组成,一个程序至少包含一个类,也可以包含多个类。对象是类的实例,Java程序中可以使用标识符表示对象,并通过对象引用类中的变量和方法。
  Java程序员的任务就是设计出类和对象来解决实际问题。创建类时既可以从父类继承,也可以自行定义。
4.2.1  类的创建
  格式: [修饰符] <class> <类名> [extends 父类] [implements接口]
       {  类体(成员变量和成员方法)    }
  修饰符:指明类在使用时所受到的限制,包括类访问权限[public]和其他特性[abstract],[final]
  例:public class C1  { …… }
    public class C2 extends Applet implements ActionListener
     {……}
  1.class  <类名>
  告诉编译器这是一个类
  2.Public(公共的)
  在没有任何修饰符的默认情况下,类只能被同一个源程序文件或同一个包中的其他类使用,加上public后,该类可以被任何包中的类使用,称为公共类。
  注意:在同一个源程序文件中不能出现两个及以上的public类,否则编译器会告诉你将第二个public类放在另一个文件中。
  3.abstract(抽象的)
  abstract说明的类称为抽象类,不能用它实例化一个对象,它只能被继承,abstract方法是不含代码的方法,需要以后的子类中重载实现,abstract类的子类必须实例化(实现)abstract方法,或将自己也声明为abstract。这对于定义概念是有用的。
  4.final(最终的)
  final说明的类称为最终类,最终类不能被继承
  Java中的String和Array类就是一个final类
  注意:final和abstract不能同时修饰一个类(出错),这样的类没有意义
  
  无修饰符是默认方式,即不使用上述三种修饰符。因此它们的优势和限制都没有作用,无修饰符的类可以被其他类访问和继承,但只有在相同程序包中的那些对象才可能使用这样的类。
  5.extends(继承)父类名
  extends告诉编译器创建的类是从父类继承下来的子类,父类必须是Java系统类或已经定义的类。
  从父类继承,可以提高代码重用性,不必从头开始设计程序。
  6.implements(实现)接口名
  implements告诉编译器类实现的接口,接口必须有定义,一般为系统类。
  接口是消息传递的通道,通过接口,消息才能传递到处理方法中进行处理。implements说明你的类可以实现的一个或多个接口,如果有多个接口,要用逗号分隔。
  例:import java.awt.*;
    import java.applet.*;
    public class ch3 extends Applet{
       public void paint(Graphics g)   {
        g.drawString("Hello Java!I love you^_^",25,25);  } }
  
    <html>
    <head>
    <title>Hello Java Applet测试</title>
    </head>
    <APPLET code=ch3.class width=200 height=40>
    抱歉,你的浏览器不支持JAVA APPLET┅
    </APPLET>
    </html>
4.2.2  对象的创建
  类的对象的模板,Java运行应该是用类创建实例化对象。
  一旦任务完成,对象就会被垃圾收集器收回,完成它从创建、使用到清除。
  见P66 例4.3
  1.创建对象与构造方法
创建对象格式:  类名 对象名=new 类名([参数]) ;
  说明:(1)运算符new为对象分配内存空间;
    (2)生成对象的最后一步是执行构造方法;
    (3)创建对象相当于定义一个变量,即分两步进行。
创建对象分成两步:  类名 对象名 ;
          对象名=new 类名([参数]) ;

  2.对象初始化的说明
  (1)系统如何对变量初始化
  当用new创建了一个对象时,系统会为对象中的变量进行初始化。即不但为变量分配相应的存储单元,还设置相应初值。系统为byte , short , int , long类型设置初值为0;float类型变量初值为0.0f;double类型变量初值为0.0;char字符型变量为’u\0000’;boolean逻辑变量初值为false;引用类型初值勤为null。
  (2)构造方法的作用与构成
  new操作符为对象分配内存后将调用类的构造方法确定对象的初始状态,初始化所有变量。
  构造方法功能:创建对象时,用给定的值,将对象初始化
  构造方法特点:
  (1)构造方法名与类名相同,且不指定类型说明;
  (2)可以重载,即可以定义多个参数个数不同的函数,系统可以根据参数的不同,自动调用正确的构造方法;
  (3)程序中不能直接调用构造函数,在创建对象时系统自动;
  (4)可以不设计构造方法,若在初始化时还要执行一些其他命令,就必须设计构造方法,因为Java规定命令语句不能出现在类体中,只能放在方法中。
  重载:参数不同可以是数量不同,类型不同,或两者都不同,但重载方法必须有相同的方法名和相同的返回类型。
  例:class  ABC{
     public ABC( )  {……}  // 无参数构造方法
     public ABC(int a, int b )  {……}  // 带两个参数构造方法
     public ABC(String a )  {……}  // 带一个个参数构造方法
     public int ABC(int a) {……}  // 错,构造方法不能有类型返回值
     public void ABC( )  {……}  // 错,构造方法不能有类型返回值
  }
    例:public class SC{
      public static void main(String args[]){
        sc1 a=new sc1( ) ;
        sc1 b=new sc1("练习") ;
        System.out.println("程序结束!");} }
      
      class sc1{
         public sc1( )   {System.out.print("开始");}
         public sc1(String z)  {System.out.println(z);}  }
  运行结果:开始练习
       程序结束
  3.对象的使用
    格式:<对象名>.<变量名>
       <对象名>.<方法名([参数])>
    例:SC a =new SC( ) //SC是已定义的类,a则是新建的SC对象
      a.bian=23  // 将对象a的变量bian赋值23
      a.Fan( )      //  调用对象a的方法Fan
      
    
    例:class parents{
      private String name[]=new String[5];
      parents(String s[])
      {for(int i=0;i<s.length;i++)
       name[i]=s[i];  }
      public void showname()
      {for(int i=0;i<s.length;i++)
        System.out.print(name[i]+”   ”);
      }}
      
      class SC
      { public static void main(String args[])
      { String name[]={"Zhang","Wang","Li"};
        parents p=parents(name);
        p.showname()
      }}
  结果: 输出 Zhang  Wang  Li
  例:public class  NewClass{
      public static void  main(String  args[]){
        G  k=new  G();
        k.setK(8);
        int  y=k.getK();
        System.out.println(“y=”+y); }
    }}
    class  G{
      private  int  k;
      public  void  setK(int  x){
         k=x;  }
      public  int  getK(){  return  k;}
    }}
  运行结果:  y=8
    
  
  
  
  4.清除对象
  Java引入了新的内存管理机制,由Java虚拟机担当垃圾收集器的工作。你可以任意创建对象,而不用担心如何清除它们,垃圾收集器会自动清除它们。
  如果要明确地清除一个对象,可以自行清除它。只需把一个空值赋给这个对象引用即可。如
  SC a =new SC( )
  ……
  a=null  // 将对象a从内存中清除
  5.析构方法(finalize)(补充)
  析构方法(finalize)与构造方法相对应,当对象已经无用,需要清除时,编译器将自动调用对象的finalize方法。析构方法一般是做一些清除工作,如关闭打开的文件等,但不能执行用户输入操作或与其他对象进行交互。
  如  class  ABC{
     ……
     protected|public  void  finalize( )
     { // do some cleanup code    }  }
4.3  成员变量与封装
  成员变量描述了类和对象的状态,有时也称为属性、数据或域
4.3.1  成员变量的声明
  成员变量的声明必须放在类体中,通常是在成员方法之前。在方法中声明的变量不是成员变量,而是方法的局部变量,二者是有区别的。
  例:见P71
4.3.2  成员变量的修饰
  声明变量格式:[public][private][protected][package]  //访问控制修饰符
      [static][final][transient][volatile]<数据类型><成员变量名称>
  1.访问控制权限
          表: 修饰符的作用范围
修饰符

子类

所有类和包
Public




Private


Protected


package(默认)

  (1)public(公共)变量
  由public修饰的变量称为公共变量,可被任何包中的任何类访问
  (2)private(私有)变量
  由private修饰的变量称为私有变量,只能被声明它的类所使用
  (3)protected(受保护)变量
  由protected修饰的变量称为受保护变量,可被声明它的类和派生的子类以及同一个包中的类访问
  (4)package(包)变量
  由package修饰的变量称为包变量,没有修饰符时,默认变量即是包变量,可被声明它的类和同一个包中的其他类(包括派生子类)访问
  2.static(静态)变量
  由static修饰的变量称为静态变量,静态变量是类固有的,可以直接引用(方法:类名.静态变量名),其他成员变量仅仅被声明,只有等到生成实例对象后才存在,才可以被引用,静态变量也称为类变量,非静态变量称为实例变量。相应地静态方法称为类方法,非静态方法称为实例方法。
  静态变量可被此类创建的所有对象共享。
  例:class Car {
      String 车型;
      static int 价格;
      public Car(String 车型, int 价格)
       { this.车型=车型;
        this.价格=价格; }
      public void 介绍(String s)
         {System.out.println(s+"\t"+车型+"\t"+"价格 "+价格);}  }
     public class SC{
    public static void main(String args[]){
      Car 奔驰=new  Car("越野车",400000)  ;
          奔驰.介绍("奔驰");
      Car 红旗=new  Car("轿车",200000)  ;
          红旗.介绍("红旗");
          奔驰.介绍("奔驰");       }}
    运行结果:奔驰    越野车   价格 400000
         红旗    轿车     价格 200000
         奔驰    越野车   价格 200000
  3.final(最终)变量
  一旦成员变量被声明为final,在程序运行中将不能被改变,即是一个常量。
  如: final  int  I=5 ;
     final  double  PI=3.1415926  ;
  4.transient(过渡)变量(不做要求)
  Java目前对transient修饰符没有明确说明,它一般用在对象序列化(object serialization)上,说明成员变量不许被序列化。
  5.volatile(易失)变量(不做要求)
  volatile声明的成员变量为易失变量,用来防止编译器对该成员进行某种优化。这是Java语言的高级特性,仅被少数程序员使用。
4.4  成员方法
  对象的行为由类的方法实现,实际上,方法就是完成某种功能的程序块。从功能上讲,方法和函数十分类似。
4.4.1  成员方法的设计
  例:见P77
4.4.2  成员方法的声明与修饰
  格式:[public][private][protected][package][static][final][abstract][native]
     [synchronized] 返回值类型 方法名(参数表)[throws 异常类型]
  说明:[public][private][protected][package][static] [final]与成员变量功能相同,都是定义方法访问权限。
  1.final(最终)方法
  方法被声明为最终方法后,将不能被子类覆盖,即最终方法,能被子类继承和使用但不能在子类中修改或重新定义它。这种修饰可以保护一些重要的方法不被修改。
  在OOP中,子类可以把父类的方法重新定义,使之具有新功能但又和父类的方法同名、同参数、同返回值,这种情况称为方法覆盖(override)。
  2.abstract(抽象)方法
  抽象方法即无方法体的方法,抽象方法不能出现在非抽象类中。
  为什么要使用抽象类和抽象方法呢?一个抽象类可以定义一个统一的编程接口,使其子类表现出共同的状态和行为,但各自细节是不同的。子类共有的行为由抽象类中的抽象方法来约束,而子类行为的具体细节则通过抽象方法的覆盖来实现。这种机制可增加编程的灵活性,也是OOP继承树的衍生基础。
  3.native(本地)方法(不做要求)
  用其他语言编写的方法在Java中称为本地方法。
  SDK提供了Java本地接口JNI(Java Native Interface),使得Java虚拟机能运行嵌入在Java程序中的其他语言,这些语言包括C/C++ ,FORTRAN ,汇编语言等。
  4.synchronized(同步)方法
  同步方法用于多线程编程。多线程在运行时,要能会同时存取一个数据。为避免数据的不一致性,应将方法声明为同步方法,对数据进行加锁。
  5.throws(异常)类型
  程序在运行时可能发生异常现象。每一个异常对象都对应着一个异常类,如果暂时不希望方法处理某种异常,可将其抛出,使程序得以继续运行。
  如:protected void  SC( )  throws IOException ;  //输入输出异常抛出
  6.返回值类型
  Java要求一个方法必须声明它的返回值类型,如果方法没有返回值就用关键字void作为返回值类型。否则应使用基本数据类型或对象类型说明返回值类型。
  如:  public  void  SC( )  ;      // 没有返回值
    int getx( ) ;                 // 返回值是int类型
    private  String  abc( ) ;      // 返回值是String类型
    public  static double  du( ) ;  // 返回值是double类型
    protected Object  oj( ) ;      // 返回值是Object类型
  7.方法名
  方法名要以是任何有效的Java标识符,方法名可以和成员变量同名,也可以和成员方法同名。同一个类中的方法同名现象在OOP中称为方法重载(overload)。
  如:   void  SC( ) {……} 
      void  SC(int a ) {……} 
      void  SC(int a, int b) {……} 
      void  SC(double a, int b) {……} 
  8.参数表
  方法的调用者正是通过参数表将外部消息传递给方法的。在参数表中要声明参数的类型,并用逗号分隔多个参数。
4.4.3  方法体
  方法体包含在一对大括号中,即使方法体中没有语句,一对大括号也是必不可少的。
4.4.4  消息传递
  一个对象和外部交换信息主要靠方法的参数来传递,如果允许的话,外部对象也可以直接存取一个对象的成员变量。
  在Java中调用方法时,如果传递的参数是基本数据类型,在方法中将不能改变参数的值,你只能使用它们。如果传递的是对象引用,你也不能在方法中修改这个引用,但可以调用对象的方法以及修改允许存取的成员变量。所以想改变参数的值,可采用传递对象的方法,间接修改参数的值。
  例1:class SC{
       public static void main(String[] args){  
         int m=10, n=20 ;
         Power p=new Power( ) ;
         p.doPower(m , n);
         System.out.println("x="+m+",y="+n);
         System.out.println("x="+p.x+",y="+p.y) ;  } }
    class Power{
       int x , y ;
       void doPower(int a , int b)
        { x=a*a  ;
         y=b*b ; } }
  运行结果:x=10,y=20
       x=100,y=400 
  例2:class SC{
      float  ptValue ;  //成员变量
      public static void main(String[] args){
        int  val=11 ; // 局部变量
        SC  pt=new SC( ) ;
        System.out.println("val1="+val) ;
        pt.changeInt(val) ;
        System.out.println("val2="+val) ;
        pt.ptValue=101f ; //float类型,加f
        System.out.println("valValue1="+pt.ptValue) ;
        pt.ChangeObj(pt) ;
        System.out.println("valValue2="+pt.ptValue) ;  }
  
    public void changeInt(int value) //参数是简单类型
      {value=55 ; }
    public void ChangeObj(SC ref)//参数是对象引用类型
      {ref.ptValue=99f ; }
  }
  运行结果:val1=11
       val2=11
       valValue1=101.0
       valValue2=99.0

作业:P87-16  class Rectangle {
      double width,height;
      double zc(double b1,double b2)
         { return 2*(b1+b2); }
      double mj(double b1,double b2)
         { return b1*b2; }}
      public class SC{
      public static void main(String args[]){
         Rectangle r=new Rectangle();
         r.width=10 ; r.height=20;
        System.out.println("周长="+r.zc(r.width,r.height)) ;
        System.out.println("面积="+r.mj(r.width,r.height)) ;  }}
作业:P87-17  public class SC{
    public static void main(String args[]) {
      int m[]={1,2,3,4,5};
      Array A=new Array(m);
      A.sum( );
      System.out.println(A.getsum());  }}
    class Array{
      private int n[];
      int sum=0;
      Array(int i[])  { n=i; }
      void sum( ){
        for (int x=0;x<n.length;x++)
           sum=sum+n[x] ;  }
      int getsum( ){
        return sum;  } }

查看更多