初始化
今天在讲构造函数与成员函数的区别之前,我们先提出一个成员变量初始化的问题,因为在面向对象中,构造函数有它特殊的意义,我们创建对象时,成员变量的数值是怎样变化的呢?
- 默认初始化
public class CarTest{
public static void main(String[] args){
Car c = new Car();//创建对象并将地址赋给变量c
c.run();//对象的引用c调用run();
}
}
class Car{
String brand;//成员变量 品牌
char color;//成员变量 颜色
public void run(){
System.out.println("品牌:"+brand+" 颜色:"+color);
}
}
如果运行 CarTest ,就会出现该结果:品牌:null 颜色:0
所以,当我们对象创建时,成员变量会默认初始化。
String 默认 null
int 默认 0
double 默认 0.0
char 默认 0
boolean 默认 false
- 显式初始化
public class CarTest{
public static void main(String[] args){
Car c1 = new Car();//创建对象并将地址赋给变量c1
c1.run();//对象的引用c1调用函数run();
Car c2 = new Car();//创建对象并将地址赋给变量c2
c2.run();//对象的引用c2调用函数run();
Car c3 = new Car();//创建对象并将地址赋给变量c3
c3.brand="BYD";//将"BYD"赋给成员变量brand
c3.run();//c3再次调用run()
}
}
class Car{
String brand="BMW";//成员变量 品牌=BMW
char color='b';//成员变量 颜色=b
public void run(){
System.out.println("品牌:"+brand+" 颜色:"+color);
}
}
上述成员变量没有添加权限,一般会加private,这里对该问题先不注重!
运行 CarTest ,就会出现该结果:
- 品牌:BMW 颜色:b
- 品牌:BMW 颜色:b
- 品牌:BYD 颜色:b
上述三种结果,如果我们不去修改成员变量的值,那么它显示的结果就是我们Car类中成员变量一开始就赋的初始值“BMW”和‘b’,但是他们都会先经过默认初始化,从无到有,然后进行显式初始化,才会有“BMW”和‘b’的结果。
c1,c2 的结果是创建对象过程时,把值给了c1,c2;c3是创建时先进行了默认初始化,又进行了显式初始化,当时值为“BMW”和‘b’,创建完后最终又将“brand”的值改为BYD,经过了从无到有到更改,那么我们想直接创建一个BYD的品牌,那么就提出第三种初始化,针对性初始化。
- 针对性初始化
我们在文章的开头提到了构造函数有特殊意义,那么在这里它的意义就是针对性初始化,首先我们来了解构造函数的格式:
//构造函数格式
权限修饰符 类名(参数列表){
return;//默认存在,仅仅代表结束函数
}
- 注意:无参的构造函数默认存在,如果类中定义了其他有参的构造函数,无参的构造函数就不存在,建议一般直接将无参的写在第一个。
可以看出来,构造函数和成员函数的第一个区别是:构造函数不需要返回值类型,而成员函数可需可不需。
我们继续讨论针对性初始化:
public class CarTest{
public static void main(String[] args){
Car c1 = new Car();//创建对象并调用无参构造函数Car()
c1.run();
Car c2 = new Car("Audi");//创建对象并调用构造函数Car(String brand)
c2.run();
Car c3 = new Car("Ferrari",'r');//创建对象并调用构造函数Car(String brand,char color)
c3.run();
}
}
class Car{
String brand="BMW";//成员变量 品牌=BMW
char color='b';//成员变量 颜色=b
public Car(){}
public Car(String brand){
this.brand=brand;
}
public Car(String brand,char color){
this.brand=brand;
this.color=color;
}
public void run(){
System.out.println("品牌:"+brand+" 颜色:"+color);
}
}
运行 CarTest ,出现该结果:
- 品牌:BMW 颜色:b
- 品牌:Audi 颜色:b
- 品牌:Ferrari 颜色:r
在该代码中这个就是针对性初始化,但是它的结果经历是:
- 创建对象时,成员变量brand和color默认初始化分别为null和0;
- 如果有了初始值,就在创建对象时,当调用构造函数进栈时,再进行显式初始化;
- 当调用的是有参数的构造函数,进行具体代码功能,将传入的局部变量赋值给当前对象的成员变量,称为针对性初始化。
this关键字
在我们说到初始化的问题时,我们代码中写了this关键字, 如:
public class CarTest{
public static void main(String[] args){
Car c2 = new Car("Audi");//创建对象并调用构造函数Car(String brand)
c2.run();
}
}
class Car{
String brand="BMW";//成员变量 品牌=BMW
char color='b';//成员变量 颜色=b
public Car(){}
public Car(String brand){
this.brand=brand;
}
public Car(String brand,char color){
this.brand=brand;
this.color=color;
}
public void run(){
System.out.println("品牌:"+brand+" 颜色:"+color);
}
}
上述分别为无参,有一个参数,有两个参数的构造函数,他们之中有this关键字,如:this.brand=brand;左边的this指的是当前对象的引用,存放当前对象的地址,因为在创建对象的同时,调用构造函数,所以this就是指创建出来的对象,如Car c2 = new Car(“Audi”);this就是指的c2,他在构造函数的空间里相当于一个变量,里面存放这c2的地址(c2是对象的引用存放对象地址),调用的是一个参数的构造函数Car(String brand),“Audi”是该构造函数的局部变量brand的值,this.brand=brand;就是将局部变量brand传入的值“Audi”赋值给当前对象c2的成员变量brand。
我们画图演示一下:
所以,当下面的成员函数被调用执行后,输出的结果就是调用的对象c2中的成员变量 brand=Audi 和 color=0;
public void run(){
System.out.println("品牌:"+brand+" 颜色:"+color);
}
- this第一个用处就是本身表示当前对象的引用
this()
- 上述我们说到this本身是对当前对象的引用,还有一个作用就是this(参数列表)表示调用当前类中其他的构造函数,通过以下代码证明:
class Car{
String brand;//成员变量 品牌
char color;//成员变量 颜色
public Car(){
//Car(null,0);
this(null,0);
}
public Car(String brand){
//Car(brand,0);
this(brand,0);
}
public Car(char color){
//Car(null,color);
this(null,color);
}
public Car(String brand,char color){
this.brand=brand;
this.color=color;
}
public void run(){
System.out.println("品牌:"+brand+" 颜色:"+color);
}
}
对比上面的代码,我们可以看到,一个参数的构造函数里面有调用的是两个参数的构造函数,不过构造函数如果只有一个参数,另一个参数在调用两个参数的时候传入的参数为默认值:如 this(brand,0) 和 this(brand,0)
- this(参数列表)必须放在第一句,否则会覆盖。
public class CarTest{
public static void main(String[] args){
Car c1 = new Car("Audi");
}
}
class Car{
String brand;//成员变量 品牌
char color;//成员变量 颜色
public Car(){
//Car(null,0);
this(null,'0');
}
public Car(String brand){
//Car(brand,0);
brand="BMW";//看这里!!!
this(brand,'0');
}
public Car(char color){
//Car(null,color);
this(null,color);
}
public Car(String brand,char color){
this.brand=brand;
this.color=color;
}
p ublic void run(){
System.out.println("品牌:"+brand+" 颜色:"+color);
}
}
当我们编译这段代码时,会报以下错误:
假设先忽略这个要放在第一句的错误,brand=“BMW”;this(brand,‘0’);执行成功,但是我们调用时 new Car(“Audi”) ,传入的是 (“Audi” ),结果会显示 Audi,"BMW"会被覆盖,所以要将this(参数列表)放在第一句。
OK!这个就是成员变量初始化和this关键字的东西,下一篇我打算是沿着this这个思路,讲构造函数和成员函数的区别,以及他们之间的调用。