} /**
* 读取狗狗亲密度 * @return 亲密度 */
public int getLove(){ return love;
} /**
* 指定狗狗亲密度 * @param love 亲密度 */
public void setLove(int love){ this.love=1ove; } /**
* 读取狗狗品种 * @return 品种 */ public String getStrain(){ return strain;
} /**
* 指定狗狗品种
* @param strain 品种 */
public void setStrain(String strain){ this.strain=strain; } /**
* 输入狗狗信息 */
public void print(){
System.out.println(“宠物的自白:\\n 我的名字叫”+this.name+”,是”+this.health+”,和主人的亲密度是”+this.love+”,我是一只”+this.strain+”。”);
} }
编写测试类,如示例10所示。
示例10 /**
* 测试类的封装 * @author 北大青鸟 */
健康值class Test{
public static void main(String[] args){ Dog dog = new Dog(); //dog.health=300; dog.setName(“欧欧”); dog.setHealth(300); System.out..println(“昵称是”+dog.getName()); System.out.println(“健康值是”+dog.getHealth()); dog.print();
} }
运行结果如图1.20所示。
去掉示例10中”d.health=300”一行的注释符后并执行,会出现什么结果呢?
运行结果如图1.21所示。
从示例10的两次运行结果图我们可以看到封装之后的两个变化:采用了private修饰符的变量不能在类外部访问,而是通过public修饰的setter方法实现;通过在setter方法中编写相应存取控制语句可以避免出现不符合实际需求的赋值。
封装(Encapsulation)是类的三大特性之一,就是将类的状态信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
封装的具体步骤:修改属性的可见性来显示对属性的访问;为每个属性创建一对赋值(setter)方法和取值(getter)方法,用于对这些属性的存取;在赋值方法中,加入对属性的存取控制语句。 封装的好处主要有:隐藏累的实现细节:让使用者只能通过程序员规定的方法来访问数据;可以方便地加入存取控制语句,限制不合理操作。
封装时会用到多个权限控制符来修饰成员变量和方法,区别如下。
Private:成员变量和方法只能在类内被访问,被同一个项目中不同包中的子类访问(父类、子类的概念将在第二章讲解)。
Public:可以被同一个项目中所有类访问,具有项目可见性,这是最大的访问权限。 问题:
电子宠物系统有如下要求
领养宠物对象时可以指定昵称、品种,以后不允许改变。
领养宠物对象时健康值和亲密度采用默认值,只有通过玩耍、吃饭、睡觉等行为改变。
分析:
实际开发中封装哪些属性、如何封装取决于业务需求。根据需求,应对示例9做如下修改。
(1)去掉所有的setter方法,保留所有的getter方法
(2)提供有name和strain两个参数的构造方法实现对昵称和品种的赋值。 (3)提供eat()、play()、sleep()等方法实现健康值和亲密度的变化。
采用类图类表示改变封装后的Dog类和Penguin类,结果如图1.22和图1.23所示,请大家把他们和图1.18 以及图1.19进行比较,看有什么不同。
改变封装后的Dog类如示例11所示。
示例11 /**
* 宠物狗狗类,使用权限修饰符private和public进行封装。 * @author 北大青鸟 */
class Dog{
private String name=”无名氏”; private int health=100; private int love=0;
private String strain=”聪明的拉布拉多犬”; /**
* 通过构造方法指定狗狗的昵称、品种 * @param name 昵称 * @param strain 品种 */
public Dog(String name,String strain){ this.name=name; this.strain=strain; } /**
* 通过吃饭增加健康值 */
public void eat(){ if(health>=100){ System.out.println(“狗狗需要多运动呀!”);
}else { health=health+3; System.out.println(“狗狗吃饭了!”); } } /**
* 通过玩游戏增加与主人亲密度,减少健康值
*/
public void play(){ if(health<60){ System.out.println(“狗狗生病了!”);
}else { System.out.println(“狗狗正在和主人玩耍。”); health =health-10; love =love+5; } } /**
* 读取狗狗昵称 * @return 昵称 */
public String getName(){ return name; } /**
* 读取狗狗健康值 * @return 健康值 */
public int getHealth(){ return health; } /**
* 读取狗狗亲密度 * @return 亲密度 */
public int getLove(){ return love; } /**
* 读取狗狗品种 * @return 品种 */
public String getStrain(){ return strain; } /**
* 输出狗狗的信息 */
public void print(){ System.out.println(“宠物的自白:\\n我的名字叫”+this.name+”,健康值是”+this.health+”,和主人的亲密度是”+this.love+”,我是一只 ”+this.strain+”。”);
}
}
编写测试类,如示例12所示。
示例12: /**
* 测试类的封装 * @author 北大青鸟 */
class Test1{
public static void main(String[] args){ Dog dog =new Dog(“欧欧”,”酷酷的雪纳瑞”); dog.play(); System.out.println(“健康值是”+dog.getHealth()); dog.eat(); dog.print(); } }
运行结果如图1.24所示。
图1.24 示例12运行结果 接下来介绍this关键字
在示例9中的一系列setter方法中我们都用到了this这个关键字,this是什么含义呢?他还有什么其他的用法?
this关键字是对一个对象的默认引用。在每个实例方法内部,都有一个this引用变量,指向调用这个方法的对象。
在示例10中,我们创建了一个Dog对象dog,dog对象的昵称是欧欧,健康值是300,但是在shiite9中Dog类代码的编写是早于创建Dog对象的,当时并不知道以后创建的对象的名字呢。this关键字就是用来表示以后调用当前方法的那个对象的引用,当调用dog.setName(“欧欧”)、dog.setHealth(300)时,this就代表dog,而当创建另外Dog对象xxx,然后调用xxx.setName(“yyy”)时,this就表示xxx.this和xxx指向同一个对象。 this使用举例
使用this调用成员变量,解决成员变量和局部变量同名的冲突。 public void setName(String name){
this.name=name;//成员变量和局部变量同名,必须使用this }
public void setName(String xm){
name=xm;//成员变量和局部变量不同名,this可以省略 }