, 用于线程同步 (Monitor.Enter(…))当一个引用类型的对象被创建时, 会需要4+4=8个byte的额外空间开销(32bit OS), 同时过度的使用引用类型对象会增加GC堆的压力, 频繁的GC对
程序的性能还是有一些影响的.
BCL中的Byte类型是一个结构体, 至于为什么它不是一个类, 我觉得可能是
设计者认为Byte不应该被继承, 或者8个byte的额外开销无法承受吧.
什么时候使用值类型/引用类型还
是应当具体情况具体分析, 个人倾向引用类型, 因为这样在设计的时候会少费些脑子, 不过能用sealed就sealed, 在方法调用时开销会小一些.
> 在.NET程序运行过程中,什么是堆,什么是栈?什么情况下会在堆(栈)上分配数据?它们有性能上的区别吗?“结构”对象可能分配在堆上吗?什么情况下会发生,有什么需要注意的吗?
.NET进程被创建时就会有一个堆随之被创建, 用来保存该进程在运行中需要使用的对象/数据; 当一个线程被创建时, 会有一个栈被创建,用来保存方法调用参数, 局部变量等轻量型数据.
当一个类里面包含一个结构体类型的变量时, 该结构体类型会被分配在堆上. (不知道有什么需要注意的…)
> 泛型的作用是什么?它有什么优势?它对性能有影响吗?它在执行时的行为是什么?.NET BCL中有哪些泛型类型?举例说明平时编程中您定义的泛型类型.
泛型有利于算法重用.
.NET进程地址空间中, 对象和类型是分开存放的, 当我们实例化一个泛型的时候 (比如List
list = new List();), 会有一个新的类型对象被创建(该对象并不位于GC堆上), 当我们在使用这个实例化泛型去创建新的对象时, 才会有一个对象(GC堆上)被创建. 所以性能上会有些许的损失. 当我们使用一个值类型作为参数,去调用一个接收引用类型参数的方法是, 会有装箱发生, 这时我们可以考虑实现一个泛型, 并在运行时确定方法的参数类型.
> 异常的作用是什么?.NET BCL中有哪些常见的异常?在代码中您是如何捕获/处理异常的?在“catch (ex)”中,“throw”和“throw ex”有什么区别?您会如何设计异常的结构,什么情况下您会抛出异常?
呃, 异常可以通知我们程序出错, 比如ArgumentException, NullReferenceException…
异常的发生会导致一次stack walk, 去寻找对应的exception handler, 在这个过程中, stack trace的信息会被一层层的收集, throw ex会清空之前收集的stack trace的信息, 相当于抛出了一个新的异常, 而throw不会, 所以throw ex不利于找出问题所在.
不同的layer应该catch不同exception, 最上层处理最general的exception, 底层去处理一些detail的exception.
> List和T[]的区别是什么,平时你如何进行选择?Dictionary是做什么的?.NET BCL中还有哪些常用的容器?它们分别是如何实现的(哪种数据结构)?分别是适用于哪些场景?
T[] 继承自Array, 而List仅仅是对T[]的封装; 相比于T[], List的size是动态变化的.
Dictionary可以用来存储键/值对.其他的比如HashTable, SortedList等.
> 抽象类和接口有什么区别?使用时有什么需要注意的吗?如何选择是定义一个“完全抽象”的抽象类,还是接口?
什么是接口的“显式实现”?为什么说它很重要?
抽象类定义了一个类及其子类是什么, 而接口更多的表现出一个类可以做什么.
当一个类实现连个不同的接口, 而这两个接口中包含一些相同签名的方法时需要用到显示实现.
> 字符串是引用类型类型还是结构类型?它和普通的引用类型相比有什么特别的地方吗?使用字符串时有什么需要注意的地方?为什么说StringBuilder比较高效?在连接多个字符串时,它无论何时都比直接相加更高效吗?
String是引用类型, 其特殊之处在于一个string是不可变的, 当我们对两个string使用连接操作时, 会生成一个新的string 对象, 而原来的两个string保持不变.
在和nat