zoukankan      html  css  js  c++  java
  • 《.NET程序员面试秘籍》读书笔记

    1. 简述 private、 protected、 public、 internal 修饰符的访问权限。

         private :设置类或类的成员为私有,在类的内部才可以访问。有时要访问私有成员时,可通过get和set属性访问器读取或者修改。

         protected :保护成员,该类内部和继承类(子类)中可以访问。(即使子类和基类不在同一个程序集中)

         public : 公共成员,完全公开,没有访问限制。须谨慎使用,滥用会影响类的封装性。 

         internal:  在同一命名空间(程序集)内可以访问。C#默认的类访问修饰符即为internal。(默认的修饰符,可缺省,最常用)

    2. 描述sealed修饰符的作用

      用于修饰类、实例方法和属性。sealed修饰类时,该类无法被继承,所以该类也被称为密封类。而abstract类(抽象类)必须被继承才有意义,所以二者是相互排斥,无法共用的。密封方法会重写基类的方法,sealed用于修饰实例被重写的虚方法或虚属性时,表示该方法或属性无法再被重写。

    3、举例说明简单工厂模式的作用

           在软件系统中,经常面临“一系列相互依赖对象”的创建工作,为了绕过常规对象的创建方式(即用new创建),利用工厂模式,提供一种“封装机制”来减少功能调用程序和“多系列具体对象创建工作”的耦合性。



             简单工厂模式,在工厂类中封装创建对象的实现部分。在应用接口的程序中广泛应用。如下例:

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
      
    namespace BaseFactory  
    {  
        //声明一个图书接口  
        interface IBook  
        {  
            //声明未实现的图书类型方法bookType()  
            void bookType();  
        }  
        //实现图书接口的A类图书  
        class BookA : IBook  
        {  
            public void bookType()  
            {  
                Console.WriteLine("A类书籍");  
            }  
        }  
        //实现图书接口的B类图书  
        class BookB : IBook  
        {  
            public void bookType()  
            {  
                Console.WriteLine("B类书籍");  
            }  
        }  
        //实例化各类图书对象的工厂  
        class PublishFactory  
        {  
            private IBook bka = new BookA();  //封装创建对象的实部分
            private IBook bkb = new BookB();  
            public IBook getBook(int i)  
            {  
                switch (i)  
                {  
                    case 1:  
                        return bka;  
                    case 2:  
                        return bkb;  
                    default:  
                        return bka;  
                }  
            }  
        }  
        public class BasicFactory  
        {  
            static void Main(string[] args)  
            {  
                PublishFactory pf = new PublishFactory();  
                Console.Write("请输入编号(1或2):");  
                int i = int.Parse(Console.ReadLine());  
                //根据输入的不同参数获得不同的图书对象  
                IBook obj = pf.getBook(i);  
                obj.bookType();  
            }  
        }  
      
    }  
    


    接口反映了面向对象编程的一个特性,即多态,多态即通过相同的方法得到不同的实现。如上面的h1.getFav()和h2.getFav();

    接口反映了面向对象编程的另个特性,即封装,使用者可以不清楚接口成员实现的细节。

    解释: 接口类型obj可以引用不同类的实例,以致相同的bookType方法有不同的表现;使用者只知道传递数字来使用不同接口的不同功能,对内部实现一无所知。实现了更好的封装。

    (此例已经够说明了)

    运行结果:

            为了处理更复杂的情况,可以将产品再次细分为多个类,用抽象类进行归纳,完成同类产品中共用代码的复用,工厂类也相应地分为多个类,用抽象类进行归纳。如下例:

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
      
    namespace LxFactory  
    {  
        //声明一个人类接口  
        interface Ihuman  
        {  
            void getFav();        //声明未实现的爱好方法getFav()  
            string getStatus();   //声明未实现的身份状态(孩子,成年人)方法  
        }  
      
        //声明一个抽象类Children,并实现接口的部分方法  
        abstract class Children : Ihuman  
        {  
            protected string _status = "孩子";  
            //实现接口Ihuman中的getStatus()方法  
            public string getStatus()  
            {  
                return _status;  
            }  
            //将接口Ihuman中的getFav()方法映射到抽象方法  
            abstract public void getFav();  
        }  
        //声明一个抽象类Adult,并实现接口的部分方法  
        abstract class Adult : Ihuman  
        {  
            protected string _status = "成年人";  
            //实现接口Ihuman中的getStatus()方法  
            public string getStatus()  
            {  
                return _status;  
            }  
            //将接口Ihuman中的getFav()方法映射到抽象方法  
            abstract public void getFav();  
        }  
      
        //声明男孩类Boy,继承小孩类Children,重写爱好方法getFav()  
        class Boy : Children  
        {  
            public override void getFav()  
            {  
                Console.WriteLine("男孩,我喜欢游戏!");  
            }  
        }  
        //声明女孩类Girl,继承小孩类Children,重写爱好方法getFav()  
        class Girl : Children  
        {  
            public override void getFav()  
            {  
                Console.WriteLine("女孩,我喜欢布娃娃!");  
            }  
        }  
        //声明男人类Man,继承成人类Adult,重写爱好方法getFav()  
        class Man : Adult  
        {  
            public override void getFav()  
            {  
                Console.WriteLine("男人,我喜欢编程!");  
            }  
        }  
        //声明女人类Woman,继承成人类Adult,重写爱好方法getFav()  
        class Woman : Adult  
        {  
            public override void getFav()  
            {  
                Console.WriteLine("女人,我喜欢逛街!");  
            }  
        }  
    
        //声明一个抽象工厂,分别创建相应类的实例  
        abstract class HumanFactory  
        {  
            protected Ihuman h1 = new Boy();  
            protected Ihuman h2 = new Man();  
            protected Ihuman h3 = new Girl();  
            protected Ihuman h4 = new Woman();  
    
            //创建一个方法,根据不同输入返回一个接口的引用  
            abstract public Ihuman getHuman(int i);  
        }  
        //声明可以实例化各种类的工厂Factory1,继承类HumanFactory,重写抽象方法getHuman()  
        class Factory1 : HumanFactory  
        {  
            //根据不同输入获得不同对象所属接口的引用  
            public override Ihuman getHuman(int i)  
            {  
                switch (i)  
                {  
                    case 1:  
                        return h1;  
                    case 2:  
                        return h2;  
                    default:  
                        return h1;  
                }  
            }  
        }  
        //声明可以实例化各种类的工厂Factory1,继承类HumanFactory,重写抽象方法getHuman()  
        class Factory2 : HumanFactory  
        {  
            //根据不同输入获得不同对象所属接口的引用  
            public override Ihuman getHuman(int i)  
            {  
                switch (i)  
                {  
                    case 1:  
                        return h3;  
                    case 2:  
                        return h4;  
                    default:  
                        return h3;  
                }  
            }  
        }  
        public class LxFactory  
        {  
            static void Main(string[] args)  
            {  
                //使用工厂1  
                Console.WriteLine("男性中有两种人,请选择编号【1】男孩【2】男人:");  
                int input1 = Int32.Parse(Console.ReadLine());  
                Factory1 f1 = new Factory1();  
                Ihuman h1 = f1.getHuman(input1);  
                h1.getFav();  
                Console.WriteLine("我的身份是:{0}", h1.getStatus());  
      
                //使用工厂2  
                Console.WriteLine("女性中有两种人,请选择编号【1】女孩【2】女人:");  
                int input2 = Int32.Parse(Console.ReadLine());  
                Factory2 f2 = new Factory2();  
                Ihuman h2 = f2.getHuman(input2);  
                h2.getFav();  
                Console.WriteLine("我的身份是:{0}", h2.getStatus());  
            }  
        }  
      
    }  
    

    运行结果:

     

    4、访问关键字this和base有什么作用

    this用于引用类的当前实例(this仅限于构造函数和方法成员中使用,静态成员与实例无关,所以静态成员中不能用this)

    base用于派生类访问基类成员(基类被重写的方法和基类的构造函数)

    5、简述程序集和应用程序域

     

    程序集

    一个.NET应用程序可以由多个程序集拼装而成的。程序集,简单来说,就是一个以公共语言运行库(CLR)为宿主的、版本化的、自描述的二进制文件。尽管显示中.NET程序集和以往Win32二进制文件(包括遗留的COM服务对象)的文件扩展名(*.exe或*.dll)完全相同,但是两者的内部构成几乎完全不同。

    程序集可以促进代码重用、确定类型边界、可版本化的单元、自描述的、可配置的。

    n CIL代码

    程序集的核心部分包含CIL代码,这些CIL代码是独立于平台和CPU的中间语言。运行时,程序集内部的CIL代码才被编译成特定平台和CPU的指令。

     

    n 类型元数据

    元数据完整的描述了程序集内含另行和引用外部类型的格式。

     

    n 程序集清单

    详细记录了程序集中的每一个模块,构建程序集的版本以及该程序集引用的所有外部程序集。

     

    n 可选的嵌入资源

     

          NET平台下,程序集并没有直接加载进进程中(传统的Win32程序是直接承载的)。.NET可执行程序(程序集)承载在进程的一个逻辑分区中,术语称应用程序域(简称AppDomain)。一个进程可以拥有多个应用程序域,应用程序域的全部目的就是提供隔离性,相比较与传统的:(代码, AppDomain.currentDomain)

    1.应用程序域是.NET平台操作系统独立性的关键特性。这种逻辑分区将不同操作系统表现加载可执行程序的差异抽象化了。

    2.和一个完整的进程相比,应用程序域的CPU和内存占用要小的多。

    3.应用程序域为承载的应用程序提供了深度的隔离。一个失败,其他不会失败。

     

    单个进程可以承载多个应用程序域,每个程序域都和该进程的其他程序域隔离开来,无法相互访问。在线程启动的时候,CLR将自动创建这个特定的应用程序域(默认应用程序域)。然后根据需要创建其他程序域。

     
     

     

    两边都有mscorlib.dll(程序集),因为所有关键程序集会被CLR自动加载到每一个应用程序域中。

    6、简述结构和类的区别

     

      答:(1)结构是值类型(传递的是数据的副本),类是引用类型。所以结构的实例化可以不用new运算符。

    (值类型变量一旦超出作用域即被销毁,而应用类型由内存垃圾处理机制完成收集)

    (2)结构不能声明无参数的构造函数(默认构造函数)和析构函数。类可以同时有构造函数和析构函数。

    (3)结构不支持继承,也无法派生其他的结构或类,(但结构可以实现接口)。而类支持继承。

    7、C#函数的参数 修饰符(out、params、ref)的作用

    (1)无修饰符,表示按值传递

    (2)out修饰,eg. 函数 static void equal(out int a,out int b,out int c)

    { a=2; b=a*100; c=b*100; Console.WriteLine("a、b、c的值分别为:{0}、{1}、{2}",a,b,c);}

         表示按引用 传递参数,实际参数(调用的函数里的参数)传递前不需要赋初值,函数(定义的函数)必须将其赋值。也可以看出out能用于一次调用返回多个值

    (3)params修饰,表示形式参数 可以为不确定个数的一组实际参数,这些实际参数必须具有相同的数据类型。

       void text(params string[] txt){}

    (4)ref修饰,类似out参数。也表示按引用 传递参数,不过实际参数传递前需要赋初值。


    8、如何使用C#的对象构造器

      这是一种新的构造并初始化对象的方法,使用时只需将初始化成员的语句用逗号分隔,位置紧跟在构造函数后面。

     eg. Snake a=new Snake("眼镜蛇"){nm="蟒蛇",Len=10,Wei=20 };

      后面大括号就是对象构造器。。列出了 对象a 的初始化值。  这种方式非常灵活的初始化对象成员,无需定义过多的重载构造函数。


    9、如何判断类型实现了某个接口  (as/is关键词)

    ClassA a=new ClassA();  

    var msg=a as ITest;    

     class  ClassA:ITest{ 类体}

    if(msg==null)

    {"未实现"}

     else {"实现了"}

    或者用 a is ITest


    10、数组列表和数组有什么区别

    非常相似,但是数组列表(即ArrayList类, 位于System.Collection下)的容量可以动态变化;有点类似StringBuilder类。。

    ArrayList.Add(); ArrayList.Insert(); ArrayList.AddRange();-----

      数组(即Array类,位于System下,)在初始化时要指定容量,并且指定后无法更改。



  • 相关阅读:
    [原创]敏捷管理实践看板思维导图
    [原创]敏捷管理实践Scrum思维导图
    [原创]App弱网测试方法介绍
    [原创]SpotLight性能监控工具使用介绍
    [原创]换一份工作要考虑什么?
    [原创]互联网公司App测试流程
    [原创]浅谈大型互联网架构发展
    [原创]Jmeter工具学习思维导图
    [联想] 联想管理三要素:1 建班子 2 定战略 3带队伍
    [原创]上海好买基金招测试开发/测试工程师/配置管理组长/配置管理工程师
  • 原文地址:https://www.cnblogs.com/peterYong/p/6556617.html
Copyright © 2011-2022 走看看