你的位置:首页 > ASP.net教程

[ASP.net教程]数往知来C#之接口 值类型与引用类型 静态非静态 异常处理 GC垃圾回收 值类型引用类型内存分配四


C# 基础接口篇

一、多态复习
使用个new来实现,使用virtual与override
   --》new隐藏父类方法 根据当前类型,电泳对应的方法(成员)
   --》override重写 无论什么情况,都是执行新的方法(成员)

继承是实现多态的一个前提,没有继承多态是不能实现的
父类与子类实现多态
抽象类与子类实现
抽象类不能实例化
抽象类中的抽象方法没有方法体

抽象类的成员有哪些
  -》包含非抽象成员
  -》不能实例化
  -》子类必须实现父类的 抽象方法,除非子类也是抽象类
抽象成员有哪些呢?(凡是与方法有关的都可以抽象)
方法、属性、索引、事件
自动属性与抽象属性
这个字段只需要实现读和写的功能不需要其他控制的时候就可以使用自动属性

二、接口
1)接口的关键字:interface 
2)接口的命名以I开头
3)成员符没有访问修饰符
4)没有方法实现体
5)接口里的成员必须是抽象的
6)接口定义能力即方法 派生类必须实现接口方法,除了抽象类
7)接口的存在就是为了实现多态
8)继承可以解决继承体积庞大的其问题,比如说有一个算法类里面有很多功能很齐全的计算方法,我现在要实现1+1=2的计算,此时如果调用这个功能齐全的类库来实现,那么无疑使大材小用了
也会产生很多的冗余代码,那么就可以考虑用接口来实现,接口的单一原则,接口实现的功能越少越好,一般一个接口实现一个功能,一般接口里面不要超过两个方法

接口可以实现多继承:
语法:
  

[public] [static] class 类名:[基类名,][[接口名,]接口名....]

接口比抽象类还抽象,接口是对功能的抽象

显示实现接口:
  -》为了避免接口的方法名相同
  -》显式实现接口必须由接口类型调用
显示实现接口的方法不能一public修饰,方法名以接口名.方法名
  

interface IInterface1  {    void Func();  }  interface IInterface2  {    void Func();  }  class MyTest : IInterface1, IInterface2  {    void IInterface1.Func()    {      Console.WriteLine("我是IInterface1提供的Func");    }    void IInterface2.Func()    {      Console.WriteLine("我是IInterface2提供的Func");    }  }

  

添加代码段

C# 值类型_引用类型篇

三、值类型、引用类型
值类型就“复制文件”
-》值类型来源于Vluar Type
引用类型就是“复制快捷方式”
->引用类型来源于object
使用ref与out都可以将参数传入方法,并保留在方法中对参数赋值时的影响
即参数在方法中被修改了,方法结束后,结果仍然保留方法中最后那一次被修改的值
ref reference 引用方法中用的是变量的引用,就是快捷方式
Out 参数用来输出,即在方法中对变量的修改就是要传到外边输出的
ref 在使用前要赋值
out 在方法中使用前要赋值

static void Main(string[] args){int num = 0;Func1(ref num);int num1;Func2(out num1);}static void Func1(ref int n){n = 10;}static void Func2(out int n){n = 10;}

C# 静态与非静态篇

wps5A12.tmp

三、静态与非静态
static修饰的成员就做静态成员
静态成员作用于整个应用程序
    -》在程序里那里都可以调用它

如何定义静态成员?
  -》加static修饰

静态成员与实例成员调用关系?
  -》静态方法、静态类中不要允许直接调用静态成员,如果要调用必须要new对象由对象来调用
如何调用静态成员?
  -》类名.成员名

静态成员属于整个类

实例成员属于对象

当某个类的成员都是静态成员不需要实例化的时候就可以把这个类定义成静态类,在程序中重复使用
static与abstract级别相同
   -》只能由其中一个修饰

与public和internal没有关系

静态类不允许继承
静态类里面不允许有实例成员

静态构造方法
  -》不允许带参数
  -》只允许由static修饰,没有public修饰等

静态构造方法从程序开始到结束只会被执行一次(一访问这个类就会第一个执行静态方法)

Dotnet基础_异常处理篇

四、异常的处理
  1)try-catch
  2)try-catch-finally
  3)tre-finally

try {   //可能出现异常的额代码 //打开数据库,操作数据等 //一旦出现异常,就从异常处停下来跳到catch中,tyr中其后的代码就不再执行了 } catch(Exception ex) {   //一旦出现异常,就执行这里的代码  //一般做日志等 } finally {  // 释放资源 }

 

异常向上抛,如果上面(调用者)没有(catch)抓住,那么就会再向上面抛,如果上面一直都没有抓住就会抛到系统去,系统就会检索这个异常,给出解决方案
如果系统解决不了就会抛给微软
不管抛异常或者return   finally始终都会被执行,(可以用if判断的错误尽量不要用try-catch)

C#_GC垃圾回收篇

三、GC   垃圾回收
垃圾回收总是从第0代开始回收
每次进行垃圾回收,前一代如果不使用了,就会被清掉,
如果,前一代中,某些对象仍然在使用中,就将其晋升为下一代。

如何自动的释放资源
   -》.net中对象有代的概念,每一个代是有内存范围的
   -》.net中的代有0、1、2三个等级
   -》2代的内存最大
   -》每次创建的对象默认为0代,当对象到达0代满了的时候会自动触动回收第0代
   -》“回收”实际上就是将需要继续使用的对象统一移动到另外一段连续的内存中
   -》所有的地址指向都会发生变化(这个移动有时叫做压缩)
   -》如此操作,当第一代满的时候就会调用回收第一代,并将需要使用的的对象放在第二代里
   -》如此操作,第二代满的时候,就会抛出一个overflow异常
当对象字节数大于85000,此时该对象将存储在大对象托管堆中
在进行垃圾回收的时候,不去考虑大对象区的数据(除非大对象区的数据小于85000)
   21250个int类型的对象==85000字节

      // 16个
            MyClass n1 = new MyClass();
            MyClass n2 = new MyClass();
            MyClass n3 = new MyClass();
            MyClass n4 = new MyClass();

            MyClass temp = n2;

            n2 = null;
            // 0x0012
            // 手动调用垃圾回收器
            System.GC.Collect(0);
            // 会根据你当前系统中内存使用情况进行优化
            n1 = null;
            System.GC.Collect(0);
            System.GC.Collect(1);
            Console.ReadKey();

wps5A42.tmp

C# 值类型引用类型内存分配篇

复习 值类型与引用类型
引用类型就是在处理地址
   --》快捷方式与文件的关系
   --》对象在内存中做了什么
32位的计算机用32个2进制位表示一个整数,同时使用32个二进制位来描述一个地址

1、内存空间的分配:分为3个空间
在栈空间中,系统是按高位到低位分配内存空间的(就是从大的数到小的数)
在堆空间中,系统是按低位到高位分配内存空间的(就是从小到大的数)

1)一个内存空间用来存放当前执行方法中的代码
     -》叫线程栈
     -》一个方法一个线程栈

程序在一开始执行就会去检索每个方法当中有哪些变量,并且为这些变量分配内存空间,相当于开辟好意见意见的空房间给这些房间编号(就是地址),
然后把内存里的数据清零(注意是清零相当于把里面的数据变成这样 0x0000,所以程序并没有执行到这个变量之前,光标放到这个变量上去会看到这个变量的值是 0,
但是此时的变量并不是赋值,并不可以用,因为这个0是内存空间里清除数据的0x0000,而不是赋值,等执行了等号之后才会真正地为这个变量赋值)

2)一个空间用来存放对象
       -》托管堆
对象就是一个变量的值,比如说 int num=10;  new person();   这个10和new person();就是对象。

3)存放静态对象,大对象(大于85000字节)等

2、值类型:
  

static void Main() {    int num=10; }

  

上面这段代码,程序执行到Main放法系统就会开辟一个线程栈,这个线程栈用来存放这个方法执行的代码,
程序一开始就会检索方法里面的所有变量,然后为int num开辟一个内存,系统会把这个内存里面的数据清除 0x0000,
并且给这个内存空间一个地址(相当于给这个内存空间编了个号)。

值类型的变量直接存在线程栈中,其中的值也存在线程栈中。数据在声明的时候系统就会根据声明的类型开辟相应大小的内存空间。
3、引用类型
    -》引用类型分为两个空间来存储,变量存储在线程栈中,对象存储在托管堆中

class Person() { } static void Main() {  Person p=new Person(); }


程序一开始在栈空间中开辟一个内存把里面的数据清零(0x0000),然后把这个p存到栈空间里去,当程序执行到main方法里面的时候会先执行new Person();(就是在new对象)
此时在就会在堆空间中开辟一个空间把数据清零,然后分配字段,,构造方法初始化,并产生一个地址,new对象时返回一个地址,这个地址指向了这个对象,然后执行等号赋值,此时赋值是把堆空间中这个对象产生的地址赋给变量p。此时变量P中存的是地址
我们处理的时候其实是对这个地址进行处理。
所以我们在传参的是时候是把变量中的值复制一份传过去,就是把这个地址复制了一份赋给方法中接收的变量,此时在方法中对这个变量是对地址的处理,所以会在外面保留影响

二、对象的创建(new对象的时候其实在内存里面做了很多事)
--》寻找类的继承关系,从上往下计算所有的字段的字节数
--》再把这个数加上8个字节(如果是64位操作系统加16) (这里8个字节方法栈4个指针占4个)
--》然后向操作系统申请空间
--》如果空间已满,返回一个overflow异常
--》如果空间够了就会返回该空间的首地址
--》根据计算出来的长度,会把这一片的内存空间清零
--》Nextobjptr会在原来的地址位置加上刚刚计算出来的数据,得到下一个对象的首地址
--》调用构造方法

多个对象在内存中时连续存储的

wps5A62.tmp

wps5A73.tmp

wps5A83.tmp

wps5AA4.tmp

wps5AA5.tmp