------- android培训、java培训、期待与您交流! ----------
一、初始化对象:构造函数
构造函数顾名思义,也是类中的成员方法,但是他的地位和作用相比普通方法有些特殊。那么它与普通的方法之间有什么区别呢?
1. 构造函数的特点(构造方法与一般方法在写法上的不同)
1) 方法名(函数名)与类名相同
2) 不用定义返回值类型
3) 由第二条决定了,构造函数不可以写return语句。
小知识点1:
注意,上述第二条,不能理解为返回值类型为void。因为void本身就是一种返回值类型,它表明了该方法没有返回值。而构造函数中,根本就不能有返回值,也就不存在定义哪种返回值类型的问题了。因此,在构造函数的末尾不需要加return语句,系统也不会默认地帮我们加上。
代码1:
class Person
{
Person()
{
System.out.println(“大家好!”);
}
}
class PersonDemo
{
public static void main(String[] args)
{
Personp = new Person();
}
}
当我们在运行上述代码时,会发现构造函数的输出语句被执行了。实际上,当我们通过“new”关键字创建新对象的同时,就会去调用该类的构造函数。
2. 构造函数的作用
我们说构造函数的作用:就是用于给对象进行初始化。通过上文描述以及代码演示,我们可以更好的理解这一点。实际上,这种特性也是符合我们日常生活的规律的。很多事物一出现,就会具备很多基本的属性和行为。比如,人一出生就会有“姓名”和“年龄”等属性,以及“哭泣”的行为。
小知识点2:
细心的同学可能已经发现了,我们在定义一个类的时候,即使没有定义它的构造函数,也是可以创建它的对象的。这是因为,如果某个类没有被人为地定义构造函数,那么“系统”就会默认为其添加空参数的构造函数:
Person(){}
这样做的目的就是方便该类进行初始化。相反,如果一个类没有定义构造函数,那就会因为无法进行初始化而不能创建对象。此外,如果自定义了构造函数,那么“系统”将不会默认为其添加构造函数。
3. 构造函数的重载
既然构造函数也是函数,那么它也就具备了一般函数的特点——重载。大家都知道,重载的特征是,函数名相同,而参数列表不同。由于,构造函数的名称与类名相同,因此,多个构造函数的名称必须是相同的。将前文代码稍微更改一下:
代码2:
Person
{
private String name;
private int age;
Person()
{
System.out.print(“空参数的构造函数:”);
System.out.println(“name =”+name+“, age= ”+age);
cry();
}
Person(StringnewName)
{
name = newName;
System.out.print(“带姓名参数的构造函数:”);
System.out.println(“name = ”+name+“, age=”+age);
cry();
}
Person(String newName, int newAge)
{
name = newName;
age = newAge;
System.out.println(“带姓名和年龄参数的构造函数:”);
System.out.println(“name = ”+name+“, age=”+age);
cry();
}
public void cry()
{
System.out.println(“Crying…”);
}
}
class PersomDemo
{
public static void main(String[] args)
{
Person p1 = new Person();
Person p2 = new Person(“张三”);
Person p3 = new Person(“李四”, 10);
}
}
运行结果:
空参数的构造函数:name = null, age = 0
Crying…
带姓名参数的构造函数:name = 张三, age = 0;
Crying…
带姓名和年龄参数的构造函数:name = 李四, age = 10
Crying…
对于上述Person类中的多个构造函数的作用,我们可以理解,当创建一个对象的时候,可能需要对其进行不同方式的初始化动作。注意:如果,没有自定义空参数的构造函数,并且又由于自定义了含参的构造函数而系统没有默认添加空参数的构造函数,此时,是不能通过无参构造函数创建对象的。
在这里可能会有朋友会有疑惑,既然cry方法可以随意调用,为什么一定要在构造函数中调用呢?这是因为,人一出生就会哭,在构造函数中调用cry方法是符合生活实际的,这也是一种初始化方式。那么就只在构造函数中定义一次哭的动作不就行了嘛?因为在人的一生可能还会哭很多次,因此要将这个动作单独封装成方法,以便复用。继续思考,既然已经在构造函数中进行过一次赋值动作,那么还有必要为成员变量定义set方法吗?答案是有必要的。联想一下生活实际,人的姓名是完全有可能被修改的,因此,应该对外提供该属性的set方法,不过最好还是要看具体情况而定。
4. 构造方法与一般方法在运行上的不同
通过上述描述与代码演示,我们可以总结如下:
1) 运行条件不同。构造方法只有随着对象的建立才能运行,而一般方法只有对象调用才能运行。
2) 运行次数不同。对于一个对象,构造方法只能运行一次,而一般方法可以反复被调用。
到此我们已经学习了,构造方法和普通方法的异同,那么既然构造方法也是类中的成员方法,那么就可以被private等访问权限修饰符修饰,考虑一个极端情况:如果一个类的所有构造方法全部被private修饰,那么就无法创建这个类的对象了,因为根本就无法为对象初始化。
5. 总结
那么说了这么多,到底应该什么时候定义构造函数呢?
当一个事物被创建时,就具备某些属性和行为时,就将这些属性和行为定义到构造函数中。此外,如果构造函数在定义时需要有未知内容参与运算,就定义参数列表,否则就不用定义。
二、初始化对象:构造代码块
代码3:
class Car
{
private int price;
//这部分叫做,构造代码块
{
System.out.println(“这是一辆车。”);
}
Car(intnewPrice)
{
price = newPrice;
System.out.println(“这辆车价值”+price+”万人民币。”);
}
public void start()
{
System.out.println(“发动引擎!”);
}
}
class CarDemo
{
public static void main(String[] args)
{
Car c1 = new Car(12);
c1.start();
Car c2 = new Car(6);
c2.start();
}
}
上述代码的运行结果为:
这是一辆车。
这辆车价值12万人民币。
发动引擎。
这是一辆车。
这辆车价值6万人民币。
发动引擎。
上面代码中注释部分代码称为构造代码块。它的作用是:给对象进行初始化。它的特点是:执行顺序优先于构造函数。
构造代码块和构造函数的区别:
1) 构造代码块为所有的对象进行初始化,也就是对象共性初始化内容;而构造函数是为对应的对象进行初始化。
2) 构造代码块的执行顺序先于构造函数。
3) 《Java编程思想》中提到:实际上构造代码块真正的用途是为匿名内部类提供初始化方式的。因为,匿名内部类没有类名,而构造代码块正是符合这个特点。关于匿名内部类的应用请参见后面的博客。