设计模式-值类型与引用类型、深拷贝与浅拷贝、原型模式详解
一. 值类型和引用类型
1. 前言
(1). 分类
值类型包括:布尔类型、浮点类型(float、double、decimal、byte)、字符类型(char)、整型(int、long、short等)、枚举(entum)、结构体(struct)。
引用类型:数组、字符串(string)、类、接口、委托(delegate)。
(2).内存存储
值类型数据存放在栈stack中, 引用类型地址存放栈stack中,数据存放在堆heap中。
值类型变量声明后,不管是否赋值,都会在在栈中分配内存空间。引用类型声明时,只在栈中分配内存,用于存放地址,并没有在堆上分配内存空间。
2. 对象的传递
(1). 将值类型的变量赋值给另一个变量,会执行一次赋值,赋值变量包含的值。
(2). 将引用类型的变量赋值给另一个引用类型变量,它复制的是引用对象的内存地址,在赋值后就会多个变量指向同一个引用对象实例。
代码分享:
Console.WriteLine("------------------------下面是值类型和引用类型赋值-----------------------------");//值类型赋值int a = 0;int b = a;Console.WriteLine($"默认值: a={a},b={b}");a = 1;Console.WriteLine($"修改a的值后: a={a},b={b}");b = 2;Console.WriteLine($"修改b的值后: a={a},b={b}");//引用类型赋值Student stu1 = new Student();stu1.age = 20;Student stu2 = stu1;Console.WriteLine($"默认值: stu1.age={ stu1.age}, stu2.age={stu2.age}");stu1.age = 30;Console.WriteLine($"修改stu1.age的值后:stu1.age={ stu1.age}, stu2.age={stu2.age}");stu2.age = 40;Console.WriteLine($"修改stu2.age的值后: stu1.age={ stu1.age}, stu2.age={stu2.age}");
运行结果:
3. 参数按值传递
(1). 对于值类型(age),传递的是该值类型实例的一个副本,因此原本的值age并没有改变。
(2). 对于引用类型(Student stu),传递是变量stu的引用地址(即stu对象实例的内存地址)拷贝副本,因此他们操作都是同一个stu对象实例。
代码分享:
{Console.WriteLine("------------------------下面是参数按值传递-----------------------------");//值类型按值传递int age1 = 60;Utils.AddAge1(age1);Console.WriteLine($"age={age1}");//引用类型按值传递Student stu2 = new Student();stu2.age = 100;Utils.ReduceAge1(stu2);Console.WriteLine($"age={stu2.age}");
}
public class Utils
{public static void ReduceAge1(Student stu){stu.age -= 10;Console.WriteLine($"ReduceAge age={stu.age}");}public static void AddAge1(int age){age += 10;Console.WriteLine($"AddAge age ={age}");}public static void ReduceAge2(ref Student stu){stu.age -= 10;Console.WriteLine($"ReduceAge age={stu.age}");}public static void AddAge2(ref int age){age += 10;Console.WriteLine($"AddAge age ={age}");}}
运行结果:
4. 参数按引用类型传递
不管是值类型还是引用类型,可以使用ref或out关键字来实现参数的按引用传递。ref或out关键字告诉编译器,方法传递的是参数地址,而非参数本身。在按引用传递时,方法的定义和调用都必须显式的使用ref或out关键字,不可以省略,否则会引起编译错误。
代码分享:
{Console.WriteLine("------------------------下面是参数按引用传递-----------------------------");//值类型按值传递int age1 = 60;Utils.AddAge2(ref age1);Console.WriteLine($"age={age1}");//引用类型按值传递Student stu2 = new Student();stu2.age = 100;Utils.ReduceAge2(ref stu2);Console.WriteLine($"age={stu2.age}");
}public class Utils{public static void ReduceAge1(Student stu){stu.age -= 10;Console.WriteLine($"ReduceAge age={stu.age}");}public static void AddAge1(int age){age += 10;Console.WriteLine($"AddAge age ={age}");}public static void ReduceAge2(ref Student stu){stu.age -= 10;Console.WriteLine($"ReduceAge age={stu.age}");}public static void AddAge2(ref int age){age += 10;Console.WriteLine($"AddAge age ={age}");}}
运行结果:
更多C++后台开发技术点知识内容包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒体,音视频开发,Linux内核,TCP/IP,协程,DPDK多个高级知识点。
C/C++Linux服务器开发高级架构师/C++后台开发架构师免费学习地址
【文章福利】另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以点击领取
5. string和其它引用类型的区别
(1). 在string字符串,一开始s1地址指向是ypf,因为s2=s1,所以s2地址也同样指向ypf;当s1再次赋值lmr时,堆中就会开辟出数据lmr,而且ypf没有消失,没有被覆盖。s1地址就指向lmr,s2地址还是原来的ypf。
(2). 在引用类型数组上,一开始arry1和arry2的地址都指向{1,2,3},当给arry1进行数据更改时,由于是引用类型,所以在{1,2,3}上面进行更改,就会对arry2进行覆盖。
代码如下:
{Console.WriteLine("------------------------下面是string和其它引用类型的区别-----------------------------");//string类型的测试string s1 = "ypf";string s2 = s1;Console.WriteLine($"s1={s1},s2={s2}");//修改s1的值s1 = "lmr";Console.WriteLine($"s1={s1},s2={s2}");//其它引用类型的测试int[] arry1 = new int[] { 1, 2, 3 };int[] arry2 = arry1;Console.WriteLine($"默认值:arry1[0]={arry1[0]},arry1[1]={arry1[1]},arry1[2]={arry1[2]}");Console.WriteLine($"默认值:arry2[0]={arry2[0]},arry2[1]={arry2[1]},arry2[2]={arry2[2]}");arry1[2] = 0;Console.WriteLine($"修改后:arry1[0]={arry1[0]},arry1[1]={arry1[1]},arry1[2]={arry1[2]}");Console.WriteLine($"修改后:arry2[0]={arry2[0]},arry2[1]={arry2[1]},arry2[2]={arry2[2]}");}
运行效果:
string变化图如下:
Array类型变化图如下:
6. 拆箱和装箱
装箱是值类型向引用类型转换时发生的,拆箱是引用类型向值类型转换时发生的。装箱是隐式的,拆箱是显式的
代码分享:
{Console.WriteLine("------------------------下面是拆箱和装箱-----------------------------");int a = 123;object obj = a; //装箱(隐式)Console.WriteLine($"装箱后的结果obj={obj}");int b = (int)obj; //拆箱(显式)Console.WriteLine($"拆箱后的结果b={b}");
}
运行效果
7. 总结
(1). 值类型有更好的效率,但不支持多态,适合用作存储数据的载体。而引用类型支持多态,适合用于定义程序的行为。
(2). 引用类型可以派生新的类型,而值类型不能。
二. 深拷贝和浅拷贝
1. 浅拷贝
创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是值类型和string类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址(string类型除外),所以修改其中一个对象,就会影响到另一个对象。
2. 深拷贝
将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象和原对象的修改不会相互影响.
3. 二者区别
最根本的区别在于是否真正获取一个对象的复制实体,而不是引用,假设B复制了A,修改A的时候,看B是否发生变化:
(1).如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)
(2).如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)
简单的来说:
如果拷贝的时候共享被引用的对象就是浅拷贝,如果被引用的对象也拷贝一份出来就是深拷贝。(深拷贝就是说重新new一个对象,然后把之前的那个对象的属性值在重新赋值给这个用户)
4. .Net中实现
(1).浅拷贝通过MemberwiseClone()方法实现.
(2).深拷贝可以通过流的方式和反射的方式来实现,其中流的方式类前必须加 [Serializable], 反射的方式需要考虑的问题很多,嵌套以及各种类型, 此处提供的方法并不完善.
代码分享:
/// <summary>/// 克隆方法(基于浅拷贝)/// 用于实现ICloneable里方法(当然你用来实现深拷贝也可以)/// </summary>/// <returns></returns>public object Clone(){return this.MemberwiseClone();}/// <summary>/// 克隆方法(基于深拷贝)/// 类前面必须加可序列化标志[Serializable]/// </summary>/// <returns></returns>public object DeepClone1(){using (MemoryStream stream = new MemoryStream()){BinaryFormatter bFormatter = new BinaryFormatter();bFormatter.Serialize(stream, this);stream.Seek(0, SeekOrigin.Begin);return bFormatter.Deserialize(stream);}}
基于反射的深拷贝:(仅供参考,不是很完善)
public class Utils{ /// <summary>/// 基于反射的深拷贝/// (存在问题,不是很好用)/// </summary>/// <param name="obj"></param>/// <returns></returns>public static object DeepClone(Object obj){Type type = obj.GetType();//对于没有公共无参构造函数的类型此处会报错object returnObj = Activator.CreateInstance(type);FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);for (int i = 0; i < fields.Length; i++){FieldInfo field = fields[i];var fieldValue = field.GetValue(obj);///值类型,字符串,枚举类型直接把值复制,不存在浅拷贝if (fieldValue.GetType().IsValueType || fieldValue.GetType().Equals(typeof(System.String)) || fieldValue.GetType().IsEnum){field.SetValue(returnObj, fieldValue);}else{field.SetValue(returnObj, DeepClone(fieldValue));}}//属性PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);for (int i = 0; i < properties.Length; i++){PropertyInfo property = properties[i];var propertyValue = property.GetValue(obj);if (propertyValue.GetType().IsValueType || propertyValue.GetType().Equals(typeof(System.String)) || propertyValue.GetType().IsEnum){property.SetValue(returnObj, propertyValue);}else{property.SetValue(returnObj, DeepClone(propertyValue));}}return returnObj;}}
5. 经过测试得出来一个结论
(1).对于浅拷贝:所有值类型和string这个引用类型修改其中一个对象的值,不相互影响; 除了string以外的引用类型都相互影响; 类属于引用类型,修改类中的一个属性值,被拷贝的另一个对象的属性值也会发生变化(与类中的属性值是什么类型没有关系).
(2).对于深拷贝:无论是值类型还是引用类型, 修改其中一个对象的值都不会相互影响。
代码分享:
/// <summary>/// Video视频类/// </summary>[Serializable]public class Video : ICloneable{public string Id { set; get; } // 视频编号public string Content { set; get; } // 视频内容public List<int> ageList { set; get; }public VideoDetails vDetails { get; set; }/// <summary>/// 克隆方法(基于浅拷贝)/// 用于实现ICloneable里方法(当然你用来实现深拷贝也可以)/// </summary>/// <returns></returns>public object Clone(){return this.MemberwiseClone();}/// <summary>/// 克隆方法(基于深拷贝)/// 类前面必须加可序列化标志[Serializable]/// </summary>/// <returns></returns>public object DeepClone1(){using (MemoryStream stream = new MemoryStream()){BinaryFormatter bFormatter = new BinaryFormatter();bFormatter.Serialize(stream, this);stream.Seek(0, SeekOrigin.Begin);return bFormatter.Deserialize(stream);}}}/// <summary>/// 视频详情类/// </summary>[Serializable]public class VideoDetails{public string videoUrl { get; set; }public int videoPic { get; set; }public VideoDetails(string myVideoUrl, int myVideoPic){this.videoUrl = myVideoUrl;this.videoPic = myVideoPic;}}
测试代码
#region 浅拷贝{Console.WriteLine("-------------------------------下面是基于浅拷贝------------------------------------");Video v1 = new Video(){Id = "001",Content = "西游记",ageList = new List<int>() { 000 }, //List是引用类型vDetails = new VideoDetails(@"H:\DesignMode", 1111) //类也是引用类型};Video v2 = (Video)v1.Clone();Console.WriteLine($"v2: Id={v2.Id},Content={v2.Content},ageList[0]={ v1.ageList[0]},Url={v2.vDetails.videoUrl},videoPic={v2.vDetails.videoPic}");//修改v1的值,v2中的属性是否变化要分情况讨论的v1.Content = "水浒传";v1.ageList[0] = 111;v1.vDetails.videoUrl = @"H:\XXXXXXX";v1.vDetails.videoPic = 22222;Console.WriteLine($"v2: Id={v2.Id},Content={v2.Content},ageList[0]={ v2.ageList[0]},Url={v2.vDetails.videoUrl},videoPic={v2.vDetails.videoPic}");}#endregion#region 深拷贝1(流的模式){Console.WriteLine("-------------------------------下面是基于深拷贝1------------------------------------");Video v1 = new Video(){Id = "001",Content = "西游记",ageList = new List<int>() { 000 },vDetails = new VideoDetails(@"H:\DesignMode", 1111)};Video v2 = (Video)v1.DeepClone1();Console.WriteLine($"v2: Id={v2.Id},Content={v2.Content},ageList[0]={ v1.ageList[0]},Url={v2.vDetails.videoUrl},videoPic={v2.vDetails.videoPic}");//修改v1的值,v2不变v1.Content = "水浒传";v1.vDetails.videoUrl = @"H:\XXXXXXX";v1.vDetails.videoPic = 22222;Console.WriteLine($"v2: Id={v2.Id},Content={v2.Content},ageList[0]={ v2.ageList[0]},Url={v2.vDetails.videoUrl},videoPic={v2.vDetails.videoPic}");}#endregion
运行结果:
三. 原型模式详解
1. 背景
在有些系统中,存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂且耗时耗资源,用原型模式生成对象就很高效,就像孙悟空拔下猴毛轻轻一吹就变出很多孙悟空一样简单。
2. 定义和特点
定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。
3. 具体实现
(1). 模式结构
A. 抽象原型类:规定了具体原型对象必须实现的接口,eg:.Net 中的ICloneable。
B. 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
C. 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
结构图如下:
(2). 使用场景
有一块视频,我需要1个一模一样的,并且我还需要1个除了路径不同其它都相同的视频,这个时候可以使用原型模式哦。
(3). 代码实操
相关类:
/// <summary>/// Video视频类/// </summary>[Serializable]public class Video : ICloneable{public string Id { set; get; } // 视频编号public string Content { set; get; } // 视频内容public List<int> ageList { set; get; }public VideoDetails vDetails { get; set; }/// <summary>/// 克隆方法(基于浅拷贝)/// 用于实现ICloneable里方法(当然你用来实现深拷贝也可以)/// </summary>/// <returns></returns>public object Clone(){return this.MemberwiseClone();}/// <summary>/// 克隆方法(基于深拷贝)/// 类前面必须加可序列化标志[Serializable]/// </summary>/// <returns></returns>public object DeepClone1(){using (MemoryStream stream = new MemoryStream()){BinaryFormatter bFormatter = new BinaryFormatter();bFormatter.Serialize(stream, this);stream.Seek(0, SeekOrigin.Begin);return bFormatter.Deserialize(stream);}}}/// <summary>/// 视频详情类/// </summary>[Serializable]public class VideoDetails{public string videoUrl { get; set; }public int videoPic { get; set; }public VideoDetails(string myVideoUrl, int myVideoPic){this.videoUrl = myVideoUrl;this.videoPic = myVideoPic;}}
测试代码:
#region 01-完全相同视频的拷贝{Console.WriteLine("------------------------------- 01-完全相同视频的拷贝------------------------------------");Video v1 = new Video(){Id = "001",Content = "西游记",ageList = new List<int>() { 000 },vDetails = new VideoDetails(@"H:\DesignMode", 1111)};Video v2 = (Video)v1.DeepClone1(); //深拷贝Console.WriteLine($"v1: Id={v1.Id},Content={v1.Content},ageList[0]={ v1.ageList[0]},Url={v1.vDetails.videoUrl},videoPic={v1.vDetails.videoPic}");Console.WriteLine($"v2: Id={v2.Id},Content={v2.Content},ageList[0]={ v2.ageList[0]},Url={v2.vDetails.videoUrl},videoPic={v2.vDetails.videoPic}");}#endregion#region 02-相似视频的拷贝{Console.WriteLine("-------------------------------02-相似视频的拷贝------------------------------------");Video v1 = new Video(){Id = "001",Content = "西游记",ageList = new List<int>() { 000 },vDetails = new VideoDetails(@"H:\DesignMode", 1111)};Video v2 = (Video)v1.DeepClone1(); //深拷贝Console.WriteLine($"v1: Id={v1.Id},Content={v1.Content},ageList[0]={ v1.ageList[0]},Url={v1.vDetails.videoUrl},videoPic={v1.vDetails.videoPic}");//相似视频的拷贝,只需要简单修改即可v2.vDetails.videoUrl = @"F:\newVideo";Console.WriteLine($"v2: Id={v2.Id},Content={v2.Content},ageList[0]={ v2.ageList[0]},Url={v2.vDetails.videoUrl},videoPic={v2.vDetails.videoPic}");}#endregion
运行结果:
4. 使用场景
(1). 对象之间相同或相似,即只是个别的几个属性不同的时候。
(2). 对象的创建过程比较麻烦,但复制比较简单的时候。
原文链接:第三节: 值类型与引用类型、深拷贝与浅拷贝、原型模式详解 - Yaopengfei - 博客园
相关文章:
设计模式-值类型与引用类型、深拷贝与浅拷贝、原型模式详解
一. 值类型和引用类型 1. 前言 (1). 分类 值类型包括:布尔类型、浮点类型(float、double、decimal、byte)、字符类型(char)、整型(int、long、short等)、枚举(entum)、结构体(struct)。 引用类型:数组、字符串(string)、类、接口…...
ssm高校功能教室预约系统java idea maven
本网站所实现的是一个高校功能教室预约系统,该系统严格按照需求分析制作相关模块,并利用所学知识尽力完成,但是本人由于学识浅薄,无法真正做到让该程序可以投入市场使用,仅仅简单实现部分功能,希望日后还能…...
C语言学习笔记-强制类型转换
强制类型转换是通过类型转换运算来实现的。其一般形式为:(类型说明符)(表达式)其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。自动转换是在源类型和目标类型兼容以及目标类型广于源类型时发生一个类型…...
docker数据卷插件
在docker中,对接外部存储我们通常需要docker的数据卷插件。docker中简要可分为两类 docker卷插件和CSI插件,其中docker卷插件分为两个版本,旧版的传统插件(legacy plugin/non-managed plugin)和新版的托管插件(managed plugin)。下面分章节讨…...
第二章-线程(3)
线程一、线程的定义二、线程的实现一、线程的定义 线程: 线程是进程中的一个实体,是系统独立调度和分派的基本单位。 进程是资源的拥有者,线程是系统独立调度和分配的基本单位。 进程与线程的比较: 调度:线程调度快…...
C++学习记录——칠 类和对象(4)
文章目录1、const成员2、取地址及const取地址操作符重载3、构造函数续集1、初始化列表2、explicit关键字4、static成员5、匿名对象6、友元1.友元函数2、友元类7、内部类1、const成员 看一段代码 class A { public:void Print(){cout << _a << endl;} private:int…...
Python-项目实战--飞机大战-碰撞检测(8)
目标了解碰撞检测方法碰撞实现1.了解碰撞检测方法pygame提供了两个非常方便的方法可以实现碰撞检测:pygame.sprite.groupcollide()两个精灵组中所有的精灵的碰撞检测groupcollide(group1, group2, dokill1, dokill2, collided None) -> Sprite_dict如果将dokill…...
T06 成绩排序
查找和排序 题目:输入任意(用户,成绩)序列,可以获得成绩从高到低或从低到高的排列,相同成绩 都按先录入排列在前的规则处理。 示例: jack 70 peter 96 Tom 70 smith 67 从高到低 成…...
【机器学习】Linear and Nonlinear Regression 线性/非线性回归讲解
文章目录一、回归问题概述二、误差项定义三、独立同分布的假设四、似然函数的作用五、参数求解六、梯度下降算法七、参数更新方法八、优化参数设置一、回归问题概述 回归:根据工资和年龄,预测额度为多少 其中,工资和年龄被称为特征࿰…...
PyQt5数据库开发1 4.1 SQL Server 2008 R2如何开启数据库的远程连接
文章目录 前言 步骤/方法 1 使用windows身份登录 2 启用混合登录模式 3 允许远程连接服务器 4 设置sa用户属性 5 配置服务器 6 重新登录 7 配置SSCM 8 确认防火墙设置 注意事项 前言 SQL Server 2008 R2如何开启数据库的远程连接 SQL Server 2008默认是不允许远程连…...
javassm高校学生评教系统的设计与实现idea msyql
伴随着社会以及科学技术的发展,互联网已经渗透在人们的身边,网络慢慢的变成了人们的生活必不可少的一部分,紧接着网络飞速的发展,管理系统这一名词已不陌生,越来越多的学校、公司等机构都会定制一款属于自己个性化的管…...
为什么神经网络做不了2次函数拟合,网上的都是骗人的吗?
环境:tensorflow2 kaggle 这几天突发奇想,用深度学习训练2次函数。先在网上找找相同的资料这方面资料太少了。大多数如下: 。 给我的感觉就是,用深度学习来做,真的很容易。 网上写出代码分析的比较少。但是也找到了…...
【Java】Help notes about JAVA
JAVA语言帮助笔记Java的安装与JDKJava命名规范JAVA的数据类型自动类型转换强制类型转换JAVA的运算符取余运算结果的符号逻辑运算的短路运算三元运算符运算符优先级JAVA的流程控制分支结构JAVA类Scanner类Java的安装与JDK JDK安装网站:https://www.oracle.com/java/…...
2023北京老博会,北京养老展,第十届中国国际老年产业博览会
2023第十届(北京)国际老年产业博览会,将于08月28-30日盛大举办; 2023北京老博会:2023第十届中国(北京)国际老年产业博览会The 2023 tenth China (Beijing) International Aged industry Expo&a…...
C++展开模板参数包、函数参数包-(lambda+折叠表达式)
开门见山 以下代码可展开模板参数包和展开函数参数包。 // lambda折叠表达式(需C17) #include <iostream> using namespace std;// 1.展开模板参数包 template<typename ...T> void Func1() {([]() {cout << typeid(T).name() << endl;}(), ...);// …...
【Spark分布式内存计算框架——Spark Core】7. RDD Checkpoint、外部数据源
第五章 RDD Checkpoint RDD 数据可以持久化,但是持久化/缓存可以把数据放在内存中,虽然是快速的,但是也是最不可靠的;也可以把数据放在磁盘上,也不是完全可靠的!例如磁盘会损坏等。 Checkpoint的产生就是…...
Connext DDSQoS参考
1 QoS策略列表 ConnextDDS 6.1.1版中所有QoS策略的高级视图。 1. QoS策略描述...
【正则表达式】获取html代码文本内所有<script>标签内容
文章目录一. 背景二. 思路与过程1. 正则表达式中需要限定<script>开头与结尾2. 增加标签格式的限定3. 不限制<script>首尾的内部内容4. 中间的内容不能出现闭合的情况三. 结果与代码四. 正则辅助工具一. 背景 之前要对学生提交的html代码进行检查,在获…...
有 9 种springMVC常用注解高频使用,来了解下?
文章目录1、Controller2、RequestMapping2.1 RequestMapping注解有六个属性2.1.1 value2.1.2 method2.1.3 consumes2.1.4 produces2.1.5 params2.1.6 headers2.2 Request Mapping("/helloword/?/aa")的Ant路径,匹配符2.3 Request …...
【ES6】掌握Promise和利用Promise封装ajax
💻 【ES6】掌握Promise和利用Promise封装ajax 🏠专栏:JavaScript 👀个人主页:繁星学编程🍁 🧑个人简介:一个不断提高自我的平凡人🚀 🔊分享方向:目…...
REDIS-持久化方案
我们知道redis是内存数据库,它的数据是存储在内存中的,我们知道内存的一个特点是断电数据就丢失,所以redis提供了持久化功能,可以将内存中的数据状态存储到磁盘里面,避免数据丢失。 Redis持久化有三种方案,…...
五、Java框架之Maven进阶
黑马课程 文章目录1. 分模块开发1.1 分模块开发入门案例示例:抽取domain层示例:抽取dao层1.2 依赖管理2. 聚合和继承2.1 聚合概述聚合实现步骤2.2 继承 dependencyManagement3. 属性管理3.1 依赖版本属性管理3.2 配置文件属性管理(了解&#…...
1.前言【Java面试第三季】
1.前言【Java面试第三季】前言推荐1.前言00_前言闲聊和课程说明本课程介绍目前考核的变化趋势vcr集数和坚持学长谷粉面试题复盘反馈最后前言 2023-2-1 12:30:05 以下内容源自 【尚硅谷Java大厂面试题第3季,跳槽必刷题目必扫技术盲点(周阳主讲࿰…...
06分支限界法
文章目录八数码难题普通BFS算法全局择优算法(A算法,启发式搜索算法)单源最短路径问题装载问题算法思想:队列式分支限界法优先队列式分支限界法布线问题最大团问题批处理作业调度问题分支限界法与回溯法的区别: &#x…...
Docker Compose编排
一、概念1、Docker Compose是什么Docker Compose的前身是Fig,它是一个定义及运行多个Docker容器的工具通过 Compose,不需要使用shell脚本来启动容器,而使用 YAML 文件来配置应用程序需要的所有服务然后使用一个命令,根据 YAML 的文…...
Docker进阶 - 11. Docker Compose 编排服务
注:本文只对一些重要步骤和yml文件进行一些讲解,其他的具体程序没有记录。 目录 1. 原始的微服务工程编排(不使用Compose) 2. 使用Compose编排微服务 2.1 编写 docker-compose.yml 文件 2.2 修改并构建微服务工程镜像 2.3 启动 docker-compose 服务…...
福利篇2——嵌入式岗位笔试面试资料汇总(含大厂笔试面试真题)
前言 汇总嵌入式软件岗位笔试面试资料,供参考。 文章目录 前言一、公司嵌入式面经1、小米1)面试时长2)面试问题2、科大讯飞1)面试时长2)面试题目3、其余公司面经二、嵌入式笔试面试资料(全)三、嵌入式岗位薪资报告四、硬件岗位薪资报告一、公司嵌入式面经 1、小米 1)…...
[ubuntu]LVM磁盘管理
LVM是 Logical Volume Manager(逻辑卷管理)的简写,是Linux环境下对磁盘分区进行管理的一种机制,由Heinz Mauelshagen在Linux 2.4内核上实现。LVM可以实现用户在无需停机的情况下动态调整各个分区大小。1.简介 LVM本质上是一个…...
开源流程引擎Camunda
开源流程引擎Camunda 文章作者:智星 1.简介 Camunda是一个轻量级的商业流程开源平台,是一种基于Java的框架,持久层采用Mybatis,可以内嵌集成到Java应用、SpringBooot应用中,也可以独立运行,其支持BPMN&a…...
【PTA Advanced】1155 Heap Paths(C++)
目录 题目 Input Specification: Output Specification: Sample Input 1: Sample Output 1: Sample Input 2: Sample Output 2: Sample Input 3: Sample Output 3: 思路 代码 题目 In computer science, a heap is a specialized tree-based data structure that s…...
自己免费做网站有什么用/站长之家ping
相信很多人像我一样在学习python,pandas过程中对数据的选取和修改有很大的困惑(也许是深受Matlab)的影响。。。到今天终于完全搞清楚了!!!先手工生出一个数据框吧import numpy as npimport pandas as pddf pd.DataFrame(np.arang…...
网站建设的问题/网站关键词公司
资源下载地址:https://download.csdn.net/download/sheziqiong/87578591 资源下载地址:https://download.csdn.net/download/sheziqiong/87578591 磁盘调度算法的实现 实验要求: 1. 本实验是模拟操作系统的磁盘寻道方式&#x…...
溧阳常州做网站/最新推广方法
Apache web服务器(LAMP架构)(week3_day4)--技术流ken apache介绍 1).世界上使用率最高的网站服务器,最高时可达70%;官方网站:apache.org 2).http 超文本协议 HTML 超文本标记语言 3).URL 统一资源定位符 http://www.si…...
织梦cms网站/百度爱采购平台登录
导读在上周末,开源的Mesa图形库背后的开发团队宣布,基于Linux的操作系统的最终Mesa 18.1版本发布。Mesa 18.1系列在大约18.0分支释出两个月后发布的,可能大多数GNU/Linux发行版目前正在使用,并且已经获得了第四次维护更新。 Mesa …...
网站搜索排名优化怎么做/网络营销推广方法十种
2019独角兽企业重金招聘Python工程师标准>>> Linux mmseg 同义词/复合分词处理: 其基本使用状况为: 词库包含: 南京西路、南京、西路 索引时: 文本中的“南京西路”会被同时索引为以上三者 查询时: 输入南京…...
外贸行业网站建设公司排名/最新新闻事件摘抄
//此方法获取到工程webapp文件夹下 String contexPath request.getSession().getServletContext().getRealPath("/"); //获取IP地址端口号以及项目名称 <% String path request.getContextPath(); String basePath request.getScheme()&q…...