该博文记录一些工作中接触较多的基础知识点的总结。
定义:值类型派生自 System.ValueType, 包括一般的非字符串基本类型(decemal,int,float)、结构体、枚举,可空类型(T?)。引用类型包括接口,类,数组,委托,string 等需要人工 new 创建的类型。
内存分配上有什么区别?
值类型分配在它声明的地方:作为字段时,跟随其所属的变量(实例)存储。作为局部变量时(eg: 方法内部局部变量),存储在栈上;而引用类型的的声明(指针)放在栈里面,而对应的实例对象(new 的对象)放在堆里面,引用类型在 C++ 中需要人工回收,而在 C# 中 GC 的 3 级回收机制可以自动回收托管代码。
错误回答:值类型放在内存栈里面,而引用类型放在堆里面。
分配内存为什么不同?
值类型类型简单,而引用类型相对复杂,引用类型会引用值类型或与其他引用类型有相互引用关系。简单来说,对象类型需要动态内存而基本类型则需要静态内存。若需要分配动态内存(GC 操作动态内存),那么就分配到堆上;反之在栈上。对于值类型,它们的内存值都分配在栈上,当我们把一个值类型分配给另外一个值类型时,需要创建一个完全不同的拷贝;对于引用类型,当我们创建一个对象,并把一个对象赋给另外一个对象时,它们的指针指向相同的内存。改变其中一个,会影响到另外一个。
装箱:用于在垃圾回收堆中存储值类型。装箱是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换。 拆箱:从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。
为何需要装箱?
一种最普通的场景是,调用一个含类型为 Object 的参数的方法,该 Object 可支持任意为型,以便通用。当你需要将一个值类型 (如 Int32) 传入时,需要装箱。 另一种用法是,一个非泛型的容器,同样是为了保证通用,而将元素类型定义为 Object。于是,要将值类型数据加入容器时,需要装箱。
重点:拆箱只是获取引用对象中指向值类型部分的指针,而内容拷贝则是赋值语句之触发。
注:使用装箱 / 拆箱会有风险,也会有一定的性能影响,一般可以用泛型替代。
为什么要用泛型?
通俗:为合并参数类型不同,逻辑相同的方法或类,提高代码复用率而产生的。
正规:可以将类型参数化以达到代码复用提高软件开发工作效率(增大代码复用性),并且提高性能和降低装箱、拆箱的成本或风险。
泛型有哪些优点?
使用泛型类型可以最大限度地重用代码、提高性能;可避免引入运行时强制转换或装箱操作的成本或风险;类型安全的(声明 T 是 string 类型,就不能是 decimal 类型)
应用:接口返回实体类用到(如:微信,QQ 等三方接口);持久层实体映射(Orm 框架中,基本上都是用实体做数据映射)等功能。
List 类是 ArrayList 类的泛型等效类,它的大部分用法都与 ArrayList 相似,因为 List 类也继承了 IList 接口。在声明 List 集合时,我们同时需要为其声明 List 集合内数据的对象类型,弥补了 ArrayList 存在不安全类型与装箱拆箱的缺点。
优点:类型安全;性能增强;代码复用。
抽象类和接口有什么相似处?
抽象类和接口有什么区别?
抽象类和接口使用在什么环境使用?
引用博客园中常见例子:
1. 狗和猫,他们都会叫、跑、睡觉,就继承同一个行为接口 "行为";但是加菲猫和折耳猫属于 "猫" 抽象类,二哈和柯基属于 "狗" 抽象类。
2. 公鸡和母鸡属于鸡(抽象类),不属于鸭(单继承),直接要一个鸡是要犯法的(不能直接实例化),如果需要具体的公鸡、母鸡是可以获得的。公鸡、母鸡都毛、两只脚(接口实现)。
单从字面上说,就是以对象为起点的编程思想。由于传统面向过程的编程方式,在各个功能模块的耦合性比较强,代码的重复率太高,造成软件后期迭代扩展功能很不方便,缺乏灵活性和代码重用性。以至于越往后期,代码的可维护性越差。为了提高代码的可维护性,重用性,灵活性和扩展性,面向对象诞生了。
面向对象三大特征,封装,继承,多态。用我做过的一个三方登录功能来说明:功能要求用户可用通过 PC 客户端,PC 网页端和 APP 端选者微信,QQ 或直接输入账号密码登录。其中有两个难点,第一个就是涉及到 3 种客户端,第二个就是三方登录平台多个。这种情况下就得用到面向对象的三大特性。首先:PC 客户端,PC 网页端和 APP 端是 3 个不同的登录逻辑,用封装特性可以将 3 种客户端的功能分别封装起来,降低耦合性,便于后期各个内部功能拓展。但是考虑到 3 种客户端登录功能又有许多可以公用的方法,可以用继承特性,将公用的方法给单独封装起来,作为一个父类(修饰符一般用 protected)大家都集成它。每种客户端类型登录中又有多重三方登录,这里也可以用到封装和继承。在登录功能中,会有和其他服务交互的功能,和每个服务交互的功能又有不同的区别。这里就可以用到多态,这里可以用一个简单工厂来实现多态,根据不同请求,与不同服务器做交互。
什么是委托,什么是多播委托,有那些优点,什么地方用到?
- public delegate voidOperateDelegate(string name);
- public voidOperatePeople(string name, OperateDelegate operateDelegate) {
- operateDelegate(name);
- }
什么是事件机制,有那些优点?
- public class EventManager
- {
- //这一次我们在这里声明一个事件
- public event EventDelegate MakeGreet;
- public voidEventOpt(stringtalkStr,ref string retStr)
- {
- MakeGreet(talkStr,ref retStr);
- }
- }
参考文章:面试中的委托、面试中的事件、委托与事件
定义
变体:带有协变或逆变参数的泛型接口或委托 (可隐式转换);
协变性,子到父的转换,让一个带有协变参数的泛型接口或泛型委托可以接收类型更具体的泛型接口或泛型委托作为参数,可以看成面向对象中多态的一个延伸;
逆变性,父到子的转换;让一个带有协变参数的泛型接口或泛型委托可以接收类型更泛化的泛型接口或泛型委托作为参数,实际上是参数类型更加精细化的过程。
不变性,只能是引用类型的泛型接口或泛型委托才能做协变 / 逆变操作。如果不用关键字 (out 或 in),强制转换都不行。
总结:协变类型参数可用作返回类型,而逆变类型参数可用作参数类型。
为什么要用可变性?
可变性可以安全的将一种类型转换成另一种类型。
lock 的作用,怎么使用?
lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
1、lock 的是引用类型的对象,string 类型除外。
2、lock 推荐的做法是使用静态的、只读的、私有的对象(静态能保证每次进入的只有一个线程,共有的有被其他程序干扰的风险,如果 lock 的对象在外部改变了,对其他线程就会畅通无阻,失去了 lock 的意义)
3、适用于单台服务器环境。
来源: http://www.cnblogs.com/harveybarray/p/6681582.html