构造函数 ;构造函数的执行顺序。静态字段的初始化顺序。new关键字为我们做了什么。

时间:2021-02-25 03:54:23

<1>

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

非静态类中可以有静态方法,但是静态类中只能是静态方法,不能有非静态方法。

实例构造函数:使用 new 表达式创建某个的对象时,会使用实例构造函数创建和初始化所有实例成员变量。或用于执行仅需执行一次的特定操作。 所以它的实际作用就是初始化对象的成员变量。

静态构造函数:静态构造函数用于初始化任何静态数据,或用于执行仅需执行一次的特定操作。如果一个类存在静态成员,那么在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。所以静态构造函数的作用和实例构造函数的作用差不多,即用户初始化静态成员变量。


1>当申明一个静态变量,同时又给它赋值的时候。这个赋值将会在静态类的构造函数前先被执行。等这个赋值完毕后在执行构造函数。

using System;
using System.Text;

namespace 静态构造函数的执行顺序
{
    class Employee
    {
        static Employee() //声明NextId并给它赋了初值42后,会跳到静态构造函数这里来。接着又是给NextId赋了一个随机数的值
        {
            NextId = 50;
        }

        public static int NextId = 42; //当申明一个静态变量,同时又给它赋值的时候。这个赋值将会在静态类的构造函数前先被执行。所有此时的NexId的值为42  等这个赋值完毕后在执行构造函数。

    }


    class Test
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Employee.NextId); //这里输出:50
            
            Console.ReadKey();
        }

    }
}


下面是构造函数的作用(初始化对象的成员变量),及构造函数的参数传递,及构造函数的重载。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test2
{
    public class Student
    {
        public Student()
        { 
        
        }
        //这里接收new Student("黄雪辉", 24, '女', "广东省广州市天河区") 传递过来的值,对对象的属性或者字段进行初始化
        public Student(string name, int age, char gender, string address) 
        {
            this.Name = name; //初始化Name属性           //注意:this 代表当前类的对象。注意是“对象”
            this.Age = age; //初始化Age属性
            this.Gender = gender; //初始化Gender字段
            this.Address = address; //初始化Address字段
        }
        public string Name { get; set; }

        public int Age { get; set; }

        public char Gender;

        public string Address { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //Student s = new Student();//在我们创建对象的时候,即new Student();的时候 ,会首先跳到 public Student(){}这个构造函数这里来,执行完构造函数后在执行我们下面的对象属性的初始化。 即:创建对象的时候一定会最先执行构造函数。既然这样,那我们就可以把对象的初始化代码放到构造函数中去(对象初始化:即将对象类的非静态的属性,或者字段赋初值)
            //s.Name = "黄雪辉";
            //s.Age = 24;
            //s.Gender = '女';
            //s.Address = "广东省广州市天河区";

            Student s = new Student("黄雪辉", 24, '女', "广东省广州市天河区");//既然要在构造函数中初始化对象,那么我们就要将对象要初始化的值传递到构造函数中。【当我们把鼠标移动到new Student()这里的时候,我们会发现这个Student后面的括号其实就是执行构造函数】这样就把我们要初始化对象的值传递到了构造函数中。

        }
    }
}


new 关键字的作用。创建一个对象的时候,new关键字帮我们做了什么事情?

using System;
using System.Text;

namespace New关键字
{
    public class Person
    { 
        
    }
    class Program
    {
        static void Main(string[] args)
        {
            //创建对象的时候会执行构造函数。

            Person p = new Person(); //这里创建了一个对象。

            //创建对象用new关键字。那么这个new到底为我们做了什么呢? 有以下3步
            // 1,在内存中开辟一块空间。
            // 2, 在开辟的空中中创建对象。
            // 3,调用对象的构造函数进行初始化对象。

            //这3步,如果有一步完不成,你这个对象就创建不出来。所以构造函数的访问修饰符必须是public 。如果构造函数的访问修饰符是private的话,出了Person类。在外面new Person()就无法调用构造函数。无法调用构造函数就无法创建对象了。
        }
    }
}


=================================================================================================

下面是构造函数的定义。及实例


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 构造函数
{
    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Person() //这儿是默认的构造函数,可以不写。构造函数也可以构成重载,一下两个函数就是重载的构造函数。构造函数没有返回值,连void都不能写,构造函数名与类名一致。构造函数就是在创建对象的同时,给它初始化 即:它通常初始化新对象的数据成员 这就是构造函数的意义。
        {
            Name = "未命名";
            Age = 0;
        }

        public Person(string name, int age) //两个参数的重载构造函数
        {
            Name = name;
            Age = age;
        }

        public Person(int age) //一个参数的重载构造函数
        {
            Age=age;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            Person p2 = new Person("小米", 20);
            Person p3 = new Person(30);

            Console.WriteLine("姓名是{0},年龄是{1}", p1.Name, p1.Age); //输出姓名是未命名,年龄是0

            Console.WriteLine("姓名是{0},年龄是{1}", p2.Name, p2.Age);  //输出姓名是小米,年龄是20

            Console.WriteLine("姓名是{0},年龄是{1}", p3.Name, p3.Age);   //输出姓名是,年龄是30

            Console.ReadKey();
        }
    }
}


<2>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Class1
    {

        private static int count = 0; //在整个类加载完成之后,就初始化静态(静态变量,静态块), 一个类中只要有静态变量,就会先初始化静态变量,这时候就会调用static Class1()静态构造函数,
        private int ni;
        private static int count2 = 2;
        static Class1()
        {
            count++; //0自增后为1 这时候count=1
            count2++;
        }
        public Class1()
        {
            count++;
        }


        static void Main(string[] args)
        {
            Class1 o1 = new Class1(); //这时候创建了一个o1对象,然后调用public Class1()构造函数 count再自增一次,变为2
            Class1 o2 = new Class1();//接着这时候有创建了一个o2对象。然后再次调用public Class1()构造函数。count再次自增一次,变为3
            Console.WriteLine(count); //输出3
            Console.ReadKey();
        }


    }
}


<3>

 ================================下面有两道题目。我没对比看看

A


//编译器在编译的时候,会事先分析所需要的静态字段,如果这些静态字段所在的类有静态的构造函数,则忽略字段的初始化,否则先进行静态字段的初始化。对类的静态成员初始化的顺序取决于在Main函数中的引用顺序,先引用到的先进行初始化,但如果类的静态成员的初始化依赖于其它类的静态成员,则会先初始化被依赖类的静态成员。而带有静态构造函数的类的静态字段,只有在引用到的时候才进行初始化。


using System;
using System.Text;

namespace Test
{
    public class A
    {
		
        public static int X; //int 的默认值就是0 所有X在没有调用静态构造函数static A(){}构造函数前默认值就是0
        static A() //一个类既如果存在静态字段,那么就一定会调用静态类的静态构造函数。那么现在开始进入静态构造函数 A() ;A()函数中引用了B类中的静态字段Y。那么现在有跳到了B.Y
        {
            X = B.Y + 1; //因为这里引用了B类中的静态Y字段。经过Y这个静态字段初始化完毕后,得知Y的值为1 所有此时X=1+1; 所以经过构造函数A()的执行完毕后。X此时的值已经为2了。
        }
    }


    public class B
    {
		
        public static int Y = A.X+1; //注意A类的static构造函数还没有执行完的时候就跳到这里来了。A.X的值此时依然为0  Y=0+1 即 Y这个静态函数没有调用静态构函数B(){}的时候,Y的值已经为1了。
        static B()// 一个类中如果存在静态字段,那么就一定会调用静态构造函数,声明静态变量Y后,并给Y赋l了A.X+1这个值后,那么现在就进入静态构造函数B()中;B()函数中什么代码也没有。所有此时的Y的值依然为1 。静态字段Y初始化完毕后(及静态构造函数执行完毕后)。又跳到了A类的 静态构造函数A()中了。
        { 
        
        }
       
    }


    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine("X={0},Y={1}", A.X, B.Y); //所以这里输出 X=2,Y=1
            Console.ReadLine();

        }
    }
}




B 注意。B类中是没有静态构造函数的哦。因为B类没有静态构造函数,所有它最新进行静态字段的初始化




using System;
using System.Text;

namespace Test
{
    public class A
    {
        public static int X; //int 的默认值就是0 所有X在没有调用静态构造函数static A(){}构造函数钱默认值就是0
        static A() 
        {
            X = B.Y + 1; 
        }
    }

    //编译器在编译的时候,会事先分析所需要的静态字段,如果这些静态字段所在的类有静态的构造函数,则忽略字段的初始化,否则先进行静态字段的初始化。对类的静态成员初始化的顺序取决于在Main函数中的引用顺序,先引用到的先进行初始化,但如果类的静态成员的初始化依赖于其它类的静态成员,则会先初始化被依赖类的静态成员。而带有静态构造函数的类的静态字段,只有在引用到的时候才进行初始化。
    public class B
    {
        public static int Y = A.X + 1;  //因为B类中没有静态构造函数,所以先进行静态字段的初始化。我们知道,int的默认值为0 所以Y没有完成初始化前,Y的值是0; 这里给Y初始化的时候引用了A类中的静字段X ,既然引用了A类中的静态字段X ,我们知道一个类中有静态字段,静态字段是最先被初始化的。所有既然要初始化X就会调用A类的静态构造函数A() X=B.Y+1 因为B.Y没有被初始化前的默认值是0 所以X=0+1; 即 X=1 。等X初始化完毕后。我们在来完成初始化B.Y  因为Y=A.X+1 现在A.X初始化完毕了。得知A.X=1 那么Y=A.X+1即Y=1+1 所有Y=2了
        public B()
        { 
        
        }
       
    }


    class Program
    {
        static void Main(string[] args)
        {

            Console.WriteLine("X={0},Y={1}", A.X, B.Y); //所以这里输出 X=1,Y=2
            Console.ReadLine();

        }
    }
}