时间:2023-03-12 11:25:26 | 栏目:JAVA代码 | 点击:次
我们上篇讲了java中类的创建,那么让我们来实战演练一下:创建一个学生类,里面有学生的基本信息,包括姓名、性别、年龄、学号,你可能会写出这样的代码:
class Student { String name; String gender; int age; long studentID; } public class TestDemo2 { public static void main(String[] args) { Student stu1 = new Student(); stu1.name = "张三"; // 给stu1对象的各个成员变量赋值 stu1.gender = "男"; stu1.age = 19; stu1.studentID = 231245431; // 打印输出 System.out.println("姓名:" + stu1.name + " 性别:" + stu1.gender + " 年龄:" + stu1.age + " 学号:" + stu1.studentID); } }
?但你在写的时候,是不是感觉给对象的成员变量一个一个的赋值太繁琐,能不能一下子就把值赋好呢?还真能,用Java中的构造方法就能做到这一点。
那么快来看看什么是构造方法吧!
?构造方法是类的一种特殊方法,用来初始化类的一个新的对象,在创建对象(new 运算符)之后自动调用,Java中的每个类都有一个默认的构造方法,并且可以有一个以上的构造方法。
Java 构造方法有以下特点:
?值得注意的是,如果为构造方法定义了返回值类型或使用 void 声明构造方法没有返回值,编译时不会出错,但 Java 会把这个所谓的构造方法当成普通方法来处理
?下面就是一个构造方法的使用例子
class Student { String name; //学生类的属性 int age; public void eat() { System.out.println(name + "在吃饭"); // 学生类的行为(方法) } public Student() { System.out.println("这是自定义的一个不带参数的构造方法"); } } public class TestDemo3 { public static void main(String[] args) { Student student1 = new Student(); } }
看到输出结果,你是不是感到:咦?不对啊,我的main方法里明明就只是实例化了一个对象啊?!我没输出啊,为啥还会输出构造方法中的内容啊?
Student student1 = new Student();
?原因就是:当类的对象被创建时,该构造方法将被自动调用。
?其实我们在用new关键字实例化对象时 , 程序一定干了这两件事(但可能不只有这两步)
?看到这,你可能又有问题了,我们之前实例化对象的时候明明没定义构造方法呀!怎么能说实例化对象时程序一定调用构造方法呢?
?是这样的,当一个类中没有提供任何构造方法,系统默认提供一个无参数的构造方法,就像这样:
Student() {}
? 但如果类中显式地定义了一个或多个构造方法,则系统不再提供默认构造方法。
在一个类中,与类名相同的方法就是构造方法。每个类可以具有多个构造方法,但要求它们各自包含不同的方法参数,比如这样:
Student() { System.out.println("这是自定义的一个没有参数的构造方法"); } Student(String name) { this.name = name; System.out.println("这是自定义的带有一个参数的构造方法"); }
那么,就让我们来看一下,调用构造方法是怎样解决上面那个麻烦的问题的,嘻嘻?
class Student { String name; String gender; int age; long studentID; // 该构造方法可由IDEA自动生成 public Student(String name, String gender, int age, long studentID) { this.name = name; this.gender = gender; this.age = age; this.studentID = studentID; } } public class TestDemo2 { public static void main(String[] args) { Student stu1 = new Student("张三", "男", 19, 231245431); System.out.println("姓名:" + stu1.name + " 性别:" + stu1.gender + " 年龄:" + stu1.age + " 学号:" + stu1.studentID); } }
?怎么样,是不是一下子就把值赋好,哈哈?,并且类中的构造方法的定义还不用自己写,在IDEA有相应的快捷键可以自动生成,就像这样:
在IDEA里点击鼠标右键,弹出窗口-->在窗口中选择Generate-->点进去后选择Constructo-->按住ctrl键的同时点击鼠标,把那几个参数全选上,点击OK?
嘻嘻,是不是IDEA帮你自动生成了?,方便吧
不过,构造方法中的this.name是什么意思啊,以前不都是 "对象名.成员变量" 吗,来接下来,我们慢慢说这个this到底是什么东东?
首先,咱先来看一段代码?
class Date { int year; int month; int day; // 通过构造函数传参来赋值 public Date(int year, int month, int day) { year = year; month = month; day = day; } public void printDate() { System.out.println(year + "/" + month + "/" + day); } } public class TestDemo2 { public static void main(String[] args) { Date date1 = new Date(2022, 4, 2); date1.printDate(); } }
这段代码有什么问题吗?细心的同学可能以经发现了 :在Date类中,传入构造方法的参数名称和Date的成员变量名字相同?,那么在Date类中的构造方法中就会出现一个问题:
public Date(int year, int month, int day) { // 那函数体中到底是谁给谁赋值?成员变量给成员变量?参数给参数?参数给成员变量? // 成员变量给参数?估计自己都搞不清楚了 year = year; // 当传入的参数相同是怎么办! month = month; day = day; }
大家觉得在上面的main方法中会输出什么?是2022/4/2吗??
让我们一起来看看吧?
?输出竟然是0/0/0,好像我们根本没给year,month,day赋值似的?
其实当构造方法的参数与类所定义的属性同名时,对于方法中的year = year,虚拟机不清楚在这里year到底是传过来的参数还是对象的成员变量,那么为了让虚拟机知道我们是把参数2022赋值给当前对象的成员变量year,我们就需要借助java中this这个关键字:
class Date { int year; int month; int day; // 添加了this关键字的构造函数 public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } public void printDate() { System.out.println(year + "/" + month + "/" + day); } } public class TestDemo2 { public static void main(String[] args) { Date date1 = new Date(2022, 4, 2); date1.printDate(); } }
?那为什么用this.name = name 赋值就好了呢?
?按照官方正规的解释,this关键字的意义被解释为“指向当前对象的引用”,比如在上述代码中当前所实例化的对象是date1,那么this其实就指向date1,是date1的一个引用(也可以理解为是date1的一个别名)那么this.xxx其实就代表了date1.xxx?
?所以在执行”this.name=name;”这条语句的时候,虚拟机就会把参数year的值”2022”赋值给对象date1的year成员变量。也就是说在这条赋值语句中,”=”左边的”this.year”表示对象date1的year成员变量,而”=”右边的year表示传给我们构造方法的参数。
?讲到这里,有的小伙伴可能会问:”this.year”为什么不能被解释为”当前对象date1自己的year参数”呢??
?因为”参数”这个概念是就某个方法而言的,它相当于某个方法的”局部变量”,只是这个”局部变量”比起在方法中定义的真正的局部变量来讲有点特殊,?它能够接收从主调方法中传递过来的值。因此,当我们说到”参数”这个概念的时候,都是相对于一个”方法”而不是一个”对象”而言的,所以也就不会有”某个对象的参数”这一说法。因此,”this.year”只能被虚拟机认定为当前对象date1自己的year成员变量,绝不会被当作参数。
不知道大家理解?了吗
?可能现在你还有点模糊,但没关系,我们现在只是刚接触到this这个关键字,先能模仿着用就行,以后可以慢慢理解?
?刚才我们用this.成员变量名访问了我们当前对象的成员变量,那么我们能不能用this.成员方法名去访问我们的方法呢?当然可以呀this.xxx此时的作用不就相当于对象名.xxx吗?,直接上代码?
class Cat { public void jump() { System.out.println("这个猫在跳!!!"); } public void run() { this.jump(); // 在run方法中用this.方法名调用当前对象的一个成员方法jump System.out.println("这个猫在跑!!!"); } } public class TestDemo2 { public static void main(String[] args) { Cat cat = new Cat(); cat.run(); } }
? 可以看出在我们成功的在run方法中用this.方法名调用了同一个类下的其他方法。
注意?:
虽然调用本类的普通方法前可以不使用this关键词。但是建议追加是this,这样的目的是可以区分方法的定义来源?
?咱们之前说了,同一个类中可以同时有多个构造函数,通过this()还可以在一个构造函数里调用另一个构造函数。
class Cat { String name; int age; Cat() { System.out.println("这是自定义的一个不带参数的构造函数"); } public Cat(String name, int age) { this(); // 调用另一个不带参数的构造方法 this.name = name; this.age = age; System.out.println(this.name + this.age + "岁了"); System.out.println("这是自定义的一个带两个参数的构造函数"); } } public class TestDemo2 { public static void main(String[] args) { Cat cat = new Cat("小花", 3); } }
从输出结果可以看出通过?this(),我们成功在一个构造方法中调用另一个不带参数的构造方法
?但有几个问题需要我们注意一下
另外,再补充一些小细节?
很多小伙伴可能不理解,为什么要通过这种方式来调用构造方法呢?我们在上面调用Cat类中一个不带参数的构造方法时,难道不能直接写一个?Cat();来调用吗?
????????????????
?这里必须做出解释:在Java语言中,一个类的构造方法与类名相同。但是,一个类当中也可以定义一个与类名相同的”普通方法”,?换句话说就是:并不是只有构造方法与类名相同,”普通方法”也可以取和类相同的名称(只不过全世界的程序员都不会这么干)。
?那么,在这种情况下,编译器如何区分这个方法是”普通方法”还是”构造方法”呢??很简单,”普通方法”的名称前面必须定义返回值类型,而”构造方法”的名称前面则没有返回值类型的定义。这样,编译器就能够分得清哪个是”构造方法”,哪个是”和类同名的普通方法”。
?定义的时候分得清,但是在调用的时候,都是通过方法名来调用的?,这时如何分得清代码中哪一句调用的是”构造方法”, 哪一句调用的是”和类同名的普通方法”呢?为了解决这个问题,Java语言规定,在本类中调用构造方法的时候,需要通过”?this(参数)”的方式来调用。