范例:TestPersonDemo2.java
01 class Person
02 {
03 String name ;
04 int age ;
05 void talk()
06 {
07 System.out.println("我是:"+name+",今年:"+age+"岁");
08 }
09 }
10
11 public class TestPersonDemo2
12 {
13 public static void main(String[] args)
14 {
15 // 声明并实例化一Person对象p
16 Person p = new Person() ;
17 // 给p中的属性赋值
18 p.name = "张三" ;
19 // 在这里将对象p的年龄属性赋值为-25岁
20 p.age = -25 ;
21 // 调用Person类中的talk()方法
22 p.talk() ;
23 }
24 }
输出结果:
我是:张三,今年:-25岁
程序说明:
1、 1~9行声明了一个新的类Person,类中有name、age两个属性,还有一个talk()方法用于输出信息。
2、程序第16行,声明并实例化一Person的对象p。
3、 18~22行,分别为p对象中的属性赋值,并调用talk()方法
之前所列举的程序都是用对象直接访问类中的属性,这在面向对象法则中是不允许的。所以为了避免程序中这种错误的情况的发生,在一般的开发中往往要将类中的属性封装(private),对范例TestPersonDemo2.java做了相应的修改后形成下面的程序TestPersonDemo3-1.java,如下所示:
范例:TestPersonDemo3-1.java
01 class Person
02 {
03 private String name ;
04 private int age ;
05 void talk()
06 {
07 System.out.println("我是:"+name+",今年:"+age+"岁");
08 }
09 }
10
11 public class TestPersonDemo3-1
12 {
13 public static void main(String[] args)
14 {
15 // 声明并实例化一Person对象p
16 Person p = new Person() ;
17 // 给p中的属性赋值
18 p.name = "张三" ;
19 // 在这里将p对象中的年龄赋值为-25岁
20 p.age = -25 ;
21 // 调用Person类中的talk()方法
22 p.talk() ;
23 }
24 }
编译结果:
TestPersonDemo3.java:18: name has private access in Person
p.name = "张三" ;
^
TestPersonDemo3.java:20: age has private access in Person
p.age = -25 ;
^
2 errors
程序说明:
1、 1~9行声明了一个新的类Person,类中有name、age两个属性,还有一个talk()方法用于输出信息,与前面不同的是这里的属性在声明时前面都加上了private关键字。
2、程序第16行,声明并实例化一Person类的对象p。
3、 18~22行,分别为p对象中的属性赋值,并调用talk()方法。
可以发现本程序与上面的范例除了在声明属性上有些区别之外,并没有其它的区别,而就是这一个小小的关键字,却可以发现程序连编译都无法通过,而所提示的错误为:属性(name、age)为私有的,所以不能由对象直接进行访问。这样就可以保证对象无法直接去访问类中的属性,但是如果非要给对象赋值的话,而这一矛盾该如何解决呢?程序设计人员一般在类的设计时,会对属性增加一些方法,如:setXxx()、getXxx()这样的公有方法来解决这一矛盾。请看下面的范例:
范例:TestPersonDemo3-2.java
01 class Person
02 {
03 private String name ;
04 private int age ;
05 void talk()
06 {
07 System.out.println("我是:"+name+",今年:"+age+"岁");
08 }
09 public void setName(String str)
10 {
11 name = str ;
12 }
13 public void setAge(int a)
14 {
15 if(a>0)
16 age = a ;
17 }
18 public String getName()
19 {
20 return name ;
21 }
22 public int getAge()
23 {
24 return age ;
25 }
26 }
27
28 public class TestPersonDemo3-2
29 {
30 public static void main(String[] args)
31 {
32 // 声明并实例化一Person对象p
33 Person p = new Person() ;
34 // 给p中的属性赋值
35 p.setName("张三") ;
36 // 在这里将p对象中的年龄赋值为-25岁
37 p.setAge(-25) ;
38 // 调用Person类中的talk()方法
39 p.talk() ;
40 }
41 }
输出结果:
我是:张三,今年:0岁
程序说明:
1、在程序9~25行,加入了一些setXxx()、getXxx()方法,主要用来设置和取得类中的私有属性。
2、在程序35行调用了Person类中的setName()方法,并赋值为“张三”,在程序37行调用了setAge()方法,同时传进了一个-25的不合理年龄。
3、程序13~17行设置年龄的时候在程序中加了些判断语句,如果传入的数值大于0,则将值赋给age属性。
由此可以发现,用private可以将属性封装起来,当然private也可以封装方法,封装的形式请参考格式5-4。
【 格式5-4 封装类中的属性或方法】
封装属性:private 属性类型 属性名
封装方法:private 方法返回类型 方法名称(参数)
注意:
用private声明的属性或方法只能在其类的内部被调用,而不能在类的外部被调用,读者可以先暂时简单的理解为,在类的外部不能用对象去调用private声明的属性或方法。
下面这道程序修改自上面的程序(TestPersonDemo3-2.java),在这里,将talk()方法封装了起来。
范例:TestPersonDemo4.java
01 class Person
02 {
03 private String name ;
04 private int age ;
05 private void talk()
06 {
07 System.out.println("我是:"+name+",今年:"+age+"岁");
08 }
09 public void setName(String str)
10 {
11 name = str ;
12 }
13 public void setAge(int a)
14 {
15 if(a>0)
16 age = a ;
17 }
18 public String getName()
19 {
20 return name ;
21 }
22 public int getAge()
23 {
24 return age ;
25 }
26 }
27
28 public class TestPersonDemo4
29 {
30 public static void main(String[] args)
31 {
32 // 声明并实例化一Person对象p
33 Person p = new Person() ;
34 // 给p中的属性赋值
35 p.setName("张三") ;
36 // 在这里将p对象中的年龄赋值为-25岁
37 p.setAge(-25) ;
38 // 调用Person类中的talk()方法
39 p.talk() ;
40 }
41 }
编译结果:
TestPersonDemo4.java:39: talk() has private access in Person
p.talk() ;
^
1 error
程序说明:
1、在程序9~25行,加入了一些setXxx()、getXxx()方法,主要用来设置和取得类中的私有属性。
2、在程序35行调用了类Person中的setName()方法,并赋值为"张三",在程序37行调用了setAge()方法,同时传进了一个不合理的年龄-25。
3、程序13~17行设置年龄的时候在程序中加了些判断语句,如果传入的数值大于0,则将值赋给age属性。
4、在程序第5行,将talk()方法用private来声明。
可以发现private也是同样可以用来声明方法的,这样这个方法就只能在类的内部被访问了。
!小提示:
读者可能会问,到底什么时候需要封装,什么时候不用封装。在这里可以告诉读者,关于封装与否并没有一个明确的规定,不过从程序设计角度来说,一般说来设计较好的程序的类中的属性都是需要封装的。此时,要设置或取得属性值,则只能用setXxx()、getXxx()方法,这是一个明确且标准的规定。
通过上面的几个范例,读者应该可以清楚,在一个java程序中是可以通过对象去调用类中的方法的,当然类的内部也能互相调用各自的方法,比如下面的程序,在下面的程序中,修改了以前的程序代码,新增加了一个公有的say()方法,并用这个方法去调用私有的talk()方法。
范例:TestPersonDemo5.java
01 class Person
02 {
03 private String name ;
04 private int age ;
05 private void talk()
06 {
07 System.out.println("我是:"+name+",今年:"+age+"岁");
08 }
09 public void say()
10 {
11 talk();
12 }
13 public void setName(String str)
14 {
15 name = str ;
16 }
17 public void setAge(int a)
18 {
19 if(a>0)
20 age = a ;
21 }
22 public String getName()
23 {
24 return name ;
25 }
26 public int getAge()
27 {
28 return age ;
29 }
30 }
31
32 public class TestPersonDemo5
33 {
34 public static void main(String[] args)
35 {
36 // 声明并实例化一Person对象p
37 Person p = new Person() ;
38 // 给p中的属性赋值
39 p.setName("张三") ;
40 // 在这里将p对象中的年龄属性赋值为-25岁
41 p.setAge(30) ;
42 // 调用Person类中的say()方法
43 p.say() ;
44 }
45 }
输出结果:
我是:张三,今年:30岁
程序说明:
1、程序9~12行声明一公有方法say(),此方法用于调用类内部的私有方法talk()。
2、在程序第43行调用Person类中的say()方法,其实也就是调用了Person类中的talk()方法。
注意:
这个时候say()方法调用talk()方法,如果非要强调对象本身的话,也可以写成如下形式:
this.talk() ;
读者也许会觉得这样写有些多余,当然this的使用方法很多,在以后的章节中会有更加完整的介绍,读者可自行修改上面的程序试验一下,看看结果是不是与原来的相同。