什么是构造函数呢 ,函数

如题所述

构造函数 - 简介
构造函数 是一种特殊的方法 主要用来在创建对象时初始化对象 即为对象成员变量赋初始值
总与new运算符一起使用在创建对象的语句中 特别的一个类可以有多个构造函数 可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载
构造函数 - 构造函数与其他方法的区别
1.构造函数的命名必须和类名完全相同;而一般方法则不能和类名相同.
2.构造函数的功能主要用于在类的对象创建时定义初始化的状态.它没有返回值,也不能用void来修饰.这就保证了它不仅什么也不用自动返回,而且根本不能有任何选择.而其他方法都有返回值.即使是void返回值,尽管方法体本身不会自动返回什么,但仍然可以让它返回一些东西,而这些东西可能是不安全的.
3.构造函数不能被直接调用,必须通过new运算符在创建对象时才会自动调用,一般方法在程序执行到它的时候被调用.
4.当定义一个类的时候,通常情况下都会显示该类的构造函数,并在函数中指定初始化的工作也可省略,不过Java编译器会提供一个默认的构造函数.此默认构造函数是不带参数的.而一般方法不存在这一特点
5当一个类只定义了私有的构造函数,将无法通过new关键字来创建其对象,当一个类没有定义任何构造函数,C#编译器会为其自动生成一个默认的无参的构造函数。
构造函数 - C++中的构造函数

C++的构造函数定义格式为: 构造函数
class <类名>
{
public:
<类名>(参数表)
//...(还可以声明其它成员函数)
};
<类名>::<类名>(参数表)
{
//函数体
}
如以下定义是合法的:
class T
{
public:
T(int a=0){i=a;}//构造函数允许直接写在类定义内,也允许有参数表。
private:int i;
};
当程序中没有析构函数时,系统会自动生成以下构造函数:
<类名>::<类名>(){},即不执行任何操作。
构造函数 - C++例子
//注意若将本代码直接复制进编译器,可能会报错,原因是网页生成时会在代码前加一个中文占位符
//最好将代码再写一次
#include
using namespace std;
class time
{
public:
time() //constructor.构造函数
{
hour=0;
minute=0;
sec=0;
}
void set_time();
void show_time();
private:
int hour;
int minute;
int sec;
};
int main()
{
class time t1;
t1.show_time();
t1.set_time();
t1.show_time();
return 0;
}
void time::set_time()
{
cin >>hour;
cin >>minute;
cin >>sec;
}
void time::show_time()
{ cout<}
程序运行情况:
0:0:0
10 11 11 回车
10:11:11
任何时候,只要创建类或结构,就会调用它的构造函数。类或结构可能有多个接受不同参数的构造函数。构造函数使得程序员可设置默认值、限制实例化以及编写灵活且便于阅读的代码。
JAVA示例代码:
public class UserManagerImpl implements UserManager {
private UserDao userDao;
public UserManagerImpl(UserDao userDao){
this.userDao=userDao;
}
public void save(String username,String password){
this.userDao.save(username, password);
}
}
PHP中的构造函数
构造函数的声明与其它操作的声明一样,只是其名称必须是两个下划线__construct( )。这是PHP5中的变化;PHP4的版本中,构造函数的名称必须与类名相同。为了向下兼容,如果一个类中没有名为__construct( )的方法,PHP将搜索一个与类名相同的方法。
格式:function __construct ( [参数] ) { ... ... }
例子:
class person{
public $name;
public $age;
function _ _construct(){ // 构造函数
$this->name="lisi";
$this->age=28;
}
function say(){
echo "my name is ".$this->name."
";
echo "my age is ".$this->age."
";
}
}
$per=new person();
$per->say();
$per->name="zhangsan";
$per->age=26;
$per->say();
?>
C#例子
构造函数是在创建给定类型的对象时执行的类方法。构造函数具有与类相同的名称,它通常初始化新对象的数据成员。
在下面的示例中,使用一个简单的构造函数定义了名为 Taxi 的类。然后使用 new 运算符来实例化该类。在为新对象分配内存之后,new 运算符立即调用 Taxi 构造函数。
public class Taxi{ public bool isInitialized; public Taxi() { isInitialized = true; }}class TestTaxi{ static void Main() { Taxi t = new Taxi(); System.Console.WriteLine(t.isInitialized); }}
温馨提示:答案为网友推荐,仅供参考
第1个回答  2011-09-22
是构造方法,不是构造函数,后者是C++的概念

首先要注意的是Java的构造器并不是函数,所以他并不能被继承,这在我们extends的时候写子类的构造器时比较的常见,即使子类构造器参数和父类的完全一样,我们也要写super就是因为这个原因。
构造器的修饰符比较的有限,仅仅只有public private protected这三个,其他的例如任何修饰符都不能对其使用,也就是说构造器不允许被成名成抽象、同步、静态等等访问限制以外的形式。
因为构造器不是函数,所以它是没有返回值的,也不允许有返回值。但是这里要说明一下,构造器中允许存在return语句,但是return什么都不返回,如果你指定了返回值,虽然编译器不会报出任何错误,但是JVM会认为他是一个与构造器同名的函数罢了,这样就会出现一些莫名其妙的无法找到构造器的错误,这里是要加倍注意的。

在我们extends一个子类的时候经常会出现一些意想不到的问题,我在这里说一些和构造器有关的。
首先说一下Java在构造实例时的顺序(不讨论装载类的过程)
构造的粗略过程如下
1、分配对象空间,并将对象中成员初始化为0或者空,java不允许用户操纵一个不定值的对象。
2、执行属性值的显式初始化(这里有一点变化,一会解释,但大体是这样的)
3、执行构造器
4、将变量关联到堆中的对象上

介绍一下准备知识,以备一会来详细说明这个的流程
this() super()是你如果想用传入当前构造器中的参数或者构造器中的数据调用其他构造器或者控制父类构造器时使用的,在一个构造器中你只能使用this()或者super()之中的一个,而且调用的位置只能在构造器的第一行, 在子类中如果你希望调用父类的构造器来初始化父类的部分,那就用合适的参数来调用super(),如果你用没有参数的super()来调用父类的构造器(同时也没有使用this()来调用其他构造器),父类缺省的构造器会被调用,如果父类没有缺省的构造器,那编译器就会报一个错误,注意此处,我们经常在继承父类的时候构造器中并不写和父类有关的内容,此时如果父类没有缺省构造器,就会出现编译器添加的缺省构造器给你添麻烦的问题了哦。例如:Class b extends a}就没有任何有关父类构造器的信息,这时父类的缺省构造器就会被调用。

举个SL-275中的例子
1 public class Manager extends Employee {
2 private String department;
3
4 public Manager(String name, double salary, String dept)
{
5 super(name, salary);
6 department = dept;
7 }
8 public Manager(String n, String dept) {
9 super(name);
10 department = dept;
11 }
12 public Manager(String dept) { // 这里就没有super(),编译器会自动地添加一个空参数的缺省super构造器,此时如果Employee类中没有空参数的缺省构造器,那就会导致一个编译错误
13 department = d;
14 }
15 }

你必须在构造器的第一行放置super或者this构造器,否则编译器会自动地放一个空参数的super构造器的,其他的构造器也可以调用super或者this,调用成一个递归构造链,最后的结果是父类的构造器(可能有多级父类构造器)始终在子类的构造器之前执行,递归的调用父类构造器

在具体构造类实例的过程中,上边过程的第二步和第三步是有一些变化的,这里的顺序是这样的,分配了对象空间及对象成员初始化为默认值之后,构造器就递归的从继承树由根部向下调用,每个构造器的执行过程是这样的:
1、Bind构造器的参数
2、如果显式的调用了this,那就递归调用this构造器然后跳到步骤5
3、递归调用显式或者隐式的父类构造器,除了Object以外,因为它没有父类
4、执行显式的实例变量初始化(也就是上边的流程中的第二步,调用返回以后执行,这个步骤相当于在父构造器执行后隐含执行的,看样子像一个特殊处理)
5、执行构造器的其它部分

这里的步骤很重要哦!!!!!

从这个步骤中可以很明显的发现这个实例初始化时的递归调用过程,估计看过这个你应该能够理解这个递归构造链是怎么样回事了。

这里还是给出SL-275中的一个例子,让你充分理解一下这个递归的过程。

public class Object {
...
public Object() {}
...
}
public class Employee extends Object {
private String name;
private double salary = 15000.00;
private Date birthDate;
public Employee(String n, Date DoB) {
// implicit super();
name = n;
birthDate = DoB;
}
public Employee(String n) {
this(n, null);
}
}

public class Manager extends Employee {
private String department;
public Manager(String n, String d) {
super(n);
department = d;
}
}

在创建Manager("Joe Smith","Sales"):时,步骤如下
0 basic initialization
0.1 allocate memory for the complete Manager object
0.2 initialize all instance variables to their default values (0 or null)
1 call constructor: Manager("Joe Smith", "Sales")
1.1 bind constructor parameters: n="Joe Smith", d="Sales"
1.2 no explicit this() call
1.3 call super(n) for Employee(String)
1.3.1 bind constructor parameters: n="Joe Smith"
1.3.2 call this(n, null) for Employee(String, Date)
1.3.2.1 bind constructor parameters: n="Joe Smith", DoB=null
1.3.2.2 no explicit this() call
1.3.2.3 call super() for Object()
1.3.2.3.1 no binding necessary
1.3.2.3.2 no this() call
1.3.2.3.3 no super() call (Object is the root)
1.3.2.3.4 no explicit variable initialization for Object
1.3.2.3.5 no method body to call
1.3.2.4 initialize explicit Employee variables: salary=15000.00;注意:在父构造器返回后子类才会初始化实例变量的值。
1.3.2.5 execute body: name="Joe Smith"; date=null;
1.3.3 - 1.3.4 steps skipped
1.3.5 execute body: no body in Employee(String)
1.4 no explicit initializers for Manager
1.5 execute body: department="Sales"

这个流程就说明了一切,这个步骤是要注意的。一会还有些内容是要涉及到这里的。

写在后边的一些在使用构造器中的注意事项。

一、构造器中一定不要创建自身的实例,否则会造成调用栈溢出错误。这个规则也适用于对象的实例变量,如果对象中有自身的引用,这个引用一定不能在定义中或者构造器中初始化。

class a
{
a _a = new a();

public a()
{
_a = new a();
a _b = new a();
}
}

以上三种情况都会造成栈溢出,呵呵,这样会造成一个无穷递归的调用栈。

二、如果父类是一个抽象类,那通过调用父类的构造器,也可以将它初始化,并且初始化其中的数据。
三、如果你要在构造器中调用一个方法时,将该方法声明为private。
对于这个规则是需要一些说明的,假使你的父类构造器中要调用一个非静态方法,而这个方法不是private的又被子类所重载,这样在实际创建子类的过程中递归调用到了父类的构造器时,父类构造器对这个方法的调用就会由于多态而实际上调用了子类的方法,当这个子类方法需要用到子类中实例变量的时候,就会由于变量没有初始化而出现异常(至于为什么子类中的实例变量没有初始化可以参考上边的实例初始化过程),这是Java不想看到的情况。而当父类构造器中调用的方法是一个private方法时,多态就不会出现,也就不会出现父类构造器调用子类方法的情况,这样可以保证父类始终调用自己的方法,即使这个方法中调用了父类中的实例变量也不会出现变量未初始化的情况(变量初始化总是在当前类构造器主体执行之前进行)。
第2个回答  2012-06-02
C++语言为类提供的构造函数可自动完成对象的初始化任务,全局对象和静态对象的构造函数在main()函数执行之前就被调用,局部静态对象的构造函数是当程序第一次执行到相应语句时才被调用。然而给出一个外部对象的引用性声明时,并不调用相应的构造函数,因为这个外部对象只是引用在其他地方声明的对象,并没有真正地创建一个对象。   C++的构造函数定义格式为:   class <类名>   {   public:   <类名>(参数表)   //...(还可以声明其它成员函数)   };   <类名>::<函数名>(参数表)   {   //函数体   }   如以下定义是合法的:   class T   {   public:   T(int a=0){i=a;}//构造函数允许直接写在类定义内,也允许有参数表。   private:int i;   };   如果一个类中没有定义任何的构造函数,那么编译器只有在以下三种情况,才会提供默认的构造函数:   1、如果类有虚拟成员函数或者虚拟继承父类(即有虚拟基类)时;   2、如果类的基类有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数);   3、在类中的所有非静态的对象数据成员,它们对应的类中有构造函数(可以是用户定义的构造函数,或 编译器提供的默认构造函数)。   <类名>::<类名>(){},即不执行任何操作。
第3个回答  2011-09-24
构造函数的作用就是在对象被创建时利用特定的初始值构造对象,把对象置于某一个初始状态,它在对象被创建的时候由系统自动调用,我们只需要使用默认的构造函数或者自己定义构造函数,而不用管怎么调用的。
构造函数也是类的成员函数,除了有成员函数的所有特征外,还有一些不同之处:构造函数的函数名跟类名一样,而且没有返回值。构造函数一般被声明为公有函数,除非我们不允许某个类生成对象则将它声明为private或protected属性。编译器碰到对象声明语句时,会自动生成对构造函数的调用语句,所以我们常说构造函数是在对象声明时由系统自动调用的。
具体的讲解可以看下http://www.jizhuomi.com/software/51.html这个教程,很清楚
相似回答