嗯,说到了构造函数,先说他是个什么东西。
构造函数,就是定义在类中,用于对成员变量进行初始化的函数(这里说得并不算准确,因为构造函数体中也可以不包含初始化语句)。构造函数没有返回值,可以有形参,前面的修饰符为public,可加可不加。
下面举个例子,比如有一个Person类
class Person
{
private String name; private int age;
Person(){}//这是Person类中的构造函数
void Person(){}//这仅仅是一个名字为Person的函数,返回值为空!注意,构造函数无返回值!
}
需要强调的是,构造函数的函数名必须与类名相同。
当然,构造函数也可以接受参数,比如Person(String name){this.name=name;}
形参name通过主函数在创建Person类成员时(如Person p = new Person("小明");)传递。创建过程简单分析如下:(进栈也叫压栈,出栈也叫弹栈)
首先主函数进栈,创建出一个变量p。
接着在堆中创建区域用来存放Person类(new关键字创建的区域存放在堆中)。Person类中有name、age两个变量,分别初始化为null、0(堆里的成员可以进行自动初始化,栈中则不行)。
然后调用构造函数Person()。即Person()函数进栈。进栈时字符串"小明"传递给Person函数的形参name,Person中出现this关键字,将之前堆中创建的对象的地址赋值给它(不太清楚这里的专有名词叫什么,望大神指正)。
注:此时穿插讲了this关键字的含义,即代表调用对象的地址
this关键字的出现,解决了一个变量重名的问题。(如果传递给构造函数的参数名字叫 n,则代码可读性差,但要是叫name,则会重名,虽然编译不会出错,但是彼此赋值的时候,其实指的是自身赋值给自身,接下来会详细讲到)。
在语句this.name=name;这条语句中,this.name,代表的是已经在堆中创建的对象中的name(那个已经初始化为NULL的实例),而后面的name ,则仅仅是Person函数的形参。
因为this.name具有指向性,所以也就代表被赋值的其实是堆中的name。
构造函数完成后,就会弹栈,同时会将之前创建在堆中的对象的地址赋值给p。((-。-;)嗯,这是最后一步)
需要注意的是
1、给this赋地址值是隐形操作,即这一步不用在代码中显性地表达出来。我们只要明白,正是有了这一步,所以this.name才能准确地指向确定的调用对象(毕竟堆中很可能存在多个Person实例)。
2、给对象中实例初始化(即NULL,0)这一步看似毫无用处,但是它确实是存在的,并且是在调用构造函数之前就已经完成了的。
构造函数的出现,方便了我们对类成员变量的初始化。毕竟不能老用堆来初始化一些数据(因为某些数据在第一次出现时就应该是有意义的)。
构造函数也也已避免用户对类成员进行一些非法赋值。
为了程序的安全性,成员变量通常用private修饰,它们是不可被外部类访问的,此时,就需要在中间架上一座桥梁(即Person()函数中所需要的参数),对这个参数进行限制后,再将此参数的值赋值给类中的变量。
这样既保证了良好的封装性,也保证了安全性。
顺便说明一下,如果程序员在类中没有定义构造函数,java是会自动给我们加上一个极简构造函数的。(例:Person(){})