对于面向对象的特点,想必大家应该都可以倒背如流:封装,继承,多态。但很多人对这些特点的理解仅仅停留在表面,认为封装就是变量的私有化,然后对外开放接口,获取和设置值,而不知道为什么要这样做。  封装,简单来说就是将变量私有化,在java里的用的就是private修饰符修饰,这样在外部产生的对象就不能直接访问这个变量。想要外部对象对变量进行访问或操作,就需要在类里面提供外部访问的接口,也就是我们熟知的get和set方法。
以上就是大部分人对于封装的理解。知道有封装这回事,知道怎么用,却不知道为什么要用,甚至觉得多此一举。因为明明person.name就是访问到变量,为什么非要person.getName()呢?
1. 任性的使用public 让我们先来看一下不使用封装的情况:
设计了3个类,人、男人、女人
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public  class  Person  {  public  String name;   public  int  age;    } public  class  Man  extends  Person  {  public  double  money;   public  Woman wife;         public  void  marry (Woman woman)  {     this .wife = woman;     woman.marry(this );   } } public  class  Woman  extends  Person  {  public  Man husband;      public  void  marry (Man man)  {     this .husband = man;   } } public  class  Test  {  public  static  void  main (String[] args)  {     Man man = new  Man();     man.name = "snail" ;     man.age = 30 ;     man.money = 10000 ;     Woman woman = new  Woman();     woman.name = "lucy" ;          man.marry(woman);     System.out.println(man.name + "的妻子"  + man.wife.name);      System.out.println(man.name + "的钱:"  + man.money);    } } 
到这里一切正常,看起来也还不错。
但是这这个时候来了一个小偷,这个小偷呢,除了偷别人的钱和老婆啥都不干。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public  class  Thief  extends  Man  {  private  double  stealMoney = 0 ;   private  List<Woman> women = new  ArrayList<Woman>();      public  void  stealMoney (Man man)  {     stealMoney += man.money;     man.money = 0 ;          System.out.println("哈哈,偷到钱了..." );   }      public  void  stealWife (Man man)  {     man.wife.husband = this ;     women.add(man.wife);          Woman woman = new  Woman();     woman.name = "凤姐" ;     man.wife = woman;     System.out.println("哈哈哈,又偷了一个妹子做老婆..." );   } } public  class  Test  {  public  static  void  main (String[] args)  {     Man man = new  Man();     man.name = "snail" ;     man.age = 30 ;     man.money = 10000 ;     Woman woman = new  Woman();     woman.name = "lucy" ;          man.marry(woman);          Thief thief = new  Thief();     thief.stealMoney(man);     thief.stealWife(man);     System.out.println(man.name + "的妻子"  + man.wife.name);      System.out.println(man.name + "的钱:"  + man.money);    } } 
现在傻眼了,钱和老婆都成别人的了,自己还莫名其妙的和凤姐结了婚…
这时,你觉得是时候改变一下了!!!
2. 封装来报到 封装觉得你有点惨,于是过来帮助你一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public  class  PackagePerson  {  private  String name;   private  int  age;    } public  class  PackageMan  extends  PackagePerson  {  private  PackageWoman wife;   private  double  money;   public  PackageMan (String name, double  money)  {     this .setName(name);     this .money = money;   }   public  void  marry (PackageWoman woman)  {     this .wife = woman;     woman.marry(this );   }   public  PackageWoman getWife ()  {     return  wife;   }   public  double  getMoney ()  {     return  money;   } } public  class  PackageWoman  extends  PackagePerson  {  private  PackageMan husband;   public  PackageWoman (String name)  {     this .setName(name);   }   public  void  marry (PackageMan man)  {     this .husband = husband;   }   public  PackageMan getHusband ()  {     return  husband;   } } public  class  TestPackage  {  public  static  void  main (String[] args)  {     PackageMan man = new  PackageMan("snail" , 10000 );     PackageWoman woman = new  PackageWoman("lucy" );          man.marry(woman);     System.out.println(man.getName() + "的妻子"  + man.getWife().getName());      System.out.println(man.getName() + "的钱:"  + man.getMoney());    } } 
上面的代码看起来除了长了点,没什么其他问题。这时候小偷已经不能偷我们的钱和老婆了,钱和老婆都被保护了起来,以至于我们自己想设置和更换都不行了,这明显不太科学…
3. 封装厉害的地方 如何解决上面的问题呢?私有化外部访问不到,自己也没法改数据,提供了set方法又会让所有人都能改,和不私有设计没什么区别,好纠结。
Wait,这里说的“所有人”真的是所有人吗?
让我们来看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public  void  setMoney (PackageMan man, double  money)  {  if (man == this ){     this .money = money;   }else {     System.out.println("喂,110吗?"  + man.getName() + " 抢钱!" );   } } public  class  TestPackage  {  public  static  void  main (String[] args)  {     PackageMan man = new  PackageMan("snail" , 10000 );     PackageMan man1 = new  PackageMan("thief" , 10000 );     man.setMoney(man, 20000 );     System.out.println(man.getName() + "的钱:"  + man.getMoney());      man.setMoney(man1, 0 );    } } 
这样就只有自己可以修改了,别人不可以。
但是你老婆不满意了,凭什么只有你自己可以改?我也想改!
这种需求还是应该满足一下的,怎么做呢?
1 2 3 4 5 6 7 public  void  setMoney (Object obj, double  money)  {  if (obj == this  || obj == this .wife){     this .money = money;   }else {     System.out.println("喂,110吗?有人抢钱!" );   } } 
4. 总结一下 以上就是对面向对象中的封装的理解,封装不仅仅只是 private + getter and setter。使用封装可以对setter进行更深层次的定制,我们可以对可以执行的setter方法的对象做规定,也可以对数据操作要求,还可以做类型转换等一系列可以想到的。
使用封装不仅仅是安全,更可以简化操作。不要觉得用了封装多了好多代码,看起来乱糟糟的。如果你写一个大系统,一开始你可能这样定义属性的
你的程序里大概有100处这样的语句:
这个时候,突然有需求要求把数据类型变了,改成:
那么重构代码是不是要把那100处数据都加个双引号呢?是不是特别麻烦?
但是如果用了封装,只需要这样:
1 2 3 public  void  setAge (int  age)  {  this .age = String.valueOf(age); } 
是不是简化了操作?
这里只是举个栗子,实际开发中也不会出现改变数据类型这么操蛋的事…
封装还有一个好处就是模块化。当你参与一个很多人实现的大型系统中,不可能知道所有的类是怎样实现的。只需要知道这个类提供了哪些方法,需要传入什么数据,能得到什么样的结果。至于怎么得到的,关我X事?
所以说,如果你写的代码还没用封装,改过来吧。不仅仅因为大家都在用,而是这确实可以给我们提供很大的便利。 封装的有以下四大好处:
良好的封装能够减少耦合 类内部的结构可以自由修改 可以对成员进行更精确的控制 隐藏信息和实现细节