5.2 类
在5.1.2节中已经讲解过类是封装对象的属性和行为的载体,而在Java语言中对象的属性以成员变量的形式存在,对象的方法以成员方法的形式存在。本节将讲解类在Java语言中是如何定义的。
5.2.1成员变量
在Java中,对象的属性也称为成员变量,成员变量可以是任意类型,整个类中均是成员变量作用范围。下面通过一个实例来演示成员变量在类中所处的位置。
【例1】为书添加书名属性
创建一个Book类,在类中设置一个name属性,并为该属性编写Getter/Setter方法。
public class Book{ //类
private String name; //String类型的成员变量
public String getName(){ //name的Getter方法
return name;
}
public void setName(String name){ //name的Setter方法this.name = name; //将参数值赋予类中的成员变量
}
}
在上面这个实例中可以看到,在Java语言中需要使用class关键字来定义类,Book是类的名称。同时在Book类中定义了一个成员变量,成员变量的类型为String类型。其实成员变量就是普通的变量,可以为它设置初始值,也可以不设置初始值。如果不设置初始值,则会有默认值。读者应该注意到成员变量name前面有一个private关键字,它用来定义一个私有成员。
5.2.2成员方法
在Java语言中,使用成员方法对应于类对象的行为。以Book类为例,它包含getName()和setName()两个方法,这两个成员方法分别为获取图书名称和设置图书名称的方法。
定义成员方法的语法格式如下:
权限修饰符 返回值类型 方法名(参数类型 参数名){
…… //方法体
return 返回值;
}
一个成员方法可以有参数,这个参数可以是对象,也可以是基本数据类型的变量,同时成员方法有返回值和不返回任何值的选择,如果方法需要返回值,可以在方法体中使用return关键字,使用这个关键字后,方法的执行将被终止。
注意:
要使Java代码中的成员方法无返回值,可以使用void关键字表示。
成员方法的返回值可以是计算结果,也可以是其他想要的数值和对象,返回值类型要与方法返回的值类型一致。
在成员方法中可以调用其他成员方法和类成员变量,如在例1的getName()方法中就调用了setName()方法将图书名称赋予一个值。同时,在成员方法中可以定义一个变量,这个变量为局部变量。
说明:
如果一个方法中含有与成员变量同名的局部变量,则方法中对这个变量的访问以局部变量进行。类的成员变量和成员方法也可以统称为类成员。
5.2.3权限修饰符
Java中的权限修饰符主要包括private、public和protected,这些修饰符控制着对类和类的成员变量以及成员方法的访问。如果一个类的成员变量或成员方法被修饰为private,则该成员变量只能在本类中被使用,在子类中是不可见的,并且对其他包的类也是不可见的。如果将类的成员变量和成员方法的访问权限设置为public,那么除了可以在本类使用这些数据,还可以在子类和其他包的类中使用。如果一个类的访问权限被设置为private,这个类将隐藏其内的所有数据,以免用户直接访问它。如果需要使类中的数据被子类或其他包中的类使用,可以将这个类设置为public访问权限。如果一个类使用protected修饰符,那么只有本包内的该类的子类或其他类可以访问此类中的成员变量和成员方法。
这么看来,public和protected修饰的类可以由子类访问,如果子类和父类不在同一包中,那么只有修饰符为public的类可以被子类进行访问。如果父类不允许通过继承产生的子类访问它的成员变量,那么必须使用private声明父类的这个成员变量。表1中描述了private、protected和public修饰符的修饰权限。
| 访问包位置 | 类修饰符 | ||
| private | protected | public | |
| 本类 | 可见 | 可见 | 可见 |
| 同包其他类或子类 | 不可见 | 可见 | 可见 |
| 其他包的类或子类 | 不可见 | 不可见 | 可见 |
注意:
当声明类时不使用public、protected和private修饰符设置类的权限,则这个类预设为包存取范围,即只有一个包中的类可以访问这个类的成员变量或成员方法。
例如,在项目中的com.mr包下创建AnyClass类。该类使用默认的访问权限。
package com.mr
;class AnyClass{
public void doString(){
…… //方法体
}
}
在上述代码中,由于类的修饰符为默认修饰符,即只有一个包内的其他类和子类可以对该类进行访问,而AnyClass类中的doStrng()方法却又被设置为public访问权限,即使这样,doString()方法的访问权限依然与AnyClass类的访问权限相同。
5.2.4局部变量
在5.2.2节中已经讲述过成员方法,如果在成员方法内定义一个变量,那么这个变量被称为局部变量。
实际上,方法中的形参也可作为一个局部变量。例如,在例1的Book类中定义setName(String name)方法,String name这个形参就被看作是局部变量。
局部变量是在方法被执行时创建,在方法执行结束时被销毁。局部变量在使用时必须进行赋值操作或被初始化,否则会出现编译错误。
【例2】交换两个整数的值
在ChangeDemo类中创建静态的exchange()方法,该方法可以将数组参数arr的前两个元素值互换,通过在方法中定义一个保存临时数据的局部变量tmp,利用tmp交换两个元素的值。
public class ChangeDemo{public static int[] exchange(int[] arr){int tmp = arr[0]; //创建局部变量tmp,保存数组第一个元素的值arr[0] = arr[1]; //第二个元素值赋给第一个元素arr[1] = tmp; //第二个元素值改为tmpreturn arr;}public static void main(String[] args){int arr[] = {17,29};System.out.println("第一个值="+arr[0]+",第二个值="+arr[1]);arr = exchange(arr);System.out.println("第一个值="+arr[0]+",第二个值="+arr[1]);}
}
运行结果如下:
第一个值=17,第二个值=29
第一个值=29,第二个值=17
5.2.5局部变量的有效范围
可以将局部变量的有效范围称为变量的作用域,局部变量的有效范围从该变量的声明开始到该变量的结束为止。列如:
public void doString(String name){
int id = 0;
for(int i = 0;i < 10;i++){
System.out.printin(nase + String.valueOf(i));
}
}
在相互不嵌套的作用域中可以同时声明两个名称和类型相同的局部变量。列如:
public void doString(String name){
int id = 0;
for(int i = 0;i < 10;i++){
System.out.printin(nase + String.valueOf(i));
}
for(int i = 0;i < 3;i++){
Systea.out.println(i);
}
}
但是在相互嵌套的区域中不可以这样声明,如果将局部变量id在方法体的for循环中再次定义,编译器将会报错。列如:
public void doString(String name){
int id = 0;
for(int i = 0;i < 10;i++){
System.out.println(name + String,valueOf(i));
}
for(int i = 0;i < 3;i++){
System.out.println(i);
int id = 7;
}
}
注意:
在作用范围外使用局部变量是一个常见的错误,因为在作用范围外没有声明局部变量的代码。
5.2.6 this关键字
this关键字用于表示本类当前的对象,当前对象不是某个new出来的实体对象,而是当前正在编辑的类。this关键字只能在本类中使用。
例如,例1中图书类的setName()方法代码如下:
public void setName(String name){ //定义一个setName()方法
this.name = name; //将参数值赋予类中的成员变量
在上述代码中可以看到,成员变量与setName()方法中的形式参数的名称相同,都为name,那么该如何在类中区分使用的是哪一个变量呢?在Java语言中,规定使用this关键字来代表本类对象的引用,this关键字被隐式地用于引用对象的成员变量和方法,如在上述代码中,this.name指的就是Book类中的name成员变量,而this.name = name语句中的第二个name则指的是形参name。实质上,setName()方法实现的功能就是将形参name的值赋予成员变量name。
在这里读者明白了this可以调用成员变量和成员方法,但Java语言中最常规的调用方式是使用“对象.成员变量”或“对象.成员方法”进行调用。
既然this关键字和对象都可以调用成员变量和成员方法,那么 this关键字与对象之间具有怎样的关系呢?事实上,this引用的就是本类的一个对象。在局部变量或方法参数覆盖了成员变量时,如上面代码的情况,就要添加this关键字明确引用的是类成员还是局部变量或方法参数。
如果省略this关键字直接写成name = name,那只是把参数name赋值给参数变量本身而已,成员变量name的值没有改变,因为参数name在方法的作用域中覆盖了成员变量name。
其实,this除了可以调用成员变量或成员方法,还可以作为方法的返回值。例如,返回图书类本类的对象,可以写成下面这种形式:
public Book getBook(){
return this; //返回Book类的本类对象}
在getBook()方法中,返回值为Book类,所以方法体中使用return this这种形式返回Book类对象。
