第三课时 构造方法的总结
知识回顾:类的组成:1) 属性:根据对象的特征定义
2) 方法:用于实例化对象,实现对象的行为
I. 普通方法:
II. 构造方法:
纲要:1.构造方法
2.方法重载
3.this关键字
4.值传递
5.引用传递
一.构造方法:普通方法和构造方法的区别
1.格式:
1.1普通方法:
访问限定符 返回值类型 方法名([ 数据类型 参数名1,数据类型 参数名2,... ]){
//方法体
}
例: //为学生类定义一个设置名字的方法
public void setName(String n){
name=n;
}
1.2构造方法:
访问限定符 类名([ 数据类型 参数名1,数据类型 参数名2,... ]){
//方法体
}
例: //为学生类定义一个不带参数的构造函数
public Student(){
}
2.格式的异同:
2.1格式的相同点:I . 都有访问限定符,可以是公有(public)可以是私有(private)也可以
是受保护的(protected)。
II . 参数可以带也可以不带,也可以带多个参数也可以不带参数,多个参
数时必须用逗号隔开,所带参数必须有相应的数据类型和参数名。
III . 都带有各自的方法体。
2.2格式的不同点:I . 普通方式必须有返回值类型,如果没有返回值,则写void,
构造方法没有返回值类型。
II. 普通方法的方法名可以根据行为的名字进行命名,
构造方法的方法名必须与类名一致。
3.用途不同
3.1普通方法:根据对象的行为定义,用于实现对象的行为。
3.2构造方法:I . 实例化对象 (见如下例题)
II. 初始化对象 (详情见方法重载部分)
III. 返回开辟的内存空间的首地址 (详情见引用传递部分,已用红色标注)
4.例题:
public class student { private String name; //学生的名字属性 private int score=0; //学生的学分属性,初始值为0 /** * 设置学生名字的方法 * @param n 学生的名字参数 */ public void setName(String n){ name=n; } /** * 获取学生名字的方法 * @return 学生的名字 */ public String getName(){ return name; } //程序主函数入口 public static void main(String [] args){ //使用默认的构造函数实例化一个student类对象 student stu=new student(); //调用普通方法为对象设置名字 stu.setName("小明"); //调用普通方法将获取的名字赋值给一个变量 String stuName=stu.getName(); //输出该名字 System.out.println(stuName); } }
二.方法重载:包括构造方法的重载和普通方法的重载
1.什么情况下使用方法重载?
在同一个类中,不同的数据类型使用相同的方法时可以使用重载。
1.1构造方法重载:实例化对象的时候,有些对象需要参数,有些对象不要参数。
(通俗来讲就是对象一“出生”的时候,就具备有不同的东西)
例如:对于一个汽车类,制造一个汽车的时候,
可能有些汽车自带了导航系统(带导航参数),
而有些汽车却没有(不带导航参数),
那么在生产的过程中两者就需要用到不同的制造工具。
1.2普通方法重载:相同的方法可以用不同的“道具”来实现。
例如:求一个三角形的面积,
可以通过 底*高/2来实现(那么就需要底和高两个参数),
也可通过三边的长求解(那么就需要三个边长参数),
还可以通过两边的长和夹角来求解(那么就需要两个边长参数和
一个夹角参数)。
2.实现方法重载的条件?
(1)方法名相同
(2)参数不同(参数的类型,参数的个数只要一个不同即可)
(注: 方法体、访问限定符和返回值类型可以不同)
3.重载后的方法如何使用?
重载后的方法与没重载的方法使用格式一样,都是 对象名.方法名([参数]);
对象会根据参数的类型和参数的个数搜寻相匹配的方法,进行调用。
4.例题:
public class student { private String name; //学生的名字属性 private int score=0; //学生的学分属性,初始值为0 /** * 定义一个不带参数的构造函数 */ public student(){ } /** *重载一个带参数的构造函数 * @param name 学生的名字参数 */ public student(String n){ name=n; } /** * 设置学生名字的方法 * @param n 学生的名字参数 */ public void setName(String n){ name=n; } /** * 获取学生名字的方法 * @return 学生的名字 */ public String getName(){ return name; } /** * 学生学习的方法,不带参数 */ public void study(){ score++; System.out.println(name+"学习了,学分加1!"); } public void study(int hour){ score+=hour; System.out.println(name+"学习了"+hour+"小时,学分加"+hour); } //程序主函数入口 public static void main(String [] args){ //用无参的构造函数实例化一个student类对象 student stu1=new student(); //使用带参数的构造函数实例化一个student类对象,并初始化学生的姓名属性 student stu2=new student("小红"); //stu1对象调用普通方法为对象设置名字 stu1.setName("小明"); //stu1对象调用不带参数的study方法 stu1.study(); //stu2对象调用带参数的study方法 stu2.study(5); } }
三.关键字this:表示当前对象
1.用于解决参数与属性同名时引起的问题
例:
private String name; //学生的名字属性 /** * 设置学生名字的方法 * @param n 学生的名字参数 */ public void setName(String name){ name=name; }
我们的目的是:将setName的参数值name(左边的name)赋给当前对象的name属性
(右边的name)。
但是:当参数名和属性名同,由于java的就近原则,和name属性相比,右边的
name和参数名name较近,因此,Java会自动将其识别为参数name而非属
性name。
所以:上述方方法体只是执行了,将参数name的值传给参数name,而无法实
现我们的最终目的。
因此:我们可以引入this关键字。如下代码:
private String name; //学生的名字属性 /** * 设置学生名字的方法 * @param n 学生的名字参数 */ public void setName(String name){ this.name=name; }
引入this关键字的作用:使用了this关键字后this.name就表示该对象的name属性,
这样就可以实现给名字属性的赋值。
2.调用当前类的构造函数
例:
/** * 定义一个不带参数的构造函数 */ public student(){ //调用带参数的构造函数 this("小黑"); } /** * 重载一个带参数的构造函数 * @param name 学生的名字参数 */ public student(String n){ name=n; }
在构造函数中,通过this指针可以调用非本身的构造函数(构造函数不能调用自身,否则会无限的递归下去)
格式:this([参数1,参数2,...])
3.例题:1)没用this关键字前
public class student { private String name; //学生的名字属性 /** *定义一个带参数的构造函数 * @param name 学生的名字参数 */ public student(String name){ name=name; } /** * 设置学生名字的方法 * @param n 学生的名字参数 */ public void setName(String n){ name=n; } /** * 获取学生名字的方法 * @return 学生的名字 */ public String getName(){ return name; } //程序主函数入口 public static void main(String [] args){ //使用带参数的构造函数实例化一个student类对象 student stu=new student("小红"); //获取stu对象的名字 String b=stu.getName(); //输出名字 System.out.println("stu对象的名字为:"+b); } }
结果为:
stu对象的名字为:null
2)使用this关键字后
public class student { private String name; //学生的名字属性 /** *定义一个带参数的构造函数 * @param name 学生的名字参数 */ public student(String name){ this.name=name; } /** * 设置学生名字的方法 * @param n 学生的名字参数 */ public void setName(String n){ name=n; } /** * 获取学生名字的方法 * @return 学生的名字 */ public String getName(){ return name; } //程序主函数入口 public static void main(String [] args){ //使用带参数的构造函数实例化一个student类对象 student stu=new student("小红"); //获取stu对象的名字 String b=stu.getName(); //输出名字 System.out.println("stu对象的名字为:"+b); } }
结果为:
stu对象的名字为:小红
四.值传递
1.适用于什么数据类型?
适用于基本数据类型(8种):字节型(byte)、字符型(char)、短整型(short)、整型(int)
长整形(long)、浮点型(float)、双精度(double)、
布尔型(booolean)
2.传递内容和如何传递?
传递内容:数值。
如何传递如下:已知学生类的学习方法
public void study(int hour){ //学分的初始值为0,学习了几小时就加多少学分 score+=hour; //输出 System.out.println(name+"学习了"+hour+"小时,学分加"+hour); }
(1)定义一个整型变量 int i=5;
(2)对象stu调用学习方法:stu.study(i);
第二步:执行分数加hour的操作后,分数变为5
第三步:分数改变后,为分数属性临时创建的score空间中的内容会被java的gc销毁,同时会释放该内存空间。内存中的内容改变如下:
五.引用传递
1.适用于什么数据类型?
适用于复杂数据类型(引用数据类型、对象数据类型、类类型、自定义类型)
class、interface、abstract class和数组都属于该类型
2.传递内容和如何传递?
传递内容:地址。
如何传递如下:已知student类的构造函数如下
/** * 定义一个不带参数的构造函数 */ public student(){ } /** * 重载一个带参数的构造寒素 * @param name 学生的名字参数 */ public student(String n){ name=n; }
(1)实例化一个student对象类 :student stu1=new student(“张三”);
在栈内为stu1开辟一段内存空间,同时为该类的属性和方法在堆中开辟一段内存空间,假设属性和方法对应空间的首地址为123,则将123传给栈中的stu1存储起来,即stu1中的内容为在堆中开辟的内存空间的首地址。
(2)用同样的方法实例化另一个对象:student stu2=new student();
(3)引用传递,将stu1中的内容123(首地址)赋值给stu2:stu2=stu1,赋值完后stu2在堆中开辟的内存内容会被gc销毁,同时释放掉该内存空间。
此时,如果对stu2执行setName操作,由于stu1和stu2中的内容都是123,所以不仅stu2中的内容发生改变,stu1的内容也会随之改变。
3.例题:代码如下:
public class student { private String name; //学生的名字属性 /** * 定义一个带参数的构造寒素 * @param name 学生的名字参数 */ public student(String name){ this.name=name; } /** * 设置学生名字的方法 * @param n 学生的名字参数 */ public void setName(String name){ this.name=name; } /** * 获取学生名字的方法 * @return 学生的名字 */ public String getName(){ return name; } //程序主函数入口 public static void main(String [] args){ //使用带参数的构造函数实例化两个student类对象 student stu1=new student("张三"); student stu2=new student("李四"); System.out.println("改变stu2对象的名字前:"); //获取stu1对象的名字 String a=stu1.getName(); //输出名字 System.out.println("stu1对象的名字为:"+a); //获取stu2对象的名字 String b=stu2.getName(); //输出名字 System.out.println("stu2对象的名字为:"+b); //引用传递 stu2=stu1; //改变stu2对象的名字 stu2.setName("王五"); System.out.println("改变stu2对象的名字后:"); //获取stu1对象的名字 a=stu1.getName(); //输出名字 System.out.println("stu1对象的名字为:"+a); //获取stu2对象的名字 b=stu2.getName(); //输出名字 System.out.println("stu2对象的名字为:"+b); } }
结果为:
改变stu2对象的名字前:
stu1对象的名字为:张三
stu2对象的名字为:李四
改变stu2对象的名字后:
stu1对象的名字为:王五
stu2对象的名字为:王五