对象和类(下)

来源:互联网 发布:北京 db2数据库培训 编辑:程序博客网 时间:2024/06/14 12:21
Top
  1. 对象和类(下)
  2. 数组

1. 对象和类(下)

1.1. 方法的重载

1.1.1. 方法的签名

方法的签名包含如下两个方面:方法名和参数列表。

Java语法规定,一个类中不可以有两个方法签名完全相同的方法,即:一个类中不可以有两个方法的方法名和参数列表都完全相同,但是,如果一个类的两个方法只是方法名相同而参数列表不同,是可以的。下面看如下代码:

copytextpop-up
  1. public class Cashier {
  2. public boolean pay(double money) {}
  3. public boolean pay(double money) {}
  4. }
public class Cashier {    public boolean pay(double money) { … }    public boolean pay(double money) { …}}

分析如上代码,结论会出现编译错误,因为在同一个类Cashier中的两个方法,签名相同,这在java语法中是不允许出现的。而下面的代码就是正确的:

copytextpop-up
  1. public class Cashier {
  2. public boolean pay(double money) {}
  3. public boolean pay(String cardId,
  4. String cardPwd) {}
  5. }
public class Cashier {    public boolean pay(double money) { … }    public boolean pay(String cardId,                                     String cardPwd) { … }}

可以看到上面的代码,在类Cashier中,虽然pay方法名相同,但是参数列表不同,这样是被允许的,可以正常编译通过。

1.1.2. 方法重载及其意义

假想收款窗口的设计,可以采用两种方式:

  1. 开设三个窗口,分别用来接收现金,信用卡和支票的交付方式(分别在窗口上标明),用户根据需要选择窗口,并投入指定的物件,如图 – 8所示:

图- 8

  1. 开设一个窗口,标为“收款”,可以接收现金,信用卡和支票三种物件。该窗口可以按照输入的不同物件实施不同的操作。例如,如果输入的是现金则按现金支付,如果输入的是信用卡则按信用卡支付,以此类推,如图 – 9所示。

图- 9

通过对如上两种方式的分析,请问:哪种方式更好一些呢?常规情况下认为,相对于A的方式,B的设计可以降低用户的负担,用户去付款时不需要去找对应的窗口,只需要到收款窗口就可以了, 减少了用户使用时的错误,B的设计更加优雅一些。

按B的设计方式即为方法重载,在Java语言中,允许多个方法的名称相同,但参数列表不同,此种方式称为方法的重载(overload)。

下面的代码即为收款窗口的两种设计方式,可以看出B方式即为方法的重载方式。

copytextpop-up
  1. public class PayMoney { //----------A方式
  2. payByCash(double money) { }
  3. payByCard(String cardId,StringcardPwd) { }
  4. payByCheck(String compayName,double money) { }
  5. }
  6. public class PayMoney { //-----------B方式
  7. pay(double money) { }
  8. pay(String cardId,StringcardPwd) { }
  9. pay(String compayName,double money) { }
  10. }
public class PayMoney {      //----------A方式      …payByCash(double money) {  }      …payByCard(String cardId,StringcardPwd) {  }      …payByCheck(String compayName,double money) {  } }public class PayMoney {     //-----------B方式      …pay(double money) {  }      …pay(String cardId,StringcardPwd) {  }      …pay(String compayName,double money) {  } }

通过如上的代码可以看出,按照A的方式若想付款,需在三个方法之中进行选择,不同的方法即为不同的付款方式,而B的方式即为重载方式,若想付款,只需要找到pay方法,只不过,传递不同的参数即可。

1.1.3. 编译时根据签名绑定调用方法

当调用重载的方法时,编译器会在编译时根据签名的不同来绑定调用不同的方法,可以把重载的方法看成是完全不同的方法,只不过,恰好方法名称相同而已。请看下面的两组代码:

重载方法:

copytextpop-up
  1. pay(double money) { }
  2. pay(String cardId,StringcardPwd) { }
  3. pay(String compayName,double money) { }
…pay(double money) {  }…pay(String cardId,StringcardPwd) {  }…pay(String compayName,double money) {  }

调用方法:(只管调用即可,由编译器来根据签名绑定不同的方法)

copytextpop-up
  1. pay(8888.88)
  2. pay(12345678,666666);    
  3. pay( “tarena”, 8888.88);
pay(8888.88);pay(“12345678”,”666666”);pay( “tarena”, 8888.88);

1.2. 构造方法

1.2.1. 构造方法语法结构

构造方法是在类中定义的方法, 但不同于其他的方法,构造方法的定义有如下两点规则:

  1. 构造方法的名称必须与类名相同。
  2. 构造方法没有返回值,但也不能写void。

如下所示为构造方法的语法:

copytextpop-up
  1. 【访问修饰符】类名( ) {
  2. //构造方法体
  3. }
【访问修饰符】类名( ) {     //构造方法体}

1.2.2. 通过构造方法初始化成员变量

Java语言中的构造方法常常用于实现对对象成员变量的初始化,如下代码展示了构造方法的使用。

copytextpop-up
  1. class Cell {
  2. int row ;
  3. int col ;
  4. public Cell (int row1 , int col1){
  5.         row = row1;
  6. col = col1;
  7. }
  8. }
  9. class TestCell {
  10. public static void main(String args[ ] ){
  11. Cell c1 = new Cell( 15 , 6 );
  12.      printCell(c1);
  13. }
  14. }
class  Cell {int  row ;int  col  ; public  Cell (int row1  , int col1){row = row1;    col = col1;    }}class  TestCell {public static void main(String   args[ ] ){Cell   c1 = new Cell( 15 , 6 );    printCell(c1);}}

可以看出,在创建对象时,构造方法写在new关键字之后,可以理解为:“new”创建了对象,而构造方法对该对象进行了初始化。

1.2.3. this关键字的使用

在上面的代码中,为该构造方法定义了两个参数,分别表示行和列。为了区分于Cell类的成员变量row和col,为两个参数分别取名为row1和col1,这显然不是一种好方法,因为,我们会希望依然使用变量row来表示行,col来表示列,而不是row1和col1。为了解决这个问题,需要使用到this关键字。

this关键字用在方法体中,用于指代调用该方法的当前对象,简单的说:哪个对象调用方法,this指的就是哪个对象。严格来讲,在方法中需要通过this关键字指明当前对象。请看如下代码:

copytextpop-up
  1. public void drop ( ) {
  2. this.row ++;    
  3. }
public  void  drop ( ) { this.row ++;}

上面的drop()方法可以解释为:将调用该方法对象的成员变量的row加1。很多时候,为了方便起见,在没有歧义的情况下可以省略this,如下所示:

copytextpop-up
  1. public void drop ( ) {
  2. row ++;    
  3. }
public  void  drop ( ) { row ++;}

在构造方法中,用来初始化成员变量的参数一般和成员变量取相同的名字,这样会有利于代码的可读性,但此处就必须通过this关键字来区分成员变量和参数了,而不能省略this了,如下代码所示:

copytextpop-up
  1. public Cell (int row , int col ) {
  2.     this . row = row ;
  3.     this . col = col ;
  4. }
public   Cell (int  row , int  col ) {this . row = row ;this . col  = col ;}

如上的代码中,this.row表示的为Cell类的成员变量,而row为参数变量。

1.2.4. 默认的构造方法

JAVA语法规定,任何一个类都必须含有构造方法,假如源程序中没有定义,则编译器在编译时将为其添加一个无参的空构造方法(此方法称之为“默认的构造方法”)。

例如:先前所定义的Cell类源文件中没有写构造方法,但也可以编译成功,因为在编译时由编译器为其添加了如下的构造方法:

copytextpop-up
  1. Cell( ) { }
Cell( ) {  } 

但是有一个问题需要注意,当类定义了构造方法后,Java编译器将不再添加默认的构造方法,看如下代码:

copytextpop-up
  1. class Cell{
  2.     int row;
  3. int col;
  4.     Cell (int row,int col){
  5.         this.row = row;
  6.         this.col = col;
  7.     }
  8. }
  9. public class CellGame {
  10. public static void main(String[] args) {
  11. Cell cell = new Cell( ); //编译错误
  12. }
  13. }
class Cell{int row;    int col;Cell (int row,int col){this.row = row;this.col = col;}}public class CellGame {public static void main(String[] args) {        Cell  cell  =  new  Cell( );  //编译错误    }}

可以看出,在创建Cell类对象时,发生了一个编译期错误,那是因为,在Cell类中已经定义了Cell(int,int)的构造方法,此时,编译器将不会再提供无参的构造方法了。所以此处发生了编译期错误。

1.2.5. 构造方法的重载

很多时候,为了使用的方便,可以对一个类定义多个构造方法,这些构造方法都有相同的名称(类名),只是方法的参数不同,称之为构造方法的重载。

在创建对象时,Java编译器会根据不同的参数调用来不同构造方法。看如下的几组构造方法的声明及调用。

copytextpop-up
  1. 声明:
  2. Cell ( int row , int col ) {
  3. }
  4. 调用:
  5. Cell c1 = new Cell ( 5 , 6 )
  6.  
  7. 声明:
  8. Cell ( ) {
  9. }
  10. 调用:
  11. Cell c1 = new Cell ( )
  12.  
  13. 声明:
  14. Cell (int row) {
  15. this(row , row );
  16. }
  17. 调用:
  18. Cell c1 = new Cell ( 5 )
声明:Cell ( int  row , int  col ) {}调用:Cell   c1 = new  Cell ( 5 , 6 );声明:Cell ( )   {  } 调用:Cell  c1 =  new  Cell (  ) ;声明:Cell (int row) {this(row  , row  );}调用:Cell  c1 =  new  Cell ( 5 ) ;

可以注意到,在第三段声明的构造方法中,使用了this关键字,在构造方法中可以通过this关键字来调用另外的一个重载的构造方法。this(row,row)调用了第一段声明Cell(int row, int col)构造方法。

2. 数组

2.1. 引用类型数组

2.1.1. 数组是对象

在java中,数组属于引用数据类型,数组对象存放在堆中存储,数组变量属于引用类型,存储数组对象的地址信息,指向数组对象。而数组的元素可以看成数组对象的成员变量(只不过类型全部相同)。看如下代码:

copytextpop-up
  1. int[ ] arr = new int [ 3 ]
int[ ]   arr  = new   int [ 3 ]   

内存的分配如下图– 4所示:

图- 4

说明: 在堆内存中分配了数组对象,分配三个int型空间,并将每个元素赋初始值为0,栈中存储对堆中数据的引用,即堆中int数组的首地址。

2.1.2. 引用类型数组的声明

刚刚声明的数组为基本类型数组,除了基本类型数组以外,也可以声明引用类型数组。所谓引用类型数组,即数组元素的类型不是基本类型(int,char,float。。) , 而是引用类型,看如下代码:

copytextpop-up
  1. Cell [ ] cells = new Cell [ 4 ] ;
Cell [ ]    cells  = new  Cell [ 4 ] ;

其内存分配如下图– 5所示:

图- 5

从上图示可以看出,new Cell[4]实际是分配了4个空间用于存放4个Cell类型的引用,并赋初始值为null,而并非是分配了4个Cell类型的对象。

2.1.3. 引用类型数组的初始化

前面所介绍的基本类型数组的默认值同成员变量默认的初始值(如int类型的数组初始值为0),而引用类型数组的默认初始值都是null。

如果希望每一个元素都指向具体的对象,则需要针对每一个数组元素进行“new”运算。与基本类型数组一样,也可以采用静态初始化的方式进行初始化操作。如下代码所示:

copytextpop-up
  1. Cell[ ] cells = new Cell[4];
  2. cells[0] = new Cell(0,4);
  3. cells[1] = new Cell(1,3);
  4. cells[2] = new Cell(1,4);
  5. cells[3] = new Cell(1,5);
Cell[ ]  cells = new  Cell[4];cells[0] = new Cell(0,4);cells[1] = new Cell(1,3);cells[2] = new Cell(1,4);cells[3] = new Cell(1,5);

等价于:

copytextpop-up
  1. Cell[ ] cells = new Cell[ ] {
  2.     new Cell(0,4) ,
  3.     new Cell(1,3) ,
  4.     new Cell(1,4) ,
  5.     new Cell(1,5)
  6. } ;
Cell[ ] cells = new Cell[ ] {new Cell(0,4) ,new Cell(1,3) ,new Cell(1,4) , new Cell(1,5) } ;

如上数组内存分配图如下图– 6 所示:

图- 6

2.1.4. 数组的类型是基本类型数组

前面所介绍的数组的元素或为基本类型int,或为引用类型Cell,而数组本身也是一种数据类型,当然也可以作为数组的元素。看下面的代码:

copytextpop-up
  1. int [ ][ ] arr = new int[3][ ];
  2. arr[0] = new int[2];
  3. arr[1] = new int[3];
  4. arr[2] = new int[2];
  5. arr[1][1] = 100;
int [ ][ ] arr = new int[3][ ];arr[0] = new int[2];arr[1] = new int[3];arr[2] = new int[2];arr[1][1] = 100;

分析如上代码可以看出,变量arr指向一个数组,该数组有三个元素,每个元素都是int类型数组,长度分别为2,3,2,arr[1][1]=100表示将arr数组中的第2个元素(数组)的第2个元素赋值为100, 其内存分配如图– 7所示:

图- 7

对于元素为数组的数组,如果每个数组元素的长度相同,也可以采用如下的方式声明:

copytextpop-up
  1. int row = 3, col = 4;
  2. int[][] arr = new int[row][col];
  3. for (int i = 0; i < row; i++) {
  4. for (int j = 0; j < col; j++) {
  5. arr[i][j] = i * j;
  6. }
  7. }
int row = 3, col = 4;int[][] arr = new int[row][col];for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {arr[i][j] = i * j;    }}

如上形式的数组可以用来表示类似“矩阵”这样的数据结构(3行4列),如下图-8所示,arr[i][j] 可以认为访问行号为i,列号为j的那个元素。在其他的一些语言中有专门表示这样结构的所谓二维数组;但严格的讲,Java语言中没有真正的二维数组。

图- 8

原创粉丝点击