第三节 类和对象2
纲要:1.构造方法
2.方法重载
3.this关键字
4.值传递
5.引用传递
一.构造方法
1.类是由属性和方法组成,
方法包括:普通方法
构造方法
抽象方法
2.构造方法的格式:
public 类名(数据类型 参数名,......){
//方法体
}
普通方法的格式:
public 返回值类型 方法名(数据类型 参数名,......){
//方法体
}
3.构造方法与普通方法的区别:
(1)返回值类型不同。
构造方法返回的是一个地址,因此不需要返回值类型。
普通方法必须要返回值类型,没有返回值时,也需要写void。
(2)方法名不同。
构造方法的方法名必须与类名相同。
普通方法的方法名一般不与类名相同。
(3)用途不同。
构造方法用于实例化对象,也可以给对象属性设置初始值。
普通方法用于实现对象的行为、作用、用途等,可以给对象属性赋值,但不是初始值。
(注:什么是初始值?即对象在生成时就带有的数值。
例如:我们刚出生时就有体重,那个体重就是我们体重的初始值,我们可以通过
各种方法让我们体重增加,比如:进食。)
4.进一步说明构造方法的用途:
用途:I . 实例化对象,
II . 给对象的属性设置初始值。
说明:(1)如果类中没有写构造方法,
java会给该类自动添加一个默认的构造方法。
该构造方法不带任何参数,方法体中也没有任何内容。
因此,在该情况下构造方法只能实例化对象而无法给属性设置初始值。
(2)如果类中写了构造方法,
默认的构造方法会被覆盖掉,就无法调用默认的构造方法 。
如果在类中写了带参数的构造方法,
那么构造方法在实例化对象的同时也可以给属性设置初始值。
(3)每实例化一次,就会在内存中开辟一段内存空间,生成一个对象。
因此如下语句是两个对象。
Student stu;
stu=new Student();
stu=new Student();
(4)用构造函数实例化对象是,由于构造函数返回的是内存地址,
因此在对象名中 存储的是地址,图解如下:
5.代码示例:
/**
* 定义一个person类
* @author zhouxiaoxiao
*
*/
public class person {
private String name; //姓名属性
private char sex; //性别属性
/**
* 设置姓名的方法
* @param n 姓名参数
*/
public void setName(String n){
name=n;
}
/**
* 获取姓名的方法
* @return 返回姓名
*/
public String getName(){
return name;
}
/**
* 设置性别的方法
* @param s 性别参数
*/
public void setSex(char s){
sex=s;
}
/**
* 获取性别的方法
* @return 返回性别
*/
public char getSex(){
return sex;
}
}
/**
* 定义一个student类
* @author zhouxiaoxiao
*
*/
public class student {
private String name; //姓名属性
private int score; //学分属性
/**
* 带姓名参数的构造函数
* @param n 学生姓名参数
*/
public student(String n){
name=n;
}
/**
* 设置姓名的方法
* @param n 姓名参数
*/
public void setName(String n){
name=n;
}
/**
* 获取姓名的方法
* @return 返回姓名
*/
public String getName(){
return name;
}
/**
* 设置学分的方法
* @param s 学分参数
*/
public void setScore(int s){
score=s;
}
/**
* 获取学分的方法
* @return 返回学分
*/
public int getSex(){
return score;
}
}
/**
* 构造方法实例化对象
* @author zhouxiaoxiao
*
*/
public class construct {
/**
* 程序主函数入口
*/
public static void main(String[] args) {
//person类中没有定义构造方法,使用默认的构造方法实例化一个person类对象
person p=new person();
//输出认证对象名p中存储的是一个地址
System.out.println("person类的对象名p存储的值是:"+p);
//student类中定义了一个带姓名参数的构造函数,默认函数被覆盖了,因此下列语句不成立
//student s3=new student();
//使用带参数的构造函数实例化一个student类对象,并初始化姓名属性
student s1=new student("小名");
System.out.println("学生类对象s1的姓名为:"+s1.getName());
//也可以用一个对象实例化另一个对象。
student s2=s1;
System.out.println("学生类对象s2的姓名为:"+s2.getName());
}
}
二.方法重载:包括普通方法重载和构造方法重载
1.为什么要用到方法重载?
在同一个类中,不同的参数设置使用相同的方法时要用到方法重载。
I. 普通方法重载举例:
我们在记一个东西或知识点时,
可能我们需要一支笔和一张纸,
能只要一台电脑,
也可能什么都不需要,用脑就可以记下来。
在这里我们就需要不同类型或个数的参数,
但是却是同一个记东西的方法,
这时我们就可以用到普通方法重载。
II. 构造方法重载举例:
我们在买杯子的时候会发现,
有些杯子不带手柄,有些带手柄,有些既带了手柄又带了盖子,
这些杯子在生产出来的时候就有不同的特征,
因此他们在生产的时候肯定用的是不同的方法,
也就是说会用到不同的构造方法来实例化,
这就会用到构造方法的重载。
2.实现方法重载的条件:
I. 方法名必须要完全相同。
II. 方法所带的参数类型、个数、顺序必须至少一个不同。
III. 访问限定符、返回值类型、方法体可以相同也可以不同。
3.如何调用重载后的方法
对象会根据参数的类型、个数和顺序,选择相匹配的方法进行调用。
调用格式与没重载的相同。
4.代码示例:
/**
* 定义一个person类
* @author zhouxiaoxiao
*
*/
public class person {
private String name; //姓名属性
private char sex; //性别属性
/**
* 定义一个不带参数的构造函数
*/
public person(){
}
/**
* 重载一个带姓名参数的构造函数
* @param n 姓名参数
*/
public person(String n){
name=n;
}
/**
* 设置姓名的方法
* @param n 姓名参数
*/
public void setName(String n){
name=n;
}
/**
* 获取姓名的方法
* @return 返回姓名
*/
public String getName(){
return name;
}
/**
* 设置性别的方法
* @param s 性别参数
*/
public void setSex(char s){
sex=s;
}
/**
* 获取性别的方法
* @return 返回性别
*/
public char getSex(){
return sex;
}
/**
* 定义一个思考的方法
*/
public void think(){
System.out.println(name+"正在思考中!");
}
/**
* 重载一个带时间参数的思考方法
* @param hour 思考的时间
*/
public void think(int hour){
System.out.println(name+"思考了"+hour+"小时!");
}
}
/**
* 方法重载
* @author zhouxiaoxiao
*
*/
public class reload {
/**
* 程序主函数入口
*/
public static void main(String[] args) {
//用无参的构造函数实例化一个person类对象
person p1=new person();
//调用没有重载的设置名字的方法
p1.setName("Min");
//用带一个姓名参数的构造方法实例化一个对象
person p2=new person("Max");
//待用不带参数的思考方法
p1.think();
p2.think();
//调用带int型参数的思考方法
int h=3;
p2.think(h);
}
}
三.this关键字
引入this关键字的目的:
1.解决由方法参数与属性同名引起的问题。
/**
* 定义一个person类
* @author zhouxiaoxiao
*
*/
public class person {
private String name; //姓名属性
/**
* 设置姓名的方法
* @param n 姓名参数
*/
public void setName(String name){
name=name;
}
/**
* 获取姓名的方法
* @return 返回姓名
*/
public String getName(){
return name;
}
/**
* 程序主函数入口
*/
public static void main(String[] args){
person p=new person();
p.setName("小命");
System.out.println("这个人的姓名为:"+p.getName());
}
}
如上代码,
当方法中的姓名参数与姓名属性相同时,
在方法体中,给姓名属性赋值时,
虽然java会在等号左边的name添加默认的关键字this,
但是由于java的就近原则优先于添加默认关键字this这一原则,
与name属性相比,方法体中的name与方法参数中的name比较近,
因此根据就近原则,等号左边的name其实也是name参数,
方法体中的语句就类似于name参数=name参数的赋值,
而并没有给姓名属性赋上值。
输出结果为:
这个人的姓名为:null
为了解决上面的问题,下面我们引入关键字。
/**
* 定义一个person类
* @author zhouxiaoxiao
*
*/
public class person {
private String name; //姓名属性
/**
* 设置姓名的方法
* @param n 姓名参数
*/
public void setName(String name){
this.name=name; //使用this关键字
}
/**
* 获取姓名的方法
* @return 返回姓名
*/
public String getName(){
return name;
}
/**
* 程序主函数入口
*/
public static void main(String[] args){
person p=new person();
p.setName("小命");
System.out.println("这个人的姓名为:"+p.getName());
}
}
由于this表示的是当前对象,
所以等号左边的name参数,明显表示当前对象的name属性,
name属性即可赋值成功。
输出结果为:
这个人的姓名为:小命
2.调用当前类的构造函数,如下代码:
/**
* 定义一个带姓名参数的构造函数
* @param name 姓名参数
*/
public person(String name){
this.name=name;
}
/**
* 在无参的构造函数中调用带参数的构造函数
*/
public person(){
this("小明");
}
在构造函数中,通过this关键字可以调用同类中的非本身的构造函数。
(注:如果调用本身就会无限循环下去。)
调用格式:this(参数1,......);
四.值传递:
1.传递的内容:值。
2.使用范围:八种基本的数据类型。
Boolean(布尔型)、byte(字节型)、short(短整型)、int(整型)、
long(长整型)、Char(字符型)、float(单精度浮点型)、double(双精度浮点型)
3.传递过程:
已知在student类中有一个学习的方法
/**
* 学习方法
* @param hour 参数
*/
public void study(int hour){
score=hour++;
System.out.println(name+"学习了,学分加"+hour);
}
在主函数中定义了一个整型常量int hour=3,
并实例化了一个stu对象来调用study方法,
在此过程中的内存改变如下:
在该过程中,hour只是把数值3传给了方法中的形参,传的是数值。
在方法体中改变了数值并不会对hour产生任何影响。
五.引用传递:
1.传递内容:地址。
2.使用范围:适用于java的引用类型(对象类型)
包括:类、抽象类、接口、数组等。
3.传递过程:
已知一个student类
public class student {
private String name; //姓名属性
/**
* 不带参数的构造寒素
*/
public student(){
}
/**
* 重载一个带姓名参数的构造函数
* @param n 学生姓名参数
*/
public student(String n){
name=n;
}
/**
* 设置姓名的方法
* @param n 姓名参数
*/
public void setName(String n){
name=n;
}
/**
* 获取姓名的方法
* @return 返回姓名
*/
public String getName(){
return name;
}
/**
* 程序主函数入口
*/
public static void main(String[] args) {
student s1=new student();
student s2=new student();
student s3=new student("小白");
s2.setName("小黑");
//没赋值前的姓名
System.out.println("没赋值之前");
System.out.println("s1的姓名是:"+s1.getName());
System.out.println("s2的姓名是:"+s2.getName());
System.out.println("s3的姓名是:"+s3.getName());
s2=s1;
s1=s3;
s3=s2;
//赋值后的姓名
System.out.println("赋值后");
System.out.println("s1的姓名是:"+s1.getName());
System.out.println("s2的姓名是:"+s2.getName());
System.out.println("s3的姓名是:"+s3.getName());
}
}
在主函数中分别执行如下语句,内存变化如下图:
最后输出结果为: