# 密封类跟抽象类有啥区别?
抽象类:抽象类不能实例化,只能被继承。抽象类中可以有抽象方法,抽象方法没有方法体。抽象方法必须被继承类实现。
密封类:密封类可以被实例化,不能被继承
# 数据库读写分离和分库分表的主要区别
数据库读写分离是将数据库分为一个主库和多个从库,主库用于增删改,从库用于读
分库分表分为两种方式
1. 垂直拆分: 根据业务将数据库中的表进行分组,将相关表放在同一个数据库中。
这种方式会增加应用的复杂度,可能引发跨库事务和木桶效应
2. 水平拆分: 根据某种分片算法将一个库(表)拆分为多个库(表),水平拆分可以显著提示读写性能,但是需要处理分布式事务和跨库查询问题
应用场景:
--读写分离: 适用读多写少的场景,在高并发读操作下,可以有效提升读的性能
--分库分表: 适用于大数据量和高并发的场景,通过分散数据和请求来提升系统整体的性能
# 什么是缓存雪崩、缓存穿透和缓存击穿?
缓存雪崩 是指: 由于大量缓存数据在同一时间过期,导致所有原本应该访问缓存的请求都直接打到数据库上,从而对数据库的 CPU 和内存造成巨大压力,严重时可能导致数据库崩溃。这种情况通常发生在缓存设置了相同的过期时间,导致大量缓存同时失效
缓存穿透 是指: 用户查询的数据在缓存和数据库中都不存在,但用户仍然不断发起请求,导致每次请求都会查询数据库,从而给数据库带来巨大压力。这种情况常见于恶意攻击或系统错误
缓存击穿 是指: 热点数据在缓存失效的瞬间,大量并发请求未能命中缓存,直接打到数据库上,导致数据库压力骤增。这种情况通常发生在热点数据过期失效的瞬间,大量用户同时访问该数据,导致数据库无法承受如此高的并发请求
解决方案:
缓存雪崩 :
1. 分散过期时间 :避免所有缓存数据同时过期,可以通过随机生成过期时间来分散压力。
2. 限流和降级 :在缓存失效时,通过限流和降级措施减少对数据库的压力。
3. 双层缓存 :使用双层缓存策略,一层是热点数据永不过期,一层是普通数据按需加载。
缓存穿透 :
a. 业务层校验 :在业务层对请求参数进行校验,过滤掉明显错误的请求。
b. 设置空值缓存 :对于不存在的数据,可以在缓存中设置一个短过期的空值。
c. 使用布隆过滤器 :通过布隆过滤器提前拦截不存在的 key,减少对数据库的查询。
缓存击穿 :
1. 热点数据永不过期 :对于热点数据设置永不过期或通过定时任务更新。
2. 互斥锁 :在热点数据过期时,通过互斥锁控制只有一个请求去查询数据库并更新缓存。
分布式锁 :在分布式环境中使用分布式锁来确保只有一个请求去更新缓存。
# 什么是多线程?
多线程是指在一个进程中同时运行多个线程的技术
多线程是一种并发编程技术,允许一个进程中的多个线程同时执行不同的任务。每个线程是进程中的一个独立执行单元,共享进程的内存空间和资源,但拥有自己的执行路径。多线程的主要目的是提高程序的执行效率和响应能力,尤其是在处理并发任务时。
# Static 静态属性
不要在多线程情况下修改 static 定义的属性,会导致数据出现异常
# Hashtable 和 Dictionary 的使用注意
多线程下推荐使用 Hashtable,单线程下推荐使用 Dictionary, 因为 Dictionary 在多线程下存在线程锁的问题
# 死锁是如何产生的,如何避免死锁 ?
死锁的产生原因:
死锁是指在多线程或多进程环境中,两个或多个进程/线程因竞争资源而造成的一种相互等待的现象,若无外力干预,这些进程将无法向前推进。
死锁产生的四个必要条件(缺一不可): 1.互斥条件:资源一次只能被一个进程使用 2.请求与保持条件:进程在等待新资源时,仍保持已分配的资源 3.不剥夺条件:已分配的资源不能被强制剥夺,只能由进程主动释放 4.循环等待条件:多个进程形成循环等待链,每个进程都在等待下一个进程释放资源如何避免死锁:打破 4 个必要条件之一即可
# **C# 中值类型和引用类型的区别是什么?**
<font color=red>主要区别在于内存分配和赋值。值类型(如`int`、`bool`、`struct`),数据存储在栈中,赋值时会创建数据的一个副本,两个变量独立操作互不影响;引用类型(如`class`、`string`、数组),变量存储的是对象的引用,存放在堆中,赋值时仅复制引用,两个变量可能指向同一对象,修改一个会影响另一个。</font>
# **简述 C# 中的 const 和 readonly 关键字的区别。**
<font color=red>const 必须在声明时赋值,且仅限于基元类型、枚举类型和字符串,值在编译时确定;readonly 主要是定义一个只读字段或属性,确保其在初始化后不能被修改 。</font>
# 解释一下 C# 中的装箱(boxing)和拆箱(unboxing)。
<font color=red>装箱和拆箱是将值类型与引用类型之间进行转换的操作。</font>
<font color=red>装箱是将值类型转换为引用类型的过程。</font>
<font color=red>拆箱是引用类型转换位值类型的过程。</font>
```c#
int val = 100;
object obj = val; // 发生了装箱
```
<font color=red>拆箱则是相反的过程,它是将已经装箱的引用类型转换回原来的值类型。</font>
```c#
object obj = 100; // 假设obj之前被装箱过
int num = (int)obj; // 发生了拆箱
```
# **什么是面向对象编程的三大特性(封装、继承、多态),请举例说明。**
<font color=red>封装是将数据和操作数据的方法捆绑在一起,并隐藏类的内部实现细节,只暴露必要的接口给外部使用。</font>
<font color=red>继承允许一个类继承另一个类的属性和方法,比如有一个动物类,小狗继承动物类的方法</font>
<font color=red>多态性使得不同类的对象可以通过相同的接口调用表现出不同的行为。</font>
# **在 C# 中,如何实现方法重载(overload)和方法重写(override)?它们有什么区别?**
方法重载和重写是实现多态性的两种不同方式。
方法重载是指在同一类中定义多个方法名相同但参数列表不同的方法。
方法重写涉及继承关系,子类可以重新定义从父类继承的方法。要使一个方法能够被重写,它必须在基类中使用`virtual`关键字声明,并且在派生类中使用`override`关键字来提供新的实现。
# **抽象类(abstract class)和接口(interface)有什么区别?**
<font color=red>抽象类使用`abstract`关键字声明,可以包含抽象方法、字段、属性等。抽象类不能被实例化,且需要子类去实现具体内容</font>
<font color=red>接口使用`interface`关键字声明,仅能包含方法、属性、索引器和事件的签名,不能包含字段或方法的具体实现。</font>
<font color=red> 一个类只能继承自一个抽象类,但可以实现多个接口。</font>
# 请列举 C# 中常用的集合类,并说明它们的适用场景。
<font color=red>ArrayList:适用于需要动态调整大小的列表,并且可以包含任意类型对象。</font>
<font color=red>List<T>:适合需要频繁添加或删除元素的场景</font>
<font color=red>Dictionary<TKey, TValue>:存储键值对集合,适用于需要通过键快速检索值的情况。</font>
<font color=red>HashSet<T>:不允许重复元素的集合,适合需要保证集合内元素唯一性的场景。</font>
# **泛型的优点是什么?**
<font color=red>类型安全:泛型在编译时提供了类型检查,可以在编译阶段捕获类型错误,而不是在运行时抛出异常。</font>
<font color=red>代码复用:通过使用泛型,可以编写更通用、可复用的代码,减少重复代码的数量。</font>
<font color=red>性能优化:避免了装箱和拆箱操作(对于值类型),提高了程序的执行效率。</font>
# **什么是委托(delegate)?**
<font color=red>允许将方法作为参数传递给其他方法,或者存储为变量以便稍后调用。</font>
# **xxxxxx**
# **什么是 LINQ(Language Integrated Query)?**
<font color=red>LINQ 是.NET 框架中集成的一种数据查询方式,允许开发者使用统一的语法和编程模型处理多种数据源。</font>
# **请用 LINQ 实现从一个整数列表中筛选出所有偶数的功能。**
```c#
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var evenNumbers = numbers.Where(n => n % 2 == 0);
```
# **什么是线程同步?请列举几种线程同步的方式,并说明它们的区别。**
线程同步是指在多线程环境下,为了防止多个线程同时访问共享资源导致的数据不一致或数据损坏问题,采取的一种协调机制。
常见的线程同步方式:
1. lock:简单易用的互斥锁,自动管理加锁和解锁。
2. Monitor:提供了比 lock 更灵活的控制,可以使用 Wait/Pulse 进行线程通信。
3. Mutex:跨进程的互斥锁,适合需要在不同程序间同步的情况。
4. Semaphore:控制同时访问某一资源的线程数量,允许多个线程同时访问。
区别:`lock`适用于简单的同步需求;`Monitor`提供额外的功能如线程通信;`Mutex`用于需要跨进程同步的场合;而`Semaphore`则用于限制同时访问资源的线程数。
# **在 ASP.NET 中,如何实现页面之间的传值?**
<font color=red>QueryString:通过 URL 传递参数,简单但不适合敏感数据。</font>
<font color=red>Session:存储用户会话数据,适合跨多个页面的数据共享。</font>
<font color=red>Cookie:在客户端保存少量信息,如用户偏好设置。</font>
<font color=red>ViewState: 在同一个页面请求之间保存数据。</font>
<font color=red>ViewBag/ViewData: 用于在视图之间传递数据。</font>
# **.NET Core 与.NET Framework 有什么区别?**
<font color=red>跨平台支持:.NET Core 支持 Windows、Linux 和 macOS,而 .NET Framework 主要针对 Windows。</font>
<font color=red>开源性:.NET Core 是完全开源的,允许社区参与贡献;.NET Framework 则大部分是闭源的。</font>
<font color=red>模块化与轻量级:.NET Core 更加模块化,允许应用程序只包含所需的库,使得应用更轻量。.NET Framework 包含了大量 API,显得臃肿。</font>
<font color=red>部署灵活性:.NET Core 支持按应用版本进行部署,不同应用可以使用不同版本的 .NET Core 运行时。.NET Framework 的版本则通常需要整个系统更新。</font>
<font color=red>容器支持:.NET Core 对 Docker 等容器有更好的支持,适合现代云原生应用开发。</font>
# **C# 中的 async 和 await 关键字有什么作用?**
<font color=red>`async`用于定义异步方法,而`await`用于暂停执行直到任务完成,这样可以避免阻塞线程,使程序更高效和响应更快。</font>
# **如何优化 C# 代码的性能?请列举一些常见的优化方法。**
<font color=red>减少对象创建:避免在循环或频繁调用的方法中创建不必要的对象。</font>
<font color=red>选择合适的数据类型:优先使用值类型而非引用类型以加快访问速度。</font>
<font color=red>避免装箱和拆箱:减少值类型与引用类型之间的转换,考虑使用泛型。</font>
<font color=red>异步处理 I/O 操作:利用 async/await 模式提高 I/O 密集型任务的响应性。</font>
<font color=red>实现 IDisposable 接口:确保非托管资源及时释放,防止内存泄漏。</font>
<font color=red>遵循 SOLID 原则:保持代码简洁、模块化,便于维护和扩展。</font>
<font color=red>并行编程:针对多核处理器,使用并行技术加速计算密集型任务。</font>
# **请解释一下 C# 中的命名空间(namespace)的作用?**
<font color=red>命名空间主要用于两个核心目的:避免名称冲突;代码组织:</font>
# **什么是 lambda 表达式?**
<font color=red>Lambda 表达式是一种简洁的匿名函数形式,使用`=>`操作符来定义。它左边是参数列表,右边是执行的代码块。</font>
# **请简述 C# 中的特性(Attribute)的概念和使用场景。**
<font color=red>Attribute 是用来给代码元素(如类、方法等)添加额外信息的标签。它们用方括号`[]`表示,并放在目标前面。</font>
# 请解释一下 C# 中的密封类(sealed class)的作用和使用方法。
<font color=red>主要目的是防止其他类继承,确保类的实现不被修改或扩展</font>
```c#
public sealed class MySealedClass
{
// 类成员
}
```
# **简述 C# 中类和结构的区别。**
内存分配:类在堆上,结构通常在栈上。</font>
<font color=red>继承:类支持继承,结构不支持。</font>
<font color=red>构造函数:类可以有默认构造函数,结构必须定义时初始化所有字段。</font>
<font color=red>赋值:类赋值是引用复制,结构赋值是内容复制。</font>
# **在 C# 中,如何获取一个对象的类型信息?**
<font color=red>使用 `GetType()` 方法</font>
# **请简述 C# 中的 is 和 as 运算符的区别?**
<font color=red>**`is`**:用于类型检查,判断对象是否为指定类型或其派生类型的实例。</font>
<font color=red>**`as`**:用于安全地进行类型转换,避免强制转换可能引发的异常。</font>
<font color=red>需要注意的是,`as` 运算符在转换失败时返回 `null`,因此在使用后应检查结果是否为 `null`,以避免后续操作引发 空引用。</font>
# **什么是索引器(Indexer)?**
<font color=red>索引器允许对象像数组一样通过下标访问其成员。</font>
# **请简述 C# 中的 lock 关键字的作用和使用注意事项。**
<font color=red>`lock` 关键字通过获取指定对象的互斥锁,确保在同一时刻只有一个线程可以执行被锁定的代码块。</font>
<font color=red>注意:避免在 lock 快中执行耗时操作、引发异常和死锁方法;避免锁定值类型和公共实例</font>
# **简述 C# 中泛型约束的作用和使用方法。**
<font color=red>泛型约束用于限制泛型类型,确保类型符合特定要求。</font>
<font color=red>常见约束类型:</font>
<font color=red>类或接口:public class MyClass<T> where T : MyClass { }</font>
<font color=red>值类型:public class MyClass<T> where T : struct { }</font>
<font color=red>引用类型:public class MyClass<T> where T : class { }</font>
<font color=red>无参构造:public class MyClass<T> where T : new() { }</font>
# **在 C# 中,如何进行序列化和反序列化操作?**
`System.Text.Json`是 C# 自带的库,轻量且高效。
`Newtonsoft.Json` 第三方库,适用于更复杂的 JSON 操作。
# **简述 C# 中委托的多播(Multicast Delegate)的概念和使用方法。**
委托的多播允许一个委托绑定多个方法,调用时依次执行这些方法。
```c#
public delegate void MyDelegate(string message);
void Method1(string msg) => Console.WriteLine("Method1: " + msg);
void Method2(string msg) => Console.WriteLine("Method2: " + msg);
MyDelegate del = Method1;
del += Method2; // 绑定 Method2
del("Hello"); // 输出:Method1: Hello \n Method2: Hello
```
# 请解释一下 C# 中的 ref 和 out 关键字的区别?
关键区别:
- `ref`:传入前需初始化,方法修改值。
- `out`:不需初始化,方法内部赋值。
# 简述 C# 中 object 类型和 dynamic 类型的区别。
关键区别:
- `object`:类型安全,使用时需要显式转换,编译时检查。
- `dynamic`:运行时类型检查,编译时不检查,灵活但性能较差。
# 简述 C# 中 lock 语句和 Monitor 类的关系。
`lock` 语句本质上是 `Monitor` 类的语法糖,`lock` 语句会被编译器自动转换为 `Monitor.Enter` 和 `Monitor.Exit` 的调用,并包装在 `try-finally` 块中以确保锁的释放。