欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

程序员文章站 2022-04-01 13:17:35
一. 静态和非静态 1. 概念介绍 ① 静态类(被static修饰) vs 普通类(没有被static修饰) ② 静态成员:被static修饰的成员,比如:静态方法、静态字段等 ③ 普通成员(实例成员):不被static修饰的成员,比如:普通方法、普通字段 2. 运行机制 ① 静态成员在程序运行的时 ......

一. 静态和非静态

1. 概念介绍

  ① 静态类(被static修饰) vs  普通类(没有被static修饰)

  ② 静态成员:被static修饰的成员,比如:静态方法、静态字段等

  ③ 普通成员(实例成员):不被static修饰的成员,比如:普通方法、普通字段

2. 运行机制

  ① 静态成员在程序运行的时候会“先于”实例成员被加载到内存中,静态成员不需要单独创建,当然静态类也不能被实例化。

  比如:静态字段和静态构造函数只有在程序第一次使用该类之前被调用,而且只能调用一次,利用该特性,可以设计单例模式。

补充单例模式的代码:

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)
 1 public class STwo
 2     {
 3         /// <summary>
 4         /// 模拟耗时的构造函数
 5         /// </summary>
 6         private STwo()
 7         {
 8             long result = 0;
 9             for (int i = 0; i < 1000000; i++)
10             {
11                 result += i;
12             }
13             Thread.Sleep(1000);
14             Console.WriteLine("{0}被构造...", this.GetType().Name);
15         }
16 
17         private static STwo _STwo = null;
18         /// <summary>
19         /// 静态的构造函数:只能有一个,且是无参数的
20         /// 由CLR保证,只有在程序第一次使用该类之前被调用,而且只能调用一次
21         /// </summary>
22         static STwo()
23         {
24             _STwo = new STwo();
25         }
26 
27         public static STwo CreateIntance()
28         {
29             return _STwo;
30         }
31     }
View Code
第十七节:易混淆的概念(静态和非静态、拆箱和装箱)
 1 public  class SThird
 2     {
 3         /// <summary>
 4         /// 模拟耗时的构造函数
 5         /// </summary>
 6         private SThird()
 7         {
 8             long result = 0;
 9             for (int i = 0; i < 1000000; i++)
10             {
11                 result += i;
12             }
13             Thread.Sleep(1000);
14             Console.WriteLine("{0}被构造...", this.GetType().Name);
15         }
16         /// <summary>
17         /// 静态变量:由CLR保证,在程序第一次使用该类之前被调用,而且只调用一次
18         /// </summary>
19         private static SThird _SThird = new SThird();
20 
21         public static SThird CreateIntance()
22         {
23             return _SThird;
24         }
25     }
View Code

  ② 实例成员:只有创建了对象(即进行了类的实例化)才会存在于内存中。

  证明:在StaticInstroduceDemo类中的静态变量a上加断点(方法体内部加断点,两次实例化类的时候加断点),然后在客户端实例化两次 StaticInstroduceDemo类,分别调用ShowStaticInstroduce方法,

  发现:第一次实例化的时候进入静态变量a上的断点,然后在调用对应的方法,而第二次实例化的时候不再进入静态变量a上的断点,直接进入调用的方法。从而验证了:静态成员优先于实例成员进入内存,且只在第一次使用该类的时候进行初始化分配内存,后续将不在分配.

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

3. 基于以上运行机制可以得出以下几个结论

① 普通类:

  a. 普通类中可以存在静态成员(静态方法、静态字段),但里面的静态方法不能调用普通类中的普通字段<普通类没有实例化的话,普通字段是不存在的>。

  b. 普通类中普通方法可以调用里面的静态字段<静态成员先于实例成员加载到内存中>

eg:

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

② 静态类:

静态类中只能存在静态成员(静态方法和静态字段)

4. 调用形式

  ① 静态成员: 类名.静态成员名

  ② 实例成员: 实例名.实例成员名

5. 声明周期

  ① 对于C/S程序:每启动一次,相当于一次生命周期,关闭程序生命周期结束,多次打开客户端程序互不干扰。 

验证:上述的ShowStaticInstroduce方法,两次实例化后调用输出的结果是2,3 。此时我再打开一个客户端,结果依旧是2,3,这也很好证明了声明周期的问题。

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

  ② 对于B/S程序:static修饰的成员存储在服务器端中,与客户端关闭与否无关。《详见HomeController下的TestStatic方法》

验证:打开不同浏览器,分别调用TestStatic1方法,发现每点击一次按钮,返回值增加1,关闭该浏览器,重新点击,返回值在原基础上加1. 关闭IIS重新运行,返回值重新计数。证明:在B/S模式下,static修饰的成员存储在服务器端内存中,与客户端关闭与否无关。

 第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

第十七节:易混淆的概念(静态和非静态、拆箱和装箱) 

6. 使用场景

  ① 对于C/S程序:static修饰的变量可以当作缓存来使用。

  ② 对于B/S程序:可以利用static的特性来设计单例模式,或者面向多线程存储数据,进行资源的共享<PS: 不考虑性能方面问题和一些极端情况>。

  ③ 作为工具类,全局资源共享。

二. 拆箱和装箱

1. 补充两个概念:

  值类型:int、double、char、bool、decimal、struct、enum

  引用类型:各种class类、string、数组、接口、委托、object

2. 装箱:

  将值类型→引用类型

3. 拆箱:

  将引用类型→值类型

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

4. 经典面试题

请问下面代码涉及到几次拆箱和装箱。

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

分析:

  ① 第一次装箱发生在 object m2 = m1;

  ② 第一次拆箱发生在 (int)m2 上;

  所以很多人认为答案是:1次装箱和1次拆箱,显然是不对的。

    我们继续分析,熟悉 Console.WriteLine原理的知道内部调用string.Concat()方法进行拼接,而Contact有很多重载,F12看源码可知,

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

    该案例只能使用 public static String Concat(object arg0, object arg1); 这个重载,

    所以第2次装箱和第3次装箱发生在 m1→object 和(int)m2→object上。

  所以最终答案是 1次拆箱和3次装箱

5.  特别注意:用什么类型进行装箱的,拆箱就拆成什么类型,否则会抛异常,无法进行类型转换。

 

 

 PS:如果你对.Net其他知识感兴趣,可以参考         

       

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 :
  • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,如需代码请留下你的评论,加我QQ:604649488 (备注:评论的博客名)