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 ! ",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 ! ",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 }
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 //创建2个Person类的对象 10 Person p1 = new Person(); 11 Person p2 = new Person(); 12 p1.setAge(15); 13 p2.setAge(18); 14 15 //p1对象调用自己的方法compare传递p2对象。 16 boolean b = p1.compare(p2); 17 System.out.println(b); 18 } 19 } 20 21 22 /** 23 以上代码执行结果如下: 24 false 25 26 */
六.构造方法介绍(Constructor)
经过上面的学习,我们对封装已经有了基本的了解,接下来我们来看一个薪的问题。依然以Person为例,由于Person中的属性被private了,外界无法直接访问属性,必须对外提供相应的set和get方法。当创建Person对象的时候,Person对象一撞见就要确定其姓名和年龄,那该怎么做呢?在Java编程中,我们称值为构造方法,在其它语言中也有人称之为初始化赋值。
1>.构造方法介绍
在开发中经常需要创造对象的同时,明确对象的属性值。比如员工入职公司就要明确它的姓名,年龄,薪资(当然薪资在你入职之后依然是可以修改的,比如现实生活中涨薪)等属性信息。那么,创建对象就要明确属性值,那怎么解决呢?也就是在创建对象的时候就要做的事情,当使用new关键字创建对象时,怎么给对象的属性初始化值赋值呢?这就是我接下来要给大家分享的另外一个小技巧,即构造方法。
那么什么是构造方法呢?从字面上理解即为构建创造时用的方法,即就是对象创建时要执行的方法。既然是对象创建时要执行的方法,那么只要在new对象时,知道其构造的方法是什么,就可以在执行这个方法的时候给对象进行赋值。
2>.构造方法的作用与定义格式
a>.构造方法的作用
就是在new的同时对成员变量赋值,给对象的属性初始化赋值。比如:new Person,就是对Person类的属性name,age进行赋值。换句话说,就是给对象初始化。
b>.构造方法的定义格式
1 权限 方法名(形参列表){
2
3 }
注意:方法的名字必须和类的名字完全一致(尤其是要注意字母的大小写!);构造方法不允许写返回值类型,void也不能写哟(如果写了void的话只能是看做当前类中的普通反方)!下面是我写的两个案例:
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 String name; 9 private int age; 10 11 //定义出Person的构造方法 12 public Person() { 13 System.out.println("我是一个空参构造!"); 14 } 15 16 public String getName() { 17 return name; 18 } 19 public void setName(String name) { 20 this.name = name; 21 } 22 public int getAge() { 23 return age; 24 } 25 public void setAge(int age) { 26 this.age = age; 27 } 28 29 }
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 p = new Person(); 10 /*注意,构造方法是在new的时候,自动触发执行,而且只运行一次,仅此而已。 11 * 当然了你定义了多个Person对象的话,构造方法还是会被调用的,只是对象不同而已! 12 * */ 13 14 15 } 16 } 17 18 19 20 21 /* 22 以上代码执行结果如下: 23 我是一个空参构造! 24 25 */
3>.构造方法的运行特点
a>.构造方法是一种特殊的方法,它的方法名与类名相同;
b>.不用定义返回值类型,不用return关键字;
c>.其返回值可以理解为新创建对象的引用,不用显式定义;
d>.构造方法是每个类中必须内容,如果没有写构造方法,系统提供一个默认构造方法(我们用javac编译工具进行编译的时候,这个编译器会自动检查类中是否有构造方法,如果有,就使用当前的构造方法,如果没有,编译器就会自动添加一个(“public Person(){}”)空参构造方法);
e>.多个构造方法是以重载的形式存在的;
f>.使用new Person();实际上就是调用空参构造方法;
4>.构造方法的调用赋值
此处我们以 Person p = new Person();为例,来分析一下在一个对象初始化过程中构造方法起到的作用。
a>.从磁盘中加载Person.class字节码到Java虚拟机的方法区中;
b>.在JVM中的栈内存中定义变量p;
c>.对象在堆内存中开辟空间;
d>.对象对成员变量进行默认初始化(0/false/0.0/null);
e>.对象对成员变量进行显示初始化;
f>.对象自己调用构造方法(对成员变量赋值);
g>.成员变量初始化完毕,将对象的地址值返回给栈中的变量p;
5>.构造方法的重载
构造方法至少有一个,如果你没有写构造方法,系统会默认给你添加一个空参构造方法。只要你写了构造方法,系统就不会再给你添加空参构造方法啦,而是以你的写的构造方法执行。当然,我建议大家在写有参构造方法的同时,别忘记手动添加一个空参构造方法。以下是我给的两个案例:
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 String name; 9 private int age; 10 11 //定义出Person类有参数的构造方法 12 public Person(String name,int age){ 13 this.name = name; 14 this.age = age; 15 } 16 //定义出Person类无参数的构造方法,简称空参构造方法 17 public Person(){ 18 19 } 20 public String getName() { 21 return name; 22 } 23 public void setName(String name) { 24 this.name = name; 25 } 26 public int getAge() { 27 return age; 28 } 29 public void setAge(int age) { 30 this.age = age; 31 } 32 33 }
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 8 public class PersonDemo{ 9 public static void main(String[] args) { 10 //1.调用空参构造方法,创建对象 11 Person p1 = new Person(); 12 p1.setName("尹正杰"); 13 p1.setAge(18); 14 System.out.format("调用空参构造方法,姓名:%s,年龄%d。 ", p1.getName(),p1.getAge()); 15 16 //2.调用2个参数的构造方法,创建对象 17 Person p2 = new Person("灵魂摆渡",2018); 18 System.out.format("调用有参构造方法,姓名:%s,年龄%d。 ", p2.getName(),p2.getAge()); 19 } 20 }
构造方法一般权限都为public,但有的时候也可以设置为private,一旦将构造方法设置为private就意味着在类外无法调用该类型的构造方法,但是这个类依然可以通过get或是set方法供大家使用,这种类我们称之为工具类。案例如下:
1 /** 2 对一维数组操作的工具类 3 @author 尹正杰 4 @version v1.0 5 */ 6 public class ArrayTool{ 7 //将构造方法私有化 8 private ArrayTool(){} 9 10 /** 11 获取最大值 12 @param arr 需要找最大值的数组 13 @return 这个数组中的最大值 14 */ 15 public static int getMax(int[] arr){ 16 int max = arr[0]; 17 for(int i = 1;i<arr.length;i++){ 18 if(arr[i] > max){ 19 max = arr[i]; 20 } 21 } 22 return max; 23 } 24 /** 25 获取最小值 26 @param arr 需要找最小值的数组 27 @return 这个数组中的最小值 28 */ 29 public static int getMin(int[] arr){ 30 int min = arr[0]; 31 for(int i = 1;i<arr.length;i++){ 32 if(arr[i] < min){ 33 min = arr[i]; 34 } 35 } 36 return min; 37 } 38 39 /** 40 获取某个元素第一次出现的索引 41 @param arr 需要查找的数组 42 @param value 需要查找索引的数值 43 @return 某个值第一次出现的索引,-1表示没有 44 45 */ 46 public static int getIndex(int[] arr,int value){ 47 for(int i = 0;i<arr.length;i++){ 48 if(arr[i] == value){ 49 return i; 50 } 51 } 52 return -1; 53 } 54 55 /** 56 求和 57 @param arr 需要求和数组 58 @return 数组中所有元素的和 59 */ 60 public static int getSum(int[] arr){ 61 int sum = 0; 62 for(int i = 0;i<arr.length;i++){ 63 sum += arr[i]; 64 } 65 return sum; 66 } 67 /** 68 求平均值 69 @param arr 需要求平均值数组 70 @return 数组的平均值 71 */ 72 public static double getAvg(int[] arr){ 73 double sum = 0.0; 74 for(int i = 0;i<arr.length;i++){ 75 sum += arr[i]; 76 } 77 return sum / arr.length; 78 } 79 80 }
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 ArrayToolDemo{ 8 public static void main(String[] args){ 9 //工具类的测试 10 int[] arr = {1,2,3,4,5}; 11 int max = ArrayTool.getMax(arr); 12 System.out.println(max); 13 } 14 }
6>.同类中构造方法和一般方法的区别
到目前为止,我们学习过了两种方法,即构造方法和一般方法。那么他们之间有什么异同呢?构造方法在对象创建时就执行了,而且就执行一次。一般方法在创建对象后,需要使用时才被对象调用,并且可以被多次调用。
那么问题来了,有了构造方法之后就可以对对象的属性进行初始化,那么还需要对应的set和get方法吗?答案是肯定的,需要相应的set和get方法,因为对象在创建之后需要修改和访问相应的属性值,在这时只能通过set或者get方法来操作。就比如你到一家公司工作了3年多了,难道你的薪资就一直固定不长了吗?
7>.this在构造方法之间的调用
为了减少代码量,其实多个构造方法是可以相互调用的哟,不过用this关键字调用其它方法的时候要注意的是:调用其它构造方法的话必须是构造方法的第一条语句(当然,注释除外!)。
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 String name; 9 private int age; 10 11 //定义出Person类有参数的构造方法 12 public Person(String name,int age){ 13 this.name = name; 14 this.age = age; 15 } 16 //定义出Person类无参数的构造方法,简称空参构造方法 17 public Person(){ 18 //这里用this关键字调用了有参构造方法,传输“yinzhengjie”和"20"传递给了变量“name”和“age”。 19 this("尹正杰",20); //构造方法中使用this调用其它构造方法的话必须是构造方法的第一条语句 20 } 21 public String getName() { 22 return name; 23 } 24 public void setName(String name) { 25 this.name = name; 26 } 27 public int getAge() { 28 return age; 29 } 30 public void setAge(int age) { 31 this.age = age; 32 } 33 34 }
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 8 public class PersonDemo{ 9 public static void main(String[] args) { 10 //1.调用空参构造方法,创建对象 11 Person p1 = new Person(); 12 System.out.format("调用空参构造方法,姓名:%s,年龄%d。 ", p1.getName(),p1.getAge()); 13 14 //2.调用2个参数的构造方法,创建对象 15 Person p2 = new Person("灵魂摆渡",2018); 16 System.out.format("调用有参构造方法,姓名:%s,年龄%d。 ", p2.getName(),p2.getAge()); 17 } 18 } 19 20 21 22 /*以上代码执行结果如下: 23 * 调用空参构造方法,姓名:尹正杰,年龄20。 24 * 调用有参构造方法,姓名:灵魂摆渡,年龄2018。 25 */
为了帮助理解,也为了若干年后我忘记了这个执行流程,我简要的画一下他们的执行流程,如下图:
七. 代码块执行顺序介绍
你以为只有构造方法可以帮你赋值吗?不,你错了,除了构造方法,还有其它2个代码块均可以对成员被变量进行赋值!接下来我们就先介绍2个执行代码是优先级比构造代码块还要高的代码块。
1>.局部代码块
在方法内部,用于限定变量的生命周期,及时释放内存.
2>.构造代码块
定义在成员位置,用于抽取不同构造方法中相同的部分.
3>.静态代码块
static修饰的构造代码块,用于对类进行初始化.
那么问题来了,静态代码块,构造代码块,构造方法的执行顺序是怎样的呢?接下来我们可以通过代码测试来看其执行的效果。
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 class Demo{ 8 { //构造代码块次之 9 System.out.println("block-2"); 10 } 11 12 Demo(){ //构造方法最后被执行 13 System.out.println("Constructor"); 14 } 15 16 { 17 System.out.println("block-1"); 18 } 19 20 static{ //静态代码块优先级最高,会被执行。加载一次后第二次加载该类时不会被调用 21 System.out.println("static block-1"); 22 } 23 24 static{ 25 System.out.println("static block-2"); 26 } 27 } 28 29 public class BlockDemo{ 30 public static void main(String[] args){ 31 Demo d1 = new Demo(); 32 Demo d2 = new Demo(); 33 } 34 } 35 36 37 38 /* 39 以上代码执行结果如下: 40 static block-1 41 static block-2 42 block-2 43 block-1 44 Constructor 45 block-2 46 block-1 47 Constructor 48 */