我们已经知道类使封装对象的属性和行为的载体,而在 Java 语言中,对象的属性是以成员变量的形式存在的,对象的方法则是以成员方法的形式存在的。

成员变量

在 Java 中,对象的属性也称为成员变量。我们可以先定义一个图书类,来帮助我们更好的了解成员变量,其中在图书类中,成员变量对应于类对象的属性,在 Book 类中设置一个成员变量 name,对应于图书名称。

public class Book {

    private String name;

    public String getName() {
        int id = 0;
        setName("Java");
        return id + this.name;
    }
    
    private void setName(String name) {
        this.name = name;
    }
    
    public Book getBook() {
        return this;            //返回 Book 类的引用
    }
}

在 Java 中使用 class 关键字来定义类,Book 是类的名称。同时在 Book 类中定义了一个成员变量,成员变量的类型可以设置为 Java 中合法的数据类型,其实成员变量就是普通的变量,可以为它设置初始值,也可以不设置初始值。如果不设置初始值,则会有默认值。

成员方法

在 Java 语言中使用成员方法对应于类对象的行为。以刚才的 Book 类为例,它包含 getName() 和 setName() 方法,这两个成员方法分别为获取图书名称和设置图书名称的方法。定义成员方法的语法格式为:

权限修饰符 返回值类型 方法名(参数类型 参数名) {
    ......            //方法体
    return 返回值;

}

一个成员方法可以有参数,这个参数可以是对象,也可以是基本数据类型的变量,同时成员方法有返回值和不返回任何值的选择,如果方法需要返回值,可以在方法体中使用 return 关键字,使用这个关键字后,方法的执行将被终止。若 Java 中的成员方法无返回值,可以使用 void 关键字。

成员方法的返回值可以是计算结果,也可以是其他想要的树枝和对象,返回值类型要与方法返回的值类型一样。在成员方法中可以调用其他成员方法和成员变量,在例子中,getName() 方法中就调用了 setName() 方法将图书名称赋予一个值。同时在成员变量中可以定义一个变量,这个变量为局部变量。

如果一个方法中含有与成员变量同名的局部变量,则方法中对这个变量的访问以局部变量进行。例如,变量 id 在 getName() 方法中值为0,而不是成员变量中 id 的值。类成员变量和成员方法也可以统称为类成员。

权限修饰符

Java 中的权限修饰符主要包括 private、protected 和 public,这些修饰符控制着对类和类的成员变量以及成员方法的访问。如果一个类的成员变量或成员方法被修饰为 private,则该成员变量只能在本类中被使用,在子类中是不可见的,并且对其他包的类是不可见的,如果将类的成员变量和成员方法中的访问权限设置为 public,那么除了可以在本类中使用这些数据之外,还可以在子类和其他包的类中使用。如果一个类的访问权限被设置为 private,这个类将隐藏其内的所有数据,以免用户直接访问它。如果需要使类中的数据被子类或其他包中的类使用,可以将这个类设置为 public 访问权限 。如果一个类使用 protected 修饰符,那么只有本包内的该类的子类或其他类可以访问此类中的成员变量和方法。

由此可以看出,public 和 protected 修饰的子类可以由子类访问,如果子类和父类不在同一个包中,那么只有修饰符为 public 的类可以被子类进行访问。如果父类不允许通过继承产生的子类访问它的成员变量,那么必须使用 private 声明父类的这个成员变量。

Java 语言中的修饰符权限

访问包位置

类修饰符

private

protected

public

本类

可见

可见

可见

同包其他类或子类

不可见

可见

可见

其他包的类或子类

不可见

不可见

可见

当声明类时不使用 public、protected 和 private 修饰符设置类的权限,则这个类预设为包存取范围,即只有一个包中的类可以调用这个类的成员变量或成员方法。

局部变量

如果在成员方法内定义一个变量,那么这个变量被称为局部变量。如示例中所示,在 Book 类中,getName() 方法中的 id 变量即为局部变量。实际上方法中的形参也可以作为一个局部变量,如在 setName() 方法中的 String name 这个形参就可以被看作是局部变量。局部变量是在方法被执行时创建,在方法执行结束时被销毁。局部变量在使用时必须进行赋值操作或被初始化,负责会出现编译错误。

局部变量的有效范围

可以将局部变量的有效范围称为变量的作用域,局部变量的有效范围从该变量的声明开始到该变量的结束为止。

//局部变量的作用范围
//变量 id 的作用域为第1行至第6行,变量 i 的作用域为第3行至第5行
public void doString(String name) {
    int id  = 0;
    for (int i = 0; i < 10; i++) {
        System.out.println(name + String.valueOf(i));
    }
}

//在相互不嵌套的作用域中可以同时声明两个名称和类型相同的局部变量
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 < 10; i++) {
        System.out.println(i);
    }
}

//在嵌套区域中不可以定义相同名称和类型的局部变量
//在嵌套区域中不能定义两个 id
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 < 10; i++) {
        int id = 7; 
        System.out.println(i);
    }

this 关键字

private void setName(String name) {
    this.name = name;
}

如上代码展示,成员变量与 setName() 方法中的形参名称相同,都为 name,那么我们如何在类中区分使用的是哪一个变量呢?在 Java 语言中规定使用 this 关键字来代表本类对象的引用,this 关键字被隐式地用于引用对象的成员变量和方法,如在上述代码中,this.name 指的就是 Book 类中的 name 成员变量,而 this.name = name 中的第二个 name 则指的是形参 name。实质上 setName() 方法实现的功能就是将形参 name 的值赋予成员变量 name。Java 语言中最常规的调用方式是使用“对象.成员变量”或“对象.成员方法”进行调用。既然 this 关键字和对象都可以调用成员变量和成员方法,那么 this 关键字与对象之间具有怎样的关系呢?事实上,this 引用的就是本类的一个对象。在局部变量或方法参数覆盖了成员变量时,如上述代码情况,就要添加 this 关键字明确引用的是类成员变量还是局部变量或方法参数。如果省略 this 关键字直接写成 name  = name,那只是把参数 name 赋值给参数本身而已,成员变量 name 的值没有改变,因为参数 name 在方法的作用域中覆盖了成员变量 name。

其实,this 除了可以调用成员变量或成员方法外,还可以作为方法的返回值。如在 Book 类中,getBook() 方法,返回值为 Book 类,所以方法体中使用 return this 这种形式将 Book 类的对象返回。