zoukankan      html  css  js  c++  java
  • Chapter4 类型基础

    4.1 所有类型都是从System.Object派生

    CLR要求所有对象都用new操作符来创建
    Employee e=new Employee("ConstructorParam1");
    new操作符所做的事情:
    1.计算类型以及所有基类中定义的实例字段所需要的字节数
    2.在托管堆中分配指定类型要求的字节数,分配对象的内存
    3.它初始化对象的“类型对象指针”和“同步块索引”成员
    4.调用类型的实例构造器,编译器会在构造器中自动生成代码来调用一个基类构造器,每个类型的构造器负责初始化有这个类型定义的实例字段,最终调用System.Object的构造器
    new 执行了所有这些操作之后,会返回指向新建对象的一个引用,这个引用保存在变量e中

    4.2类型转换

    CLR允许一个对象转换为它的实际类型或者它的基类型。
    类型安全性测验:
    internal class B{} //基类
    internal class D:B{} //派生类
    表格:

    语句 编译成功和执行 编译时错误 运行时错误
    Object o1=new Object();    
    Object o2=new B();    
    Object o3=new D();    
    Object o4=o3;    
    B b1=new B();    
    B b2=new D();    
    D d1=new D();    
    B b3=new Object();    
    D d2=new Object();    
    B b4=d1;    
    D d3=b2;    
    D d4=(D)d1;    
    D d5=(D)b2;    
    D d6=(D)b1;    
    B b5=(B)o1;    
    B b6=(D)b2;    

    使用C#is和as操作符来转型
    is:检查一个对象是否兼容于指定的类型,并返回一个Boolean值,is永远不会抛出异常
    if(o is Employee){
    Employee e=(Employee)o;
    //if语句剩余的部分中使用e
    }
    as:如果兼容指定类型就返回一个指定类型非null的引用,不兼容,返回null
    Employee e=o as Employee;
    if(e!=null){
    //在if语句中使用e
    }
    一般情况as用的比较多,因为使用is会检查两次对象的类型,首先核实o是否兼容Employee,如果是执行if内语句在核实o是否引用一个Employee。性能没有as高。

    4.3命名空间和程序集

    C# using 指令
    潜在问题:可能有两个或多个类型在不同的命名空间中具有相同的名称
    例如:Microsoft下有个Widget的类型,Wintellect下也有个Widget的类型
    using Microsoft;
    using Wintellect;

    Widget w=new Widget(); //一个不明确的引用
    解决方案:
    //将WintellectWidget定义成Wintellect.Widget的别名
    using WintellectWidget=Wintellect.Widget;
    注意:命名空间和程序集(实现了一个类型的文件)不一定是相关的。特别是,同一个命名空间中的各个类型可能是在不同的程序集中实现的。
    例如System.IO.FileStream类型是在MSCorLib.dll程序集中实现的,而System.IO.FileSystemWatcher是在System.dll中实现的。

    4.4运行时相互联系

    1.类型、对象、线程栈和托管堆在运行时的相互关系
    线程栈:1个线程创建时,会分配一个1MB大小的栈,这个栈的空间用于向方法传递实参,并用于方法内部定义的局部变量。
    由于线程栈是从高位开始分配内存,先分配的我就画在上面了,在调用M1()方法时,分配内存的顺序是:name->s->M2的返回地址->length->tally;
    回收内存的顺序当然是反过来的。在一个方法中,应该包含一些序幕代码,进行一些初始化工作,还有一些尾声代码,等方法执行完成之后做一些回收工作。
    由于方法的返回地址先分配,在方法执行完成的时候回到返回地址,递归太深就容易出现栈溢出,因为参数、局部变量都必须等到方法返回的时候才能回收。
    2.调用静态方法、实例方法和虚方法的却别
    假设有2个类定义:

    internal class Person
    {
    private int height;
    //实例方法
    public void SetHeight(int height)
    {
    this.height = height;
    }
    //虚方法
    public virtual void Say(string word) { }
    //静态方法
    public static string Head()
    {
    return "my head";
    }
    public static int Age = 10;
    }
    internal class Student : Person
    {
    public override void Say(string word)
    {
    Console.WriteLine(word); ;
    }
    }
    现在马上就要调用Main入口方法:
    static void Main(string[] args)
    {
    Person student = new Student();
    student.Say("Hello cth");
    student.SetHeight(172);
    Person.Head();
    Console.ReadLine();
    }

    1.JIT将Main的IL代码转换成本地CPU指令,然后将内部引用的所有类型的程序集加载,然后创建数据结构来表示类型本身,如图所示

    2.当CLR确定方法需要的所有类型对象都以创建,开始允许线程执行Main的本地代码,然后Main执行它的代码来构造一个Student对象,这造成托管堆中创建了Student的一个实例
    略。。。。以后单独拿出一篇来介绍

  • 相关阅读:
    最小生成树——prim
    最短路径——floyd(多源最短路径)
    最短路径——Dijkstra(简易版)
    图的遍历——BFS(队列实现)
    图的遍历——DFS(邻接矩阵)
    图的创建——十字链表
    图的创建——邻接表法
    图的创建——邻接矩阵
    队列——链表实现
    队列——数组实现(循环队列)
  • 原文地址:https://www.cnblogs.com/hailiang2013/p/2856301.html
Copyright © 2011-2022 走看看