C#.Net筑基-类型系统①基础

image.png

C#.Net的BCL提供了丰富的类型,最基础的是值类型、引用类型,而他们的共同(隐私)祖先是 System.Object(万物之源),所以任何类型都可以转换为Object。


01、数据类型汇总

C#.NET 类型结构总结如下图,Object是万物之源。最常用的就是值类型、引用类型,指针是一个特殊的值类型,泛型必须指定确定的类型参数后才是一个正式的类型。

image

1.1、值类型汇总⭐

🔸值类型Type说明示例/备注
byteSystem.Byte8 位(1字节)无符号整数,0到255,
sbyteSystem.SByte8 位(1字节)有符号整数,-128 到 127不符合 CLS
intSystem.Int3232位(4字节)有符号整型,大概-21亿-21亿
uintSystem.UInt3232位(4字节)无符号整型, 0 到 42亿不符合 CLS
shortSystem.Int1616 位(2字节)有符号短整数,-32768 到 32767,
ushortSystem.UInt1616 位(2字节)无符号 短整数, 0 到 65535不符合 CLS
longSystem.Int6464位(8字节)有符号长整形,19位数
ulongSystem.UInt6464位(8字节)无符号长整形,20位数不符合 CLS
Int128Int128128 位有符号整数,.Net7支持
BigIntegerBigInteger表示任意大小的(有符号)整数,不可变值
整数表示-十六进制:0x/0X前缀;二进制:0b/0B前缀var默认为int
floatSystem.Single32位(4字节)单精度浮点数,最多6-7 位小数,-+3.402823E38后缀f/F
doubleSystem.Double64位(8字节)双精度浮点数,最多15-16 位小数,-+1.7*E308后缀d/D
decimalSystem.Decimal128位(16字节)高精度浮点数,28位小数,-+7.9E28后缀m/M
boolSystem.Boolean8位(1字节)布尔型,只有两个值:truefalse
charSystem.Char16 位(2字节)单个字符,0 到 65,535的码值,使用 UTF-16 编码
enumSystem.Enum支持任意整形的(常量)枚举,可以看做是一组整形的常量值集合
ComplexComplex表示一个复数,实部和虚部都为double
GuidGuid全局唯一标识符(16字节),一出生就是全球唯一的值Guid.NewGuid()
struct结构体是一种用户自定义的值类型,常用于定义一些简单(轻量)的数据结构
DateTimeDateTime时间日期,详见下一章节

  • bool 虽然只需要1位空间,但仍然占用了1个字节,是因为字节是处理器的最小单位。如果有大量的Bool,可用BitArray。
  • 值类型大多都是“不可变的”,就意味着修改会创建新的对象,上面表格中除了自定义的结构体Struct外都是不可变的。
  • CTS(Common Type System)为通用类型系统,为微软定制的通用类型规范,所有.Net语言都支持(如F#、VB、C#)。不符合CTS就意味着C#独有。

1.2、引用类型汇总⭐

🔸引用类型Type说明示例/备注
objectSystem.Object.NET 类的顶层基类,万物之源,包括所有值类型、引用类型万物之源
stringSystem.String字符串,引用类型,使用上有点像值类型恒定性、驻留性
dynamicSystem.Dynamic动态类型,编译时不检查,可随意编码,只在运行时检查dynamic = 12
Interface-严格来说并不是“类型”,只是一组契约,可作为引用申明变量接口契约
Class-定义一个引用类型,隐式继承自object定义类
DelegateSystem.Delegate委托类型,详见后文《解密委托与事件》
IEnumerable-可枚举集合接口,几乎所有集合类型都实现了该接口
T[]Array数组,同上枚举接口,更多参考《.Net中的集合》
匿名类型new{P=v,V=1}动态申明一个临时匿名类型实例,编译器会创建类
元祖Tuple内置的一组包含若干属性的泛型类,常用(ValueTuple)编译器支持
recoredrecord记录类型,支持class(默认)、struct,其实就是简化版的类型申明编译器创建完整类型

1.3、Object-万物之源

System.Object是所有类型的根,任何类都是显式或隐式的继承于System.Object,包括值类型,所以任何类型都可以转换为Object

成员描述
string? ToString ()返回对象的字符串,默认返回对象类型名称,按需重写。
bool Equals (object? obj)比较是否与当前(this)相同,引用类型比较引用地址,值类型比较值&类型,可重写!
int GetHashCode ()获取当前对象的哈希码,用于哈希集合Dictionary、Hashtable中快速检查相等性。但不可用于相等判断,如果重写了Equals,应同时重写GetHashCode,确保两者一致。
Type GetType ()当前实例的准确运行时类型。如果是类型,在可用typeof(T)
protected ~Object ();Object.Finalize析构函数,GC调用释放资源,按需实现。一般配合Dispose(GC.SuppressFinalize )
protected object MemberwiseClone()浅拷贝,创建新对象>赋值非静态字段,引用类型字段就是赋值引用地址了。
static bool Equals(Object, Object)比较相同,内部会调用实例的Equals(Object)方法
static bool ReferenceEquals(o1,o2)比较两个引用对象是否同一实例,⁉️注意如果用于值类型会被装箱从而始终false

下面代码为.Net中的 System.Object 源码:

public partial class Object
{public Object(){ }public virtual string? ToString(){return GetType().ToString();}protected internal unsafe object MemberwiseClone();  //对象浅拷贝public virtual bool Equals(object? obj){return this == obj;}public static bool Equals(object? objA, object? objB){return objA == objB || (objA != null && objB != null && objA.Equals(objB));}public static bool ReferenceEquals(object? objA, object? objB){return objA == objB;}public virtual int GetHashCode(){return RuntimeHelpers.GetHashCode(this);}~Object(){}  //终结器
}

02、值类型与引用类型

值类型和引用类型是C#中最重要、最常用的两种数据类型,两者是有很多区别的,而且常常和性能有很大关系,因此这是C#开发者必须掌握的基础知识。

2.1、值类型 VS 引用类型

区别值类型 ValueType引用类型 ReferenceType
⭐存储位置栈(Stack),也可以称为线程栈堆(GC Heap),由GC管理
⭐存储内容对象在堆上,引用变量在栈上,栈存储的的是堆上对象的内存地址
⭐传递方式值传递,参数传递时传递的是值拷贝,各回各家传递的是引用(地址),因此是同一个对象,分身代理
装箱、拆箱转换为object、接口时会装箱、拆箱
默认值default数字、枚举默认0,bool默认false默认null
占用内存大小就值本身的长度,如int为4个字节值本身+额外空间(引用对象的标配:TypeHandle、同步块)
继承的对象隐式继承自System.ValueType默认继承自Object
接口、继承不支持继承其他值类型,可继承接口支持继承类、接口
怎么判断Type.IsValueTypeo.GetType().IsValueTypeIsValueType ==false
生命周期作用域结束就释放,或方法结束就释放了由GC管理,当对象没被使用了,GC检查后标记清除
性能栈内存性能很高低,需要GC分配内存、GC释放
  • default可以表示任意类型的默认值,编译时会被赋值。struct的默认值为每个字段设置默认值。
int x = 100;
int y = x;     //值拷贝传递
string name = "sam";
int[] arr = new int[] { 1, 2, 3 };
var list = arr; //引用地址传递,实际指向同一个引用对象,分身幻象

📢 两者核心区别就是存储的方式不同,理解这一点非常重要,在变量(字段)赋值、方法参数传递上都是如此。

image

🔸Stack 栈:(线程)栈,由操作系统管理,存放值类型、引用类型变量(就是引用对象在托管堆上的地址)。栈是基于线程的,也就是说一个线程会包含一个线程栈,线程栈中的值类型在对象作用域结束后会被清理,效率很高。

🔸托管堆(GC Heap):进程初始化后在进程地址空间上划分的内存空间,存储.NET运行过程中的对象,所有的引用类型都分配在托管堆上,托管堆上分配的对象是由GC来管理和释放的。托管堆是基于进程的,当然托管堆内部还有其他更为复杂的结构。

关于更多堆栈内存信息,查看后文《C#的内存管理艺术》

📢值类型可使用outref关键字,像引用类型一样传递参数地址。两者对于编译器是一样的,都是取地址,唯一区别就是ref参数需要在外面初始化,out参数在方法内部初始化。

2.3、装箱和拆箱⁉️

因为值类型、引用类型的基类都是Object,因此值类型、引用类型是可以相互转换的,但这个转换是有很高成本的,这个过程就是装箱、拆箱。

int x = 100;     //一个普通的值类型变量
object obj =x;   //装箱到obj
int y = (int)obj;//拆箱到y

可视化分析一下这个过程:

🔸装箱:值类型转换为引用对象,一般是转换为System.Object类型,或接口类型。所以“箱子”就是Object引用对象,装箱的过程:

  • ❶ 在GC堆上申请内存,内存大小为值类型的大小,再加上额外固定空间(引用类型的标配:TypeHandle和同步索引块);
  • ❷ 将值(100)拷贝到分配的内存中;
  • ❸ 返回新对象(箱子)的引用地址给变量obj

🔸拆箱:引用类型转换为值类型,注意,这里的引用类型只能是被装箱的引用类型对象。

  • ❶ 检测操作是否合法,如箱子是否为null,类型是否和待拆箱的类型一致,检测失败则抛出异常InvalidCastException
  • ❷ 把箱子中的值拷贝到栈上。

image.png

上面三行装箱、拆箱代码的IL代码:装箱box、拆箱unbox是两个专门的指令。

image.png

由上可知,装箱会在GC堆上创建一个“箱子”(Object对象)来装载值,这是装箱造成极大的性能损失的根本原因,拆箱则把值搬回到栈内存上。

  • 只有值类型才会有装箱、拆箱,引用类型一直都在“箱子”里。
  • 相对来说装箱的性能损失更大,原因不难理解,创建引用对象(箱子)的性能开销更大。

📢在日常开发中,很容易发生隐式装箱,所以要特别注意,尽量用泛型。如ArrayList、Hashtable 都是面向Object的集合,应该用List<T>Dictionary<TKey, TValue>代替。

ArrayList arr = new ArrayList();
arr.Add(1);      //装箱
arr.Add(true);   //装箱
Hashtable ht = new Hashtable();
ht.Add(1,1.2f);  //装箱了两次

对比测试装箱、拆箱的性能影响:

private T Add<T>(T arg1,T arg2) where T:INumber<T>
{return arg1+arg2;
}
private int AddWithObject(object x, object y)
{return (int)x + (int)y;
}

测试结果比较明显,装箱的方法在执行效率、内存消耗上都要差很多。

image.png


03、Nullable?可空类型

可空类型可用于值类型、引用类型,他们使用语法类似,不过他们是完全不同的两种东西。值类型的可空?是一个泛型Nullable<T>类型,而引用类型的?只是一个用于编译器检查的语法。

image.png

int? n = null;
string? str = "sam";

可空值类型、引用类型都支持null操作符:

  • Null 条件运算符,str?.Length
  • Null 合并赋值,n??=1

3.1、值类型的Nullable<T>

对于值类型,可空值类型表示值类型对象可以为null值,可空值类型T?的本质其实是Nullable<T>,他是一个值类型(结构体)。

int x0 = default;  //默认值为0
int? x1 = default; //默认值值为null
int? x2 = null;
Nullable<int> x3 = null;  //同上if (x3.HasValue)
{Console.WriteLine(x3.Value);
}
int a = x0 + (x3.HasValue? x3.Value : 10);
int b = x0 + x3 ?? 10; //效果同上
  • 简化的语法为:Type?,示例:int? n;,类型后跟一个问号"?",和引用类型的可空语法一样。
  • 属性HasValue判断是否有值,Value获取值,如果HasValuefalse时获取 Value 值会抛出异常。
  • 转换:T可隐式转换为T?,反之则需要显示转换。

下面为Nullable<T>的源码,是一个简单的结构体,T被约束为结构体(值类型)。

public struct Nullable<T> where T : struct
{//判断是否有值public readonly bool HasValue { get; }//获取值public readonly T Value { get; }public readonly T GetValueOrDefault()public readonly T GetValueOrDefault(T defaultValue)
}

image.png

3.2、可空引用类型T?

引用类型本身的默认值就是null,为了避免一些场景下不必要的 NullReferenceException,就有了可空的引用类型T?,其核心目的就是为提高代码的健壮性。可空的引用类型并不是一个“新的类型”,而是一个编译指令,告诉编译器这个引用类型变量可能是null,使用时需检查,未初始化也没检查null就使用,编译器会产生编译告警,由此来提前发现潜在Bug,提高代码健壮性。如果没加?,则该表示引用对象不会为null

要开启可空引用类型需要配置启用才行:

  • 在项目配置中开启:<Nullable>enable</Nullable>,值disable表示不启用。
  • 在代码文件中启用,在文件头部加#nullable enable,只对当前代码文件有效。
public int GetLength(string? firstName, string lastName)
{var len = firstName.Length; //编译器会警告 firstName 可能为nullif (firstName != null)      //加上null判断就好了len += firstName.Length;len = firstName!.Length;    //加上!,则忽略检查len += lastName.Length;     //lastName不会为null,没有告警return len;
}

对于上面的示例代码,编译器会认为firstName可能会为null,在使用前必须初始化,或者检查是否为null。而lastName不会为null,可以直接使用。

📢 消除可空引用类型的编译告警的方法是结尾加!(null 包容运算符),告诉编译器这个对象肯定不会为null,别再告警了!

在命名空间“System.Diagnostics.CodeAnalysis”下还有一些特性,用来辅助代码的静态检查和编译器检查。

[NotNull]  //标记返回值不会为null
private string? FullName => "sam";//当方法返回false时参数value不会为null。该方法就是string.IsNullOrEmpty的源码
public static bool IsNullOrEmpty([NotNullWhen(false)] string? value)
{if ((object)value != null){return value.Length == 0;}return true;
}

04、类型转换⭐

数据类型之间是可以相互转换的,由一个数据类型转换为另一数据类型,常见的转换方式:

转换方式说明备注/示例
隐式转换转换是自动的,一般是兼容的数值类型之间,编译时检查int n =100; float f = n;
强制显示转换使用强制转换操作符转换,(Type)value值类型编译时检查,引用类型运行时检查,失败抛出异常!
装箱、拆箱值类型转换为引用类型object,反之为拆箱装箱是隐式的,拆箱需显示转换
as显示转换只用于引用类型转换:value as Type运行时检查,失败返回null
is类型检查检查一个值是否为指定(兼容)类型,如果是则转换if(obj is float f) {}
类型方法Parse内置值类型基本都提供Parse、TryParse方法int.Parse("123")
Convert静态类,提供了大量的静态方法来转换内置数据类型Convert.ToInt16(false)
BitConverter静态类,各种内置类型和字节之间的转换方法BitConverter.GetBytes(0xff)
XmlConvert静态类,提供了各种内置类型和string之前的转换方法XmlConvert.ToInt32("1221")
TypeConverterSystem.ComponentModel 空间下提供的大量类型转换器var cc = TypeDescriptor.GetConverter(typeof(Color))
dynamic动态类型并不算是类型转换,作为一种特殊方式,运行时检查dynamic d = Foo; d.Print();

📢注意

  • 几乎所有类型都可以隐式转换为 Object,注意值类型转换Object会装箱。
  • 对于值类型,范围小的类型转换范围大的类型大都支持隐式转换,且不会损失精度,如floatdoubleint转浮点数。反之则需要强制转换,可能会损失精度,或溢出。
  • is 语句可用于模式匹配,实现灵活的类型、数据检查,详细参考《C#中的模式匹配汇总》。
int a = (int)'a';     // 强制类型转换
Console.WriteLine(a); // 97float f = a;          // 隐式类型转换
Console.WriteLine(f);object obj = f;         //装箱,值类型隐式转换为引用类型
float f2 = (float)obj;  //拆箱
if(obj is float f3)     //is检查是否为float类型,如果是则转换值到变量f3
{Console.WriteLine(f3);
}
string str = obj as string; //as 转换失败,obj是float装箱
Console.WriteLine(str);     //null

4.1、数值转换方式汇总

转换需求转换方法示例
解析十进制数字Parse、TryParseint.Parse("1234")double.Parse("123.04")
解析2/8/16进制数Convert.To()Convert.ToInt32("F",16)//15
16进制格式化ToString(“X”)1234.ToString("X6")//0004D2
无损数值转换隐式转换int n = 100; double d = n;
截断数值转换显示转换 T v2 = (T)v1double d=12.56d; int n = (int)d; //n = 12,直接截断,不会四舍五入
四舍五入转换Convert.To()、Math.Round(d)int n = Convert.ToInt32(d); //n = 13,四舍五入转换
int n = Math.Round(d) //n = 13,可指定小数位数

05、相等、大小比较

📢 值类型比较的是值(结构体会比较其所有字段值),引用类型是比较的引用地址!

比较操作说明
==、!=相等运算符,其本质是调用静态方法(运算符重载方法)
a.Equals(b)实例的虚方法(可被重写),运行时根据实际类型调用。
🔸 ①、a不能为null,否则就NullReferenceException了。
🔸 ②、引用类型默认比较引用地址,值类型会递归调用每一个字段的Equals方法。
🔸 ③、装箱的值类型会比较箱子内的值。
Object.Equals(a,b)Object静态方法,null判断+a.Equals(b),参数是Object,值类型会装箱。
Object.ReferenceEquals(a,b)Object静态方法,只比较引用地址
IEquatable<T>相等接口方法bool Equals(T? other)
IComparable<T>大小比较 int CompareTo(T? other),返回一个int值:a.CompareTo(b)// a>b 返回1,a==b 返回 0, a<b 返回 -1
>、<大小比较运算符,结果应该和上面 IComparable 保持一致
IEqualityComparer<T>扩展的相等比较接口,非泛型版本 IEqualityComparer
StringComparer提供了用于字符串的多种类型的比较器:StringComparer.Ordinal.Compare("h","H")
public interface IComparable<in T>
{int CompareTo(T? other);
}
public interface IEquatable<T>
{bool Equals(T? other);
}
public interface IEqualityComparer<in T>
{bool Equals(T? x, T? y);int GetHashCode([DisallowNull] T obj);
}
// System.Object
public static bool Equals(object? objA, object? objB)
{if (objA == objB){return true;}if (objA == null || objB == null){return false;}return objA.Equals(objB);
}
  • Equals()方法必须自相等,即 x.Equals(x) 必为true
  • 对于值类型,大多数情况下Equals()方法等效于 ==,只有double.NaN例外,double.NaN 不等于任何对象。而引用类型则不一定了,有些引用类型重写了Equals()方法,而没有重写 == 运算符。
Console.WriteLine(double.NaN == double.NaN);     //False
Console.WriteLine(double.NaN.Equals(double.NaN));//TrueConsole.WriteLine(object.Equals(1,1));           //True  //装箱比较值
Console.WriteLine(object.ReferenceEquals(1,1));  //False //装箱比较引用StringBuilder sb1 = new StringBuilder("sb");
StringBuilder sb2 = new StringBuilder("sb");
Console.WriteLine(sb1 == sb2);                     //False
Console.WriteLine(object.Equals(sb1,sb2));         //False
Console.WriteLine(object.ReferenceEquals(sb1,sb2));//False
Console.WriteLine(sb1.Equals(sb2));				   //True  //与上面的 object.Equals(sb1,sb2) 不同

上面的 StringBuilder 重新实现了 Equals方法,但不是继承覆盖,而是隐式new覆写实现的,因此只能在 通过 StringBuilder 引用调用时才有效。参考:StringBuilder 源码。

image.png

5.1、自定义相等

⁉️什么时候需要自定义相等比较?

  • 提高比较速度,多用于自定义结构体。
  • 修改相等比较的语义,基于实际业务需要自定义相等的规则,如System.Url、String.String 都是引用类型,只要字符值相同则相等(== 和 Equals)。

⁉️如何自定义相等比较?

  • 重写 GetHashCode()Equals() 方法。这两个一般是一起配对重写,需注意 二者的一致性。
  • (可选)重载 !===
  • (可选)实现 IEquatable<T> 接口。

📢GetHashCode() 是基类 Object 的一个虚方法,该方法用于获取一个对象的 Int32 类型的散列码。该散列码只在键值结构(Hashtable、HashSet、Dictionary)中使用,用来表示元素的唯一“ID”,用于在哈希表中快速检索数据。

GetHashCode()的默认实现:

  • 值类型的散列码 是由每一个字段的值来计算的,如果有多个字段则通过一定的规则组合(如异或运算)。
  • 引用类型则基于对象的内存地址。

so,如果重写了Equals() 方法,则一般要重写GetHashCode(),让两者匹配。当然如果不遵守该规则也没问题,只是在使用哈希表时可能会出现问题(如性能严重下降)。


参考资料

  • .NET类型系统②常见类型
  • C# 文档
  • 《C#8.0 In a Nutshell》
  • .NET面试题解析(02)-拆箱与装箱
  • .NET面试题解析(01)-值类型与引用类型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/353860.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用@Value注解无法成功获取配置文件内容,常见原因

在日常的java开发中&#xff0c;我们经常会遇到一些需要将信息写在配置文件的要求&#xff0c;比如文件的输出目录&#xff0c;输入目录的。当在配置文件中写入对应的目录配置时&#xff0c;那么怎么读取配置文件的内容就需要我们去了解了。 在java中一般使用Value这个注解去读…

SSM小区车辆信息管理系统-计算机毕业设计源码06111

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&#xff0c;应用软件的工作…

【机器学习】第5章 朴素贝叶斯分类器

一、概念 1.贝叶斯定理&#xff1a; &#xff08;1&#xff09;就是“某个特征”属于“某种东西”的概率&#xff0c;公式就是最下面那个公式。 2.朴素贝叶斯算法概述 &#xff08;1&#xff09;是为数不多的基于概率论的分类算法&#xff0c;即通过考虑特征概率来预测分类。 …

ubuntu如何查看ip地址

ubuntu如何查看ip地址 方法一&#xff1a;使用ifconfig方法二&#xff1a;使用ip命令 方法一&#xff1a;使用ifconfig 命令行输入ifconfig&#xff1a; 这里inet后跟的内容就是IP地址。 方法二&#xff1a;使用ip命令 命令行输入&#xff1a;ipa ddr&#xff1a; 这里ine…

可抑制癌细胞增殖!慧湖药学院联手天津医科大,研发新型肿瘤抑制蛋白降解剂 dp53m

或许很多人不知道&#xff0c;其实我们每个人体内都存在癌细胞。 人体每天都在进行着数十亿甚至上百亿细胞的新生与更替&#xff0c;在这个代谢过程中&#xff0c;DNA 复制难免会「出错」&#xff0c;比如会出现基因突变&#xff0c;让正常的细胞变成原位癌细胞。不过&#xff…

最新版首发 | 手把手教你安装 Vivado2024.1(附安装包)

Q&#xff1a;Vivado出2024版了&#xff01;不知迪普微有没有对应的安装包呢&#xff1f; A&#xff1a;有的&#xff01;回复“Vivado2024.1”即可获得相应安装包哦~ Q&#xff1a;好哒~但是我不会安装&#xff0c;可否安排一期安装教程&#xff1f; A&#xff1a;立马安排&…

ONES 功能上新|ONES 开放平台新功能一览

ONES 开放平台提供 OpenAPI、插槽、事件等能力&#xff0c;以便开发者通过插件&#xff0c;实现第三方集成和流程定制&#xff0c;满足客户的二次开发需求。 支持在任意工作项视图的详情表单中&#xff0c;添加插件的自定义标签页&#xff0c;以满足插件开发者在工作项详情页显…

人力资源招聘社会校企类型招聘系统校园招聘小程序

校企社会人力资源招聘小程序&#xff1a;开启高效招聘新时代 &#x1f680;开篇&#xff1a;打破传统&#xff0c;开启招聘新篇章 在快速发展的现代社会&#xff0c;人力资源招聘已经成为企业和学校共同关注的重要议题。为了更高效、便捷地满足双方的招聘需求&#xff0c;一款…

【NoSQL数据库】Redis Cluster集群(含redis集群扩容脚本)

Redis Cluster集群 Redis ClusterRedis 分布式扩展之 Redis Cluster 方案功能数据如何进行存储 redis 集群架构集群伸缩向集群中添加一个新的master节点&#xff0c;并向其中存储 num10 .脚本对redis集群扩容缩容&#xff0c;脚本参数为redis集群&#xff0c;固定从6001移动200…

Mac用虚拟机玩游戏很卡 Mac电脑玩游戏怎么流畅运行 苹果电脑怎么畅玩Windows游戏

对于许多Mac电脑用户而言&#xff0c;他们经常面临一个令人头疼的问题&#xff1a;在虚拟机中玩游戏时卡顿严重&#xff0c;影响了游戏体验。下面我们将介绍Mac用虚拟机玩游戏很卡&#xff0c;Mac电脑玩游戏怎么流畅运行的相关内容。 一、Mac用虚拟机玩游戏很卡 下面我们来看…

NUC 14 Pro+:解锁AI前沿,体验科技之美

NUC 14 Pro不仅是一台迷你主机&#xff0c;更是生活品质的体现。如果你也是细节控&#xff0c;那这篇文章或许是你需要的。 超小体积 造型精致 NUC 14 Pro作为迷你PC拥有约0.66L的超小体积&#xff0c;如果你对升没有概念&#xff0c;那你可以想象&#xff1a;它的机箱面积144…

swagger下载文件名中文乱码、swagger导出文件名乱码、swagger文件导出名称乱码、解决swagger中文下载乱码bug

文章目录 一、场景描述&#xff1a;swagger导出文件名称乱码二、乱码原因三、解决方法3.1、方法一、在浏览器中输入地址下载3.2、方法二、swagger升级为2.10.0及以上 四、可能遇到的问题4.1、DocumentationPluginsManager.java:152 一、场景描述&#xff1a;swagger导出文件名称…

Pentest Muse:一款专为网络安全人员设计的AI助手

关于Pentest Muse Pentest Muse是一款专为网络安全研究人员和渗透测试人员设计和开发的人工智能AI助手&#xff0c;该工具可以帮助渗透测试人员进行头脑风暴、编写Payload、分析代码或执行网络侦查任务。除此之外&#xff0c;Pentest Muse甚至还能够执行命令行代码并以迭代方式…

Linux C编译器从零开发三

AST语法树 BNF抽象 expr equality equality relational ("" relational | "!" relational)* relational add ("<" add | "<" add | ">" add | ">" add)* add mul ("" …

重生奇迹MU 探秘奇幻世界

"探秘奇幻世界&#xff0c;成就无尽荣耀&#xff01;欢迎来到重生奇迹MU&#xff0c;一个永不落幕的游戏乐园。在这里&#xff0c;你可以尽情挑战各种困难&#xff0c;发掘神秘宝藏&#xff0c;还可与来自世界各地的玩家一起创造无尽的历史。为了帮助你更好地探索游戏世界…

mysql中返回日期格式带有T、Java解决返回日期格式带 ‘T‘ 问题、MySQL查询日期为什么带T、java.util.Date()类型为什么有T

文章目录 一、场景描述&#xff1a;Mysql返回日期格式带有T二、解决方法2.1、方法一&#xff1a;通过注解格式化2.2、方法二&#xff1a;通过全局配置2.3、方法三&#xff1a;查询时手动转换时间格式 三、mysql 数据库时间类型数据为什么有T3.1、什么是ISO 8601格式 四、java中…

C语言实现五子棋教程

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

现代密码学-国密算法

商用密码算法种类 商用密码算法 密码学概念、协议与算法之间的依赖关系 数字签名、证书-公钥密码、散列类算法 消息验证码-对称密码 &#xff0c;散列类 安全目标与算法之间的关系 机密性--对称密码、公钥密码 完整性--散列类算法 可用性--散列类、公钥密码 真实性--公…

Boost 网络库

asio 网络编程的基本流程创建 socket绑定acceptor连接指定的端点服务器接受连接 网络编程的基本流程 服务端 1&#xff09;socket----创建socket对象。 2&#xff09;bind----绑定本机ipport。 3&#xff09;listen----监听来电&#xff0c;若在监听到来电&#xff0c;则建…

系统之家教你安装最新Win10 22H2版本!一看就会!

当前很多用户办公或学习都喜欢使用Win10系统&#xff0c;但很多新手用户不知道怎么操作才能安装上最新的Win10 22H2版本&#xff1f;接下来系统之家小编就给大家带来最简单的安装方法&#xff0c;帮助大家轻松快速给电脑安装上Win10系统最新版本22H2&#xff0c;体验22H2版本带…