构造函数

构造函数分为:实例构造函数,静态构造函数,私有构造函数。

实例构造函数

1、构造函数的名字与类名相同。

2、使用 new 表达式创建类的对象或者结构(例如int)时,会调用其构造函数。并且通常初始化新对象的数据成员。

3、除非类是静态的,否则会为没有构造函数的类,自动生成一个默认构造函数,并使用默认值来初始化对象字段。

4、构造函数可以有参数,可以以多态的形式存在多个构造函数。

例:

class CoOrds
{
public int x, y;
// 实例构造函数(默认构造函数)
public CoOrds()
{
x = ;
y = ;
}
// 具有两个参数的构造函数
public CoOrds(int x, int y)
{
this.x = x;
this.y = y;
}
// 重写toString方法
public override string ToString()
{
return (String.Format("({0},{1})", x, y));
}
static void Main(string[] args)
{
CoOrds p1 = new CoOrds();
CoOrds p2 = new CoOrds(, ); // 使用重写ToString方法显示结果
Console.WriteLine("CoOrds #1 at {0}", p1);
Console.WriteLine("CoOrds #2 at {0}", p2);
Console.ReadKey();
}
} /* Output:
CoOrds #1 at (0,0)
CoOrds #2 at (5,3)
*/

其中CoOrds()是构造函数,诸如此类不带参数的构造函数称为“默认构造函数”。

CoOrds(int x, int y)同样也是构造函数,构造函数可以有参数,允许多态。

静态构造函数

静态构造函数具有以下属性:

  • 静态构造函数不使用访问修饰符或不具有参数。

  • 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数以初始化类。

  • 不能直接调用静态构造函数。

  • 用户无法控制在程序中执行静态构造函数的时间。

  • 静态构造函数的一种典型用法是在类使用日志文件且将构造函数用于将条目写入到此文件中时使用。

  • 静态构造函数对于创建非托管代码的包装类也非常有用,这种情况下构造函数可调用 LoadLibrary 方法。

  • 如果静态构造函数引发异常,运行时将不会再次调用该函数,并且类型在程序运行所在的应用程序域的生存期内将保持未初始化。

构造函数与静态构造函数:

class TestClass
{
public static int x = ;
//构造函数
TestClass()
{
x = ;
}
//静态构造函数
static TestClass()
{
//第二步,执行x = 2
x = ;
}
//第一步,程序入口Main最先执行。然后执行public static int x = 0 接着执行静态构造函数。
public static void Main(string[] args)
{
Console.WriteLine("x:{0}", x); //打印,x = 2
TestClass Test = new TestClass();//第三步执行构造函数,此时x = 1
Console.WriteLine("x:{0}", x); //打印 x = 1
Console.Read();
}
}

Main是程序入口,当执行Main的时候,最先执行public static int x = 0

接着执行静态构造函数,此时 x = 2

然后执行Main函数里面的内容,打印 x,此时 x = 2

初始化TestClass,然后会执行构造函数,此时 x = 1

打印 x = 1

那么,在调用某类的静态函数时真正的执行顺序:

1、静态变量 > 静态构造函数 > 静态函数

2、静态变量 > 静态构造函数 > 构造函数

C#高效编程改进C#代码的50个行之有效的办法(第2版)里说到这样一段话:
类型实例的完整过程。你需要理解这些操作的顺序,以及对象的默认初始化操作。你要保证在构造的过程中对每个成员变量仅初始化一次。实现这一点最好的方法就是,尽可能的早地进行初始化。
下面就是创建某个类型的第一个实例时,所进行的操作顺序为:
(1)静态变量设置为0
(2)执行静态变量初始化器
(3)执行基类的静态构造函数
(4)执行静态构造函数
(5)实例变量设置为0
(6)执行衯变量初始化器
(7)执行基类中合适的实例构造函数
(8)执行实例构造函数 
同样类型的第二个以及以后的实例将从第5步开始执行,因为类的构造器仅会执行一次。此外,第6步和第7步将被优化,以便构造函数初始化器使编译器移除重复的指令。

练习题:(core项目下,答案不同)

public class A
{
public static readonly int x;
static A()
{
x = B.y + ;
}
} public class B
{
public static int y = A.x + ;
public static void Main(string[] args)
{
Console.WriteLine("x:{0},y:{1}。", A.x, y);
Console.ReadLine();
}
}

下面公布答案:

public class A
{
public static readonly int x;
static A()
{
//第二步,调用B.y,此处B.y = 0,因为int类型在初始化阶段,会给赋默认值,默认值为0。最后x = 0 + 1(返回给第一步)
x = B.y + ;
}
} public class B
{
//第一步,调用A.x,然后执行类A的静态构造函数,等待返回(第二步返回的A.x = 1,所以y = 1 + 1)
public static int y = A.x + ;
public static void Main(string[] args)
{
//第三步,A.x = 1,y = 2。
Console.WriteLine("x:{0},y:{1}。", A.x, y);
Console.ReadLine();
}
}

练习题答案

详细解答:

1、首先,每一个项目有且只能有一个静态类的Main函数作为入口函数。而入口函数是最先执行的。

2、由于Main函数在B类里面,首先会初始化B类。而类的初始化顺序是:类里的静态变量,然后执行静态构造函数。

3、运行起先执行 public static int y = A.x + 1 这个,执行的时候,会先把 y 初始化为0,然后计算 y 的值。

4、计算 y 的值的时候,调用了 A 的静态变量 x 。所以会先初始化A。

5、初始化A时首先去执行 public static readonly int x ,先把 x 初始化为0。

6、然后执行A的静态构造函数 x = B.y + 1 此时 y 已经初始化为0了。

7、计算得到 x = 1。然后回到 public static int y = A.x + 1 得到 y = 2。

8、然后再执行Main函数的内容。得出结果x=1,y=2

补充: 小鹏Y 提出了 .net core 项目下得出的答案有出入。非常感谢他!以下是 .net core 项目的角度

在第二步计算 x = B.y + 1,B.y 的值是1,不是0。 所以在计算 x = B.y + 1 的时候,x = 2。

最后的结果变成:A.x = 2,y = 1

具体为何这样,还不清楚,此篇文章目前只考虑非 core 项目的情况。

私有构造函数

私有构造函数是一种特殊的实例构造函数。 它通常用于只包含静态成员的类中。 如果类具有一个或多个私有构造函数而没有公共构造函数,则其他类(除嵌套类外)无法创建该类的实例。

public class PrivateConstructor
{
private PrivateConstructor()
{
//PrivateTest a = new PrivateTest(); //注释打开会报错,错误信息:不可访问,因为它受保护级别限制。因为私有构造函数无法在类的外面实例化。
}
public class PrivateTest
{
int i;
private PrivateTest()
{
i = ;
}
static void Main(string[] args)
{
PrivateConstructor t = new PrivateConstructor(); //嵌套类允许实例化。
PrivateTest p = new PrivateTest(); //类的内部允许实例化。
Console.WriteLine("i:{0}", p.i); //结果:i:3
Console.Read();
}
}
}

声明空构造函数可阻止自动生成默认构造函数。 请注意,如果不对构造函数使用访问修饰符,则在默认情况下它仍为私有构造函数。 但是,通常会显式地使用 private 修饰符来清楚地表明该类不能被实例化。

实例:

其中单例模式就用到了私有构造函数的特性来保证类不会被实例化。C# 单例模式


相关文章: http://www.cnblogs.com/michaelxu/archive/2007/03/29/693401.html

https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/constructors

C# 构造函数总结的更多相关文章

  1. .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]

    构造函数.析构函数 构造函数: 语法: //无参的构造函数 [访问修饰符] 函数名() :函数名必须与类名相同. //有参的构造函数 [访问修饰符] 函数名(参数列表):函数名必须与类名相同. 作用: ...

  2. javascript工厂模式和构造函数模式创建对象

    一.工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程(本书后面还将讨论其他设计模式及其在JavaScript 中的实现).考虑到在ECMAScript 中无法创 ...

  3. JS继承之借用构造函数继承和组合继承

    根据少一点套路,多一点真诚这个原则,继续学习. 借用构造函数继承 在解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数(constructor stealing)的技术( ...

  4. PHP与JAVA构造函数的区别

    早期的PHP是没有面向对象功能的,但是随着PHP发展,从PHP4开始,也加入了面向对象.PHP的面向对象语法是从JAVA演化而来,很多地方类似,但是又发展出自己的特色.以构造函数来说,PHP4中与类同 ...

  5. C++ 拷贝构造函数和赋值运算符

    本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义 ...

  6. golang语言构造函数

    1.构造函数定义 构造函数 ,是一种特殊的方法.主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中.特别的一个类可以有多个构造函数 ,可根据其参数个 ...

  7. 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型

    前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...

  8. Aop动态生成代理类时支持带参数构造函数

    一.背景 在某些情况下,我们需要植入AOP代码的类并没有默认构造函数.那么此时动态生成的代理类也需要相同签名的构造函数,并且内部调用原始类的构造函数.自己折腾了1晚上没搞定,现在搞定了发出来供大家一起 ...

  9. C#的泛型的类型参数可以有带参数的构造函数的约束方式吗?

    Review后看到标题让我十分羞愧自己语文功底太差,估计...请见谅......我还特地把这句写回开头了...... 问题 前天遇到的一个问题,所以在MSDN发了个问,刚也丰富了下问题,关于泛型的. ...

  10. Android中自定义样式与View的构造函数中的第三个参数defStyle的意义

    零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第 ...

随机推荐

  1. jsp中EL表达式不起作用的问题1

    问题:在jsp页面中使用el表达式取值,取不到值,但是使用jsp中嵌套java代码可以取到值,对应代码如下: 解决: 只要在 jsp中 头文件中写上 : <%@page isELIgnored= ...

  2. 【java提高】---ArrayList源码

    ArrayList源码 一.定义 public class ArrayList<E> extends AbstractList<E> implements List<E& ...

  3. Java之路上,让我们Stand Up Again

    在开始之前,先发表一下个人想法吧. 在读书的时候每天忙的不可开交,也就没有了所谓的自由,突然参加工作,传统的朝八晚五,标准的八小时工作制,每天都是两点一线,工作中涉及商业机密,公司的东西也不能带回家, ...

  4. 【java】抓取页面内容,提取链接(此方法可以http get无需账号密码的请求)

    package 网络编程; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileOutpu ...

  5. Struts2学习---基本配置,action,动态方法调用,action接收参数

    首先我们先来直接配置,然后再来讲原理: 第一步:jar包的引入: 我们可以到struts2的官网上下载: http://struts.apache.org/download.cgi#struts251 ...

  6. 如何写一个SSH项目(一)程序设计大体思路

    SSH:分别是指Spring,Struts,Hibernate. 后来Struts2代替了Struts,所以我们常说的SSH是指Spring,Struts2,Hibenate. 其中Spring一般用 ...

  7. css弹性盒子新旧兼容

    前言:本篇随笔是对弹性盒子有了解的人来写的这篇文章,具体属性产生的效果这里不做说明,基础的东西去查文档.这里只是总结. 时至今日,css3的flex弹性盒子在移动端基本上都是支持的,但不排除有些些低版 ...

  8. deepin系统下安装git

    1.打开命令行 2.输入 sudo apt-get update sudo apt-get install git 3.显示 建议安装: git-daemon-run | git-daemon-sys ...

  9. centos 7 部署 open-falcon 0.2.0

    =============================================== 2017/12/06_第2次修改                       ccb_warlock 更 ...

  10. Mac_OS_Sierra_10.12.6编译OpenJDK9

    编译环境以及依赖 macOS:Sierra,10.12.6 处理器:2.6 GHz Intel Core i7 内存:16 GB 2133 MHz LPDDR3 Command Line Tools ...