typora-root-url: images
何谓编程思想?首先解释一下“思想”。
先问你个问题:你想做个怎样的人?
可能你会回答:我想做个好人,孝敬父母,尊重长辈,关爱亲朋…
你看,这就是思想。这是你做人的思想,或者说,是你做人的原则。做人有做人的原则,编程也有编程的原则。这些编程的原则呢,就是编程思想。
面向过程与面向对象都是我们编程中,编写程序的一种思维方式。
面向过程
面向过程的程序设计方式,是遇到一件事时,思考“我该怎么做”,然后一步步实现的过程。
例如:公司打扫卫生(擦玻璃、扫地、拖地、倒垃圾等),按照面向过程的程序设计方式会思考“打扫卫生我该怎么做,然后一件件的完成”,最后把公司卫生打扫干净了。
面向对象
面向对象的程序设计方式,是遇到一件事时,思考“我该让谁来做”,然后那个“谁”就是对象,他要怎么做这件事是他自己的事,反正最后一群对象合力能把事就好就行了。
例如,公司打扫卫生(擦玻璃、扫地、拖地、倒垃圾等),按照面向对象的程序设计方式会思考“我该让谁来做,如小明擦玻璃、让小丽扫地、让小郭拖地、让小强倒垃圾等”,这里的“小明、小丽、小郭、小强”就是对象,他们要打扫卫生,怎么打扫是他们自己的事,反正最后一群对象合力把公司卫生打扫干净了。
需求:买电脑(组装机)
假如我们需要买组装电脑,这时首先会在网上查询具体每一个硬件的参数和报价。然后会去电脑城进行多家询价,接着询价结束后回家根据具体的结果分析出自己比较满意的哪家报价,接着会到这家店里进行组装,组装时还需要进行现场监督,组装完成安装相应的系统,然后电脑抱回家。
分析上述整个过程大体分一下几步:上网查询参数和报价、电脑城询价、现场安装和监督、抱电脑回家。在整个过程中我们参与了每一个细节,并且会感觉相当累。
假如我们需要买组装机,这时应该找一个懂电脑硬件的人,让他帮我们查看参数和报价,并进行询价和杀价,以及现场组装监督。而我们自己并不需要亲历亲为具体怎么做,只要告诉这个人我们想要的具体需求即可。
分析上述整个过程,发现瞬间变的十分轻松,只要找到懂电脑硬件的这个人,我们的问题都可以解决。并且在这个过程中我们不用那么辛苦。
通过生活中的真实场景使用面向对象分析完之后,我们开始分析面向过程和面向对象的差异做出总结:
洗衣服:
面向过程:把衣服脱下来-->找盆-->放洗衣粉-->加点水-->浸泡10分钟-->揉一揉-->清洗衣服-->拧干-->晾起来
面向对象:把衣服脱下来-->打开全自动洗衣机-->扔衣服-->按钮-->晾起来
区别:
对面向对象有了了解之后,我们来说说在具体问题中如何使用面向对象去分析问题,和如何使用面向对象。
我们把大象装冰箱为例进行分析。
在针对具体的需求,可以使用名词提炼的办法进行分析,寻找具体的对象。
需求:把大象装冰箱里
对象:大象、冰箱
分三步:
1、打开冰箱门
2、将大象装进去
3、关闭冰箱门
分析发现打开、装、关闭都是冰箱的功能。即冰箱对象具备如下功能:
冰箱打开
冰箱存储
冰箱关闭
用伪代码描述,上述需求中有两个具体的事物 大象 和 冰箱
描述大象:
class 大象
{
}
描述冰箱:
class冰箱
{
void 打开(){}
void 存储(大象){}
void 关闭(){}
}
当把具体的事物描述清楚之后,需要使用这些具体的事物,Java使用具体的事物,需要通过new关键字来创建这个事物的具体实例。
使用对象:
1、创建冰箱的对象
冰箱 bx = new 冰箱();
2、调用冰箱的功能
对象.功能();
bx.打开();
bx.存储(new 大象());
bx.关闭();
总结:
在分析现实生活中的事物时发现,这些事物都有其具体的特点和功能,这些特点和功能就组成了这个特殊的事物。
描述小汽车。
分析:
事物的特点(属性):
颜色。
轮胎个数。
事物的(功能):
运行。
发现:事物其实就是由特点(属性)和行为(功能)组成的。
可以简单理解:属性就是数值,其实就是变量;行为就是功能,就是方法。
小汽车 {
颜色;
轮胎个数;
运行() { }
}
通过计算机语言Java来描述这个事物:
定义类的格式:
public class 类名 {
//可编写0至n个属性
数据类型 变量名1;
数据类型 变量名2;
//可编写0至n个方法
修饰符 返回值类型 方法名(参数){
执行语句;
}
}
汽车类:
public class Car {
String color;
int number;
public void run() {
System.out.println(color + ":" + number);
}
}
通过代码的描述,知道类的真正意义就是在描述事物。属性和功能统称为事物中的成员。
# 类名 对象名 = new 类名();
public class CarDemo {
public static void main(String[] args) {
// 1,创建Car的对象。给对象起个名字。
Car c = new Car();// c是类类型的变量。c指向了一个具体的Car类型的对象。
// 2,通过已有的对象调用该对象的功能。格式:对象.对象成员;
// 3,可以该对象的属性赋值。
c.color = "red";
c.number = 4;
c.run();
}
}
经过上面对小汽车的描述,和Java代码测试,我们虽然可以将生活中的事物使用Java代码描述出来,但是这些代码在内存中是如何执行的,接下来我们需要研究下对象在内存的图解。
接下来就是分析对象在内存中的分配情况。这里需要画图一步一步演示,严格按照画图流程讲解内存对象创建过程。
面向对象的编程思想力图在程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出两个概念,即类和对象。其中,类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。接下来通过一个图例来抽象描述类与对象的关系,如下图所示。
在上图中,可以将玩具模型看作是一个类,将一个个玩具看作对象,从玩具模型和玩具之间的关系便可以看出类与对象之间的关系。类用于描述多个对象的共同特征,它是对象的模板。对象用于描述现实中的个体,它是类的实例。从上图中可以明显看出对象是根据类创建的,并且一个类可以对应多个对象。
经过前面几个知识点的学习,基本上掌握了类是用于描述事物的,类中可以定义事物的属性和行为。而对象是通过描述的这个类,使用new关键字创建出来,通过对象就可以调用该对象具体的属性和功能了。
理解清楚了类和对象之后,发现在描述类的属性和前面学习定义变量差别不大,唯一区别就是位置发生了改变,那么类中定义的变量,和在方法定义的变量有啥差别呢?
回忆以前学习时变量的定义方式和位置,以及现在定义类中属性的特点。总结下面几点异同:
区别一:定义的位置不同
区别二:在内存中的位置不同
区别三:声明周期不同
区别四:初始化不同
基本类型作为参数传递时,其实就是将基本类型变量x空间中的值复制了一份传递给调用的方法show(),当在show()方法中x接受到了复制的值,再在show()方法中对x变量进行操作,这时只会影响到show中的x。当show方法执行完成,弹栈后,程序又回到main方法执行,main方法中的x值还是原来的值。
当引用变量作为参数传递时,这时其实是将引用变量空间中的内存地址(引用)复制了一份传递给了show方法的d引用变量。这时会有两个引用同时指向堆中的同一个对象。当执行show方法中的d.x=6时,会根据d所持有的引用找到堆中的对象,并将其x属性的值改为6.show方法弹栈。
由于是两个引用指向同一个对象,不管是哪一个引用改变了引用的所指向的对象的中的值,其他引用再次使用都是改变后的值。
类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该
类事物。
现实中,描述一类事物:
举例:小猫。
对象:是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为。
现实中,一类事物的一个实例:一只小猫。
举例:一只小猫。
现实世界的一类事物: 属性:事物的状态信息。 行为:事物能够做什么。
Java中用class描述事物也是如此: 成员变量:对应事物的属性 ;成员方法:对应事物的行为 。
简单来说,定义一个类的步骤是:
① 定义类
② 编写类的成员变量
③ 编写类的成员方法
public class 类名{
// 成员变量
// 成员方法
}
public class Phone{
String brand;
int price;
//成员方法
public void call() {
System.out.println("打电话");
}
public void sendMessage() {
System.out.println("发短信");
}
}
# 类名 对象名 = new 类名();
# 对象名.成员变量;
# 对象名.成员方法();
class Student {
//成员变量
String name;
int age;
//成员方法
public void study() {
System.out.println("好好学习,天天向上");
}
public void doHomework() {
System.out.println("键盘敲烂,月薪过万");
}
}
/* 学生测试类 */
public class StudentDemo {
public static void main(String[] args) {
//创建对象
Student s = new Student();
//使用对象
System.out.println(s.name + "," + s.age);
s.name = "林青霞";
s.age = 30;
System.out.println(s.name + "," + s.age);
// 调用方法
s.study();
s.doHomework();
}
}
需求:首先定义一个手机类,然后定义一个手机测试类,在手机测试类中通过对象完成成员变量和成员方法的使用
分析:
示例代码:
public class Phone {
// 成员变量
String brand; //品牌
int price; //价格
String color; //颜色
// 成员方法
//打电话
public void call(String name) {
System.out.println("给"+name+"打电话");
}
//发短信
public void sendMessage() {
System.out.println("群发短信");
}
}
public class Test02Phone {
public static void main(String[] args) {
//创建对象
Phone p = new Phone();
//输出成员变量值
System.out.println("品牌:"+p.brand);//null
System.out.println("价格:"+p.price);//0
System.out.println("颜色:"+p.color);//null
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐");
//给成员变量赋值
p.brand = "锤子";
p.price = 2999;
p.color = "棕色";
//再次输出成员变量值
System.out.println("品牌:"+p.brand);//锤子
System.out.println("价格:"+p.price);//2999
System.out.println("颜色:"+p.color);//棕色
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐");
//调用成员方法
p.call("紫霞");
p.sendMessage();
}
}
通过上图,我们可以理解,在栈内存中运行的方法,遵循"先进后出,后进先出"的原则。变量p指向堆内存中 的空间,寻找方法信息,去执行该方法。
但是,这里依然有问题存在。创建多个对象时,如果每个对象内部都保存一份方法信息,这就非常浪费内存了,因为所有对象的方法信息都是一样的。那么如何解决这个问题呢?请看如下图解。
对象调用方法时,根据对象中方法标记(地址值),去类中寻找方法信息。这样哪怕是多个对象,方法信息只保存一份,节约内存空间。
引用类型作为参数,传递的是地址值。
提起封装,大家并不陌生。前面我们学习方法时,就提起过,将具体功能封装到方法中,学习对象时,也提过将方法封装在类中,其实这些都是封装。
封装,它也是面向对象思想的特征之一。面向对象共有三个特征:封装,继承,多态。接下来我们具体学习封装。
封装表现:
从以上两点得出结论,封装的好处:
一台电脑,它是由CPU、主板、显卡、内存、硬盘、电源等部件组成,其实我们将这些部件组装在一起就可以使用电脑了,但是发现这些部件都散落在外面,很容造成不安全因素,于是,使用机箱壳子,把这些部件都装在里面,并在机箱壳上留下一些插口等,若不留插口,大家想想会是什么情况。
总结:机箱其实就是隐藏了各部件设备的细节,对外提供了插口以及开关等访问内部细节的方式。
我要用洗衣机,只需要按一下开关和洗涤模式就可以了。有必要了解洗衣机内部的结构吗?有必要碰电动机吗?
我们程序设计追求“高内聚,低耦合”:
隐藏对象内部的复杂性,只对外公开简单的接口:
便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。但除此之外,没有其他制约条件。但是,实际问题中,我们往往需要给属性赋值加入额外限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行条件的添加。比如说,每个人都有年龄属性(age),如果直接赋值的话,有可能输入的是非法的值。所以,我们需要避免用户再使用“对象.属性”的方式对属性进行赋值。则需要将属性声明为私有的(private),如果属性是私有的,那么外部是不能直接访问的,那么此时,针对于属性就体现了封装性。当然我们还是需要对属性赋值的嘛,怎么办呢?就需要通过方法进行对该属性赋值,那么在方法中,就可以实现对用户赋予的值进行判断了,从而避免非法值赋予年龄。
描述人。Person
属性:年龄。
行为:说话:说出自己的年龄。
class Person {
int age;
String name;
public void show() {
System.out.println("age=" + age + ",name" + name);
}
}
public class PersonDemo {
public static void main(String[] args) {
// 创建Person对象
Person p = new Person();
p.age = -20; // 给Person对象赋值
p.name = "人妖";
p.show(); // 调用Person的show方法
}
}
通过上述代码发现,虽然我们用Java代码把Person描述清楚了,但有个严重的问题,就是Person中的属性的行为可以任意访问和使用。这明显不符合实际需求。
可是怎么才能不让访问呢?需要使用一个Java中的关键字也是一个修饰符 private(私有,权限修饰符)。只要将Person的属性和行为私有起来,这样就无法直接访问。
class Person {
private int age;
private String name;
public void show() {
System.out.println("age=" + age + ",name" + name);
}
}
年龄已被私有,错误的值无法赋值,可是正确的值也赋值不了,这样还是不行,那肿么办呢?按照之前所学习的封装的原理,隐藏后,还需要提供访问方式。只要对外提供可以访问的方法,让其他程序访问这些方法。同时在方法中可以对数据进行验证。
一般对成员属性的访问动作:赋值(设置 set),取值(获取 get),因此对私有的变量访问的方式可以提供对应的 setXxx或者getXxx的方法。
class Person {
// 私有成员变量
private int age;
private String name;
// 对外提供设置成员变量的方法
public void setAge(int a) {
// 由于是设置成员变量的值,这里可以加入数据的验证
if (a <0 || a > 130) {
System.out.println(a + "不符合年龄的数据范围");
return;
}
age = a;
}
// 对外提供访问成员变量的方法
public void getAge() {
return age;
}
}
类中不需要对外提供的内容都私有化,包括属性和方法。
以后再描述事物,属性都私有化,并提供setXxx getXxx方法对其进行访问。
注意:私有仅仅是封装的体现形式而已。
修饰符:
public class Student {
private String name;
private int age;
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
}
我们发现 setXxx 方法中的形参名字并不符合见名知意的规定,那么如果修改与成员变量名一致,是否就见名知意了呢?
public class Student {
private String name;
private int age;
public void setName(String name) {
name = name;
}
public void setAge(int age) {
age = age;
}
}
经过修改和测试,我们发现新的问题,成员变量赋值失败了。也就是说,在修改了 setXxx() 的形参变量名后,方法并没有给成员变量赋值!这是由于形参变量名与成员变量名重名,导致成员变量名被隐藏,方法中的变量名,无法访问到成员变量,从而赋值失败。所以,该怎么解决?
当在方法中出现了局部变量和成员变量同名的时候,那么在方法中怎么区别局部变量成员变量呢?可以在成员变量名前面加上this.来区别成员变量和局部变量。
注意:
事实上:
this代表所在类的当前对象的引用(地址值),即对象自己的引用。
记住 :方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。
使用 this 修饰方法中的变量,解决成员变量被隐藏的问题。
public class Student {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
方法中只有一个变量名时,默认也是使用this 修饰,可以省略不写。
代码
class Person {
private int age;
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
}
public class PersonDemo {
public static void main(String[] args) {
Person p = new Person();
p.setAge(30);
System.out.println("大家好,今年我" + p.getAge() + "岁");
}
}
图示
解释
程序执行流程说明:
1. 先执行main方法(压栈),执行其中的 Person p = new Person();
2. 在堆内存中开辟空间,并为其分配内存地址0x1234,紧接着成员变量默认初始化(age = 0);将内存地址0x1234赋值给栈内中的Person p 变量
3. 继续执行p.setAge(30)语句,这时会调用setAge(int age)方法,将30赋值为setAge方法中的“age”变量;执行this.age = age语句,将age变量值30 赋值给成员变量this.age为30;
4. setAge()方法执行完毕后(弹栈),回到main()方法,执行输出语句System.out.println(),控制台打印p对象中的age年龄值。
注意:
我们对封装已经有了基本的了解,接下来我们来看一个新的问题,依然以Person为例,由于Person中的属性都被private了,外界无法直接访问属性,必须对外提供相应的set和get方法。
但是我们当创建人对象的时候,人对象一创建就要明确其姓名和年龄,那该怎么做呢?
在开发中经常需要在创建对象的同时明确对象的属性值,比如员工入职公司就要明确他的姓名、年龄等属性信息。
那么,创建对象就要明确属性值,那怎么解决呢?也就是在创建对象的时候就要做的事情,当使用new关键字创建对象时,怎么给对象的属性初始化值呢?这就要学习Java另外一门小技术,构造方法。
那什么是构造方法呢?从字面上理解即为构建创造对象时用的方法,即就是对象创建时要执行的方法。既然是对象创建时要执行的方法,那么只要在new对象时,知道其执行的构造方法是什么,就可以在执行这个方法的时候给对象进行属性赋值。
修饰符 构造方法名(参数列表){
// 方法体
}
class Person {
// Person的成员属性age和name
private int age;
private String name;
// Person的构造方法,拥有参数列表
Person(int age, String name) {
// 接受到创建对象时传递进来的值,将值赋给成员属性
this.age = age;
this.name = name;
}
}
构造方法是一种特殊的方法,主要是创建对象,并且完成对象数据的初始化。
// 学生类
class Student {
private String name;
private int age;
public Student() {
}
public Student(String name) {
this.name = name;
}
public Student(int age) {
this.age = age;
}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println(name + "," + age);
}
}
// 测试类
public class StudentDemo {
public static void main(String[] args) {
//创建对象
Student s1 = new Student();
s1.show();
//public Student(String name)
Student s2 = new Student("林青霞");
s2.show();
//public Student(int age)
Student s3 = new Student(30);
s3.show();
//public Student(String name,int age)
Student s4 = new Student("林青霞",30);
s4.show();
}
}
class Person {
// Person的成员属性age和name
private int age;
private String name;
// Person的构造方法,拥有参数列表
Person(int a, String nm) {
// 接受到创建对象时传递进来的值,将值赋给成员属性
age = a;
name = nm;
}
public void speak() {
System.out.println("name=" + name + ",age=" + age);
}
}
class PersonDemo {
public static void main(String[] args) {
// 创建Person对象,并明确对象的年龄和姓名
Person p2 = new Person(23, "张三");
p2.speak();
}
}
即在创建对象时,会调用与参数列表对应的构造方法。
在没有学习构造方法之前,我们也可以通过new关键字创建对象,并调用相应的方法,同时在描述事物时也没有写构造方法。这是为什么呢?
在之前学习的过程中,描述事物时,并没有显示指定构造方法,当在编译Java文件时,编译器会自动给class文件中添加默认的构造方法。如果在描述类时,我们显示指定了构造方法,那么,当在编译Java源文件时,编译器就不会再给class文件中添加默认构造方法。
class Person {
//如果没有显示指定构造方法,编译会在编译时自动添加默认的构造方法
//Person(){} //空参数的默认构造方法
}
当在描述事物时,要不要在类中写构造方法呢?这时要根据描述事物的特点来确定,当描述的事物在创建其对象时就要明确属性的值,这时就需要在定义类的时候书写带参数的构造方法。若创建对象时不需要明确具体的数据,这时可以不用书写构造方法(不书写也有默认的构造方法)。
class Person {
private int age;
private String name;
// 私有无参数的构造方法,即外界不能通过new Person();语句创建本类对象
private Person() {
}
// 多个构造方法是以重载的形式存在
Person(int a) {
age = a;
}
Person(String nm, int a) {
name = nm;
age = a;
}
}
到目前为止,学习两种方法,分别为构造方法和一般方法,那么他们之间有什么异同呢?
问题:
有了构造方法之后可以对对象的属性进行初始化,那么还需要对应的set和get方法吗?
答案:需要相应的set和get方法,因为对象在创建之后需要修改和访问相应的属性值时,在这时只能通过set或者get方法来操作。
JavaBean 是 Java语言编写类的一种标准规范。符合 JavaBean 的类,要求类必须是具体的和公共的,并且具有无参数的构造方法,提供用来操作成员变量的 set 和 get 方法。
所谓 javaBean,是指符合如下标准的 Java 类:
public class Student {
//成员变量
private String name;
private int age;
//构造方法
public Student() {
}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
//成员方法
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
publicint getAge() {
return age;
}
}
public class TestStudent {
public static void main(String[] args) {
//无参构造使用
Student s= new Student();
s.setName("柳岩");
s.setAge(18);
System.out.println(s.getName()+"‐‐‐"+s.getAge());
//带参构造使用
Student s2= new Student("赵丽颖",18);
System.out.println(s2.getName()+"‐‐‐"+s2.getAge());
}
}
在之前学习方法时,我们知道方法之间是可以相互调用的,那么构造方法之间能不能相互调用呢?若可以,怎么调用呢?
在之前学习方法之间调用时,可以通过方法名进行调用。可是针对构造方法,是无法通过构造方法名来相互调用。
构造方法之间的调用,可以通过this关键字来完成。
this(参数列表);
class Person {
// Person的成员属性
private int age;
private String name;
// 无参数的构造方法
Person() {
}
// 给姓名初始化的构造方法
Person(String name) {
this.name = name;
}
// 给姓名和年龄初始化的构造方法
Person(String name, int age) {
// 由于已经存在给姓名进行初始化的构造方法 this.name = name;因此只需要调用即可
// 调用其他构造方法,需要通过this关键字来调用
this(name);
// 给年龄初始化
this.age = age;
}
}
了解了构造方法之间是可以相互调用,那为什么他们之间通过this就可以调用呢?
通过上面的学习,简单知道使用this可以实现构造方法之间的调用,但是为什么就会知道this调用哪一个构造方法呢?接下来需要图解完成。
class Person {
private int age;
private String name;
Person() {
}
Person(String nm) {
name = nm;
}
Person(String nm, int a) {
this(nm);
age = a;
}
}
class PersonDemo {
public static void main(String[] args) {
Person p = new Person("张三", 23);
}
}
解释说明:
1、先执行main方法,main方法压栈,执行其中的new Person(“张三”,23);
2、堆内存中开辟空间,并为其分配内存地址0x33,紧接着成员变量默认初始化(name=null age = 0);
3、拥有两个参数的构造方法(Person(String nm , int a))压栈,在这个构造方法中有一个隐式的this,因为构造方法是给对象初始化的,那么哪个对象调用到这个构造方法,this就指向堆中的哪个对象。
4、由于Person(String nm , int a)构造方法中使用了this(nm);构造方法Person(String nm)就会压栈,并将“张三”传递给nm。在Person(String nm , int a)构造方法中同样也有隐式的this,this的值同样也为0x33,这时会执行其中name = nm,即把“张三”赋值给成员的name。当赋值结束后Person(String nm , int a)构造方法弹栈。
5、程序继续执行构造方法(Person(String nm , int a)中的age = a;这时会将23赋值给成员属性age。赋值结束构造方法(Person(String nm , int a)弹栈。
6、当构造方法(Person(String nm , int a)弹栈结束后,Person对象在内存中创建完成,并将0x33赋值给main方法中的p引用变量。
this到底代表什么呢?this代表的是对象,具体代表哪个对象呢?哪个对象调用了this所在的方法,this就代表哪个对象。
调用其他构造方法的语句必须定义在构造方法的第一行,原因是初始化动作要最先执行。
通过上面学习,基本明确了对象初始化过程中的细节,也知道了构造方法之间的调用是通过this关键字完成的。但this也有另外一个用途,接下来我们就学习下。
当在方法中出现了局部变量和成员变量同名的时候,那么在方法中怎么区别局部变量成员变量呢?
可以在成员变量名前面加上this.来区别成员变量和局部变量
class Person {
private int age;
private String name;
// 给姓名和年龄初始化的构造方法
Person(String name, int age) {
// 当需要访问成员变量是,只需要在成员变量前面加上this.即可
this.name = name;
this.age = age;
}
public void speak() {
System.out.println("name=" + this.name + ",age=" + this.age);
}
}
class PersonDemo {
public static void main(String[] args) {
Person p = new Person("张三", 23);
p.speak();
}
}
需求:在Person类中定义功能,判断两个人是否是同龄人。
class Person {
private int age;
private String name;
// 给姓名和年龄初始化的构造方法
Person(String name, int age) {
// 当需要访问成员变量是,只需要在成员变量前面加上this.即可
this.name = name;
this.age = age;
}
public void speak() {
System.out.println("name=" + this.name + ",age=" + this.age);
}
// 判断是否为同龄人
public boolean equalsAge(Person p) {
// 使用当前调用该equalsAge方法对象的age和传递进来p的age进行比较
// 由于无法确定具体是哪一个对象调用equalsAge方法,这里就可以使用this来代替
return this.age == p.age;
}
}
② 构造方法中不能通过"this(形参列表)"的方式调用自己。
③ 如果一个类中声明了n个构造方法,则最多有n -1个构造方法中使用了"this(形参列表)"。
④ "this(形参列表)"必须声明在类的构造器的首行!
⑤ 在类的一个构造器中,最多只能声明一个"this(形参列表)"。