本节书摘来自异步社区《Android游戏开发详解》一书中的第3章,第3.2节getter和setter,作者 【美】Jonathan S. Harbour

3.2 getter和setter
Android游戏开发详解
构造方法允许你在创建对象的时候初始化对象的实例变量,但是,它对于随后访问或修改这些值就帮不上什么忙了。此外,由于使用了private修饰符来隐藏变量,我们没有办法来直接完成这两项任务。实际上,如下所示的代码将会导致错误。

// somewhere inside the World class...
Coder c3 = new Coder(“Mark”, 30);
String c3Name = c3.name; // cannot reference private variable from another class
c3.age = 25; // cannot modify private variable from another class

怎样才能绕开这些限制呢?我们可以将Coder类的实例变量标记为public的,但是,由于第2章所介绍的原因,我们不想这么做。相反,可以在Coder类中创建访问器(accessor)方法。我们将讨论两种类型的访问器方法。

1.  getter方法返回了所请求的隐藏变量的值的一个副本(但是,保留该隐藏变量不动)。通过这么做,我们可以使得隐藏变量避免未经授权的修改,同时还允许访问该变量的值。

2.  setter方法允许其他的类修改一个隐藏变量的值,只要这些类遵守我们在该setter方法中描述的规则。

我们来看看这些访问器方法的应用。向Coder类添加如下所示的getter和setter方法:getAge()、 setAge()、getName()和setName()(参见程序清单3.6的第26行到第28行)。

程序清单3.6 向Coder.java添加getter和setter方法

01 public class Coder {
02 
03     private String name;
04     private int age;
05 
06     public Coder(String name, int age) {
07         this.name = name;
08         this.age = age;
09     }
10
11    public void writeCode() {
12        System.out.println(name + " is coding!");
13    }
14
15    public void describe() {
16        System.out.println("I am a coder");
17        System.out.println("My name is " + name);
18        System.out.println("I am " + age + " years old");
19    }
20
21    public String getName() {
22        return name;
23    }
24    
25    public int getAge() {
26        return age;
27    }
28    
29    public void setName(String newName) {
30        if (newName != null) {
31            name = newName;
32        } else {
33            System.out.println("Invalid name provided!");
34        }
35    }
36    
37    public void setAge(int newAge) {
38        if (newAge > 0) {
39            age = newAge;
40        } else {
41            System.out.println("Invalid age provided");
42        }
43    }
44 }

我们的两个getter方法返回了该方法的调用者的name和age变量。这意味着,能够访问(或引用)Coder对象的任何类,都可以调用其getter方法,并且看到Coder的实例变量的值。这里,值是关键字。我们并没有允许访问实例变量最初的版本,而是允许访问存储在其中的值。

两个setter方法允许其他的类修改Coder对象的实例变量,但是,我们可以提供一组规则,以确保这些实例变量不会被非法或无效地修改。在程序清单3.6中,我们的setters拒绝了非正值的age值和null的name值。

让我们在World类中调用getters和setters以测试它们,如程序清单3.7的第8行和第9行所示。

程序清单3.7 在World.java中调用getters和setters

01 public class World {
02    public static void main(String[] args) {
03      
04        Coder c = new Coder("Bill", 59);
05        c.describe();
06        System.out.println(""); // empty line for readability
07  
08        String cName = c.getName();
09        int cAge = c.getAge();
10
11        System.out.println(cName + ", " + cAge);
12        System.out.println(""); // empty line for readability
13        c.setName("Steve");
14        c.setAge(-5); // This will be rejected by our setter method
15
16        c.describe(); 
17    }
18
19 }

输出如下所示的结果。

I am a coder
My name is Bill
I am 59 years old
Bill, 59
I am a coder
My name is Steve
Invalid age provided

在前面的例子中,我们能够创建一种方法,来保持Coder对象的实例变量私有,同时允许外界通过公有的访问器方法,来获取(get)和修改(set)这些隐藏的变量。这允许我们保持安全地获取和使用私有变量,同时允许我们访问和修改需要的值。注意,我们的setter方法可以拒绝不合法的参数,因此,我们能够防止World类将Coder对象的年龄修改为−5。