Java基础-面向对象第一特性之封装(Encapsulation)
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.理解什么是面向过程和面向对象
面向过程与面向对象都是我们编程中,编写程序的一种思维方式。
1>.面向过程的程序设计方式,是遇到一件事时,思考“我该怎么做”,然后一步步实现的过程。典型的编程语言代表就是C语言。
例如:公司打扫卫生(彩玻璃,扫地,拖地,倒垃圾等),按照面向过程的程序设计方式会思考“打扫卫生我该怎么做,然后一件件的完成”,最后把公司卫生打扫的干干净净。
2>.面向对象的程序谁教方式,是遇到一件事时,思考“我该让谁来做”,然后那个“谁”就是对象,他要怎么做这件事就是他字节的事,反正最后一群对象合力能把事做好就行了。典型的编程语言代表就是Java语言。
例如:公司打扫卫生(彩玻璃,扫地,拖地,倒垃圾等),按照面向对象的程序设计方式会思考“我该让谁来做,如让张三擦玻璃,让李四扫地,让王五拖地,让赵六倒垃圾等等”,这里的“张三,李四,王五,赵六”就是对象,他们要打扫卫生,怎么打扫是他们自己的事,反正最后一群对象合力把公司卫生打扫干净了。
二.面向对象举例
我们就举一个简单的例子,在实际生活中,如果你想买一台组装电脑,通过面向过程和面向对象有着两种不同的方案。
1>先使用面向过程说明买电脑这件事
假如我们需要买组装电脑,这时首先会在网上查询具体每一个硬件的参数和报价。然后会去电脑城进行多家询价,接着询价结束后回家根据具体的结果分析出字节比较满意的哪家报价,接着会去电脑成进行多家询价,接着询价结束回家根据具体的结果分析出自己比较满意的哪家报价,接着会到这家店进行组装,组装时还需要进行现场监督,组装完成安装相应的系统,最后再把组装好的电脑抱回家。
2>.使用面向对象说明买电脑这件事
假如我们需要买组装组装电脑,这时应该找一个懂电脑硬件的人,让他帮我们查看参数和报价,并进行询价和杀价,以及现场组装监督。而我们自己并不需要亲力亲为具体怎么做,只要告诉这个人我们想要的具体需求即可。
分析上述整个过程,发现瞬间变得十分轻松,只要找到懂电脑硬件的这个人,我们的问题都可以解决。并且在这个过程中我们不用那么辛苦。
三.面向对象思维方式的好处
世间万物皆是对象,通过生活中的真实场景使用面向对象分析完之后,我们开始分析面向过程和面向对象的差异做出如下总结:
1>.面向对象思维方式是一种更符合人们思考习惯的思想;
2>.面向过程思维方式中更多的体现是执行者(自己做事情),面向对象中更多的体现是指挥者(指挥对象做事情),换句话说,就是将程序员从执行者转换成了指挥者;
3>.面向对象思维方式将复杂的问题简单化;
· 完成需求时,先要去找具体所需的功能的对象来用,如果该对象不存在,那么创建一个具有所需功能的对象,这样简化开发并提高复用。
四.成员变量和局部变量的区别
1>.定义的位置上的区别
成员变量:定义在类中,方法外。
局部变量:方法内,方法体内。
2>.作用域不同
成员变量:作用范围是整个类。
局部变量:方法内,语句内。
3>.默认值不同
成员变量:有自己的默认值。
局部变量:没有默认值,不赋值不能使用(也就是说你得手动赋初值)。
4>.内存位置不同
成员变量:跟随对象进入堆内存存储。
局域变量:跟随自己的方法,进入栈内存。
5>.生命周期不同
成员变量:跟随对象,在堆中存储,内存等待JVM清理(换句话说,成员变量随着对象的出现而出现在堆中,随着对象的消失而从堆中消失)。
局部变量:随着方法的运行而出现在栈中,随着方法的弹栈而消失。
五.封装的概述
封装,它是面向对象思想的特征之一。面向对象共有三个特征:封装,继承和多态。本篇博客主要是介绍封装,接下来我们具体学习一下封装。
1>.封装表现
a>.方法就是一个最基本封装体;
b>.类其实也是一个封装体;
2>.从以上两点得出结论,封装的好处:
a>.提高了代码的复用性;
b>.隐藏了实现细节,还要对外提供可以访问的方式。便于调用者的使用。这是核心之一,也可以理解为就是封装的概念;
c>.提高了安全性;
3>.如果实现封装
a>.使用private关键字修饰成员变量;
b>.对外提供公有的setter和getter方法;
4>.封装在生活中的举例
比如我们IT人员必须要用的工具,即机箱就是一种封装的设计理念。一台电脑,它是由CPU,主板,显卡,内存,硬盘,电源等部件组成,其实我们将这些部件组装在一起就可以使用电脑了,但是发现这些部件都散落在外面,很容易造成不安全因素,于是,使用机箱把这些部件都组装在里面,并在机箱壳留下一些插口用于接通电源,显示器,鼠标等。
总结:机箱其实就是隐藏了板卡设备的细节,对于提供插口以及开关等间接访问内部细节的方式。
5>.private关键字
在介绍private关键字之前,我们先看一下下面2个代码
a>.Person.java 类文件
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/ 4 EMAIL:y1053419035@qq.com 5 */ 6 7 public class Person{ 8 //定义人的姓名,成员变量 9 String Name; 10 //人的年龄,成员变量 11 int age; 12 13 public void speak(){ 14 System.out.printf("My name is %s ,and i am %d years old !",Name,age); 15 } 16 17 }
b>.PersonDemo.java 文件
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/ 4 EMAIL:y1053419035@qq.com 5 */ 6 7 public class PersonDemo{ 8 public static void main(String[] args){ 9 //创建Person类的对象 10 Person p = new Person(); 11 //对成员变量赋值 12 p.age = 200; 13 p.Name = "尹正杰"; 14 //调用类中方法 15 p.speak(); 16 } 17 }
我们从上面的PersonDemo.java文件中可以看出它是调用者,在调用过程中,对Person的age属性赋值时小手一哆嗦赋值成了200,本来我想赋值为20来着,现在可好,直接输入了200,最终打印结果我今年200岁啦!虽然这个200这个数字不会导致程序出问题,但是的确是违反生活中的真实情况!
因此,为了提高安全问题,我们应该让外面的类(PersonDemo)不允许直接调用我的成员变量,而是通过间接的方式访问。这就得用到Java中一个关键字,即private(私有的)它有以下几个特点:第一,它是一个权限修饰符;第二,用于修饰成员(成员变量和成员方法),切记不可以用来修饰局部变量;第三,被私有化的成员只能在本类中可以直接访问。
将成员变量设置为私有,这样就防止在类外进行访问,对外提供相应的公有的setXxx或者getXxx方法。好处就是提高了数据访问的安全性。并且可以增加复杂的逻辑控制。接下来我们对上面的代码用private进行改造,具体代码如下:
c>.Person.java文件
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/ 4 EMAIL:y1053419035@qq.com 5 */ 6 7 public class Person{ 8 //定义人的姓名,成员变量 9 String Name; 10 //人的年龄,成员变量,变量age被(private)私有,只能通过定义提供方法,才能让外面的类使用 11 private int age; 12 13 //定义方法,对age变量进行赋值,方法名字,必须set开头 14 public void setAge(int a){ 15 //对变量参数a进行范围限制,实际生成环境中这个判断是不必做的,因为数据从前端传过来之前就已经做了合法性判断 ! 16 if(a<0 || a >120){ 17 //如果a超过范围,手动将age赋值为20 18 age = 20; 19 }else{ 20 //如果a没有超过范围,直接对age进行赋值操作。 21 age = a; 22 } 23 } 24 public void speak(){ 25 System.out.printf("My name is %s ,and i am %d years old !",Name,age); 26 } 27 }
d>.PersonDemo.java 文件
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/ 4 EMAIL:y1053419035@qq.com 5 */ 6 7 public class PersonDemo{ 8 public static void main(String[] args){ 9 //创建Person类的对象 10 Person p = new Person(); 11 //对成员变量赋值,此处我故意把数值写的偏大,看我程序是否会进行合法性判断! 12 p.setAge(30000); 13 p.Name = "尹正杰"; 14 //调用类中方法 15 p.speak(); 16 } 17 } 18 19 20 21 22 /** 23 以上代码执行结果如下: 24 My name is 尹正杰 ,and i am 20 years old ! 25 */
6>.get和set方法
我们知道一个成员变量被私有化,类外是无法直接对其进行访问的,因为定义的成员变量已经被隐藏了,隐藏后,还需要提供访问方式,只需要对外提供访问的方法,让其它程序访问这些方法。同时在方法中可以对数据进行验证。一般对成员属性的访问动作:赋值(设置 set),取值(获取 get),因此对私有的变量访问的方式可以提供对应的setXxx或者getXxx的方法。我们还是以上面的Person类为例子,具体代码只想效果如下:
a>.Person.java 文件
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/ 4 EMAIL:y1053419035@qq.com 5 */ 6 7 public class Person{ 8 //定义人的姓名,成员变量 9 private String Name; 10 //人的年龄,成员变量,变量age被(private)私有,只能通过定义提供方法,才能让外面的类使用 11 private int age; 12 13 14 public void setName(String n){ 15 Name = n; 16 } 17 18 //定义方法,对age变量进行赋值,方法名字规定以set开头 19 public void setAge(int a){ 20 //对变量参数a进行范围限制,实际生成环境中这个判断是不必做的,因为数据从前端传过来之前就已经做了合法性判断 ! 21 if(a<0 || a >120){ 22 //如果a超过范围,手动将age赋值为20 23 age = 20; 24 }else{ 25 //如果a没有超过范围,直接对age进行赋值操作。 26 age = a; 27 } 28 } 29 30 public String getName(){ 31 return Name; 32 } 33 34 //定义方法,对变量age获取值使用,方法名字规定以get开头。 35 public int getAge(){ 36 return age; 37 } 38 39 public void speak(){ 40 System.out.printf("My name is %s ,and i am %d years old !\n",Name,age); 41 } 42 }
b>.PersonDemo.java 文件
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/ 4 EMAIL:y1053419035@qq.com 5 */ 6 7 public class Person{ 8 //定义人的姓名,成员变量 9 private String Name; 10 //人的年龄,成员变量,变量age被(private)私有,只能通过定义提供方法,才能让外面的类使用 11 private int age; 12 13 14 public void setName(String n){ 15 Name = n; 16 } 17 18 //定义方法,对age变量进行赋值,方法名字规定以set开头 19 public void setAge(int a){ 20 //对变量参数a进行范围限制,实际生成环境中这个判断是不必做的,因为数据从前端传过来之前就已经做了合法性判断 ! 21 if(a<0 || a >120){ 22 //如果a超过范围,手动将age赋值为20 23 age = 20; 24 }else{ 25 //如果a没有超过范围,直接对age进行赋值操作。 26 age = a; 27 } 28 } 29 30 public String getName(){ 31 return Name; 32 } 33 34 //定义方法,对变量age获取值使用,方法名字规定以get开头。 35 public int getAge(){ 36 return age; 37 } 38 39 public void speak(){ 40 System.out.printf("My name is %s ,and i am %d years old !\n",Name,age); 41 } 42 }
总结:类中不需要对外提供内部的都私有化,包括属性和方法,以后描述事物,属性都私有化,并提供setXxx或者getXxx方法对其进行访问。注意:私有仅仅是封装的体现形式而已。
7>.this关键字
作用:this代表当前正在调用方法的对象
使用场景: a>.setXxx方法中对成员变量赋值:区分成员变量和局部变量;
b>.构造方法互相调用(注意:构造方法中使用this或者super调用其它构造方法的话必须是构造方法的第一条语句);
c>.方法中调用本类其它方法;
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/ 4 EMAIL:y1053419035@qq.com 5 */ 6 7 public class Person{ 8 private int age; 9 10 public void setAge(int age){ 11 if(age<0 || age >120){ 12 this.age = 20; 13 }else{ 14 this.age = age; 15 } 16 } 17 18 public int getAge(){ 19 return age; 20 } 21 22 //定义方法:比较是否是同龄人,是就返回true,不是就返回false 23 public boolean compare(Person p){ 24 return this.age == p.age; 25 } 26 27 }