类的封装性

现在就来看一看面向对象第一大特性—— 封装性。那什么是封装性呢?读者可以先看看下面的程序,看看会产生什么问题:

范例: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的使用方法很多,在以后的章节中会有更加完整的介绍,读者可自行修改上面的程序试验一下,看看结果是不是与原来的相同。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值