设计模式-值类型与引用类型、深拷贝与浅拷贝、原型模式详解

news2024/11/18 12:35:36

一. 值类型和引用类型

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 - 博客园

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DamiCMS SQL注入分析

2023年将会持续于B站、CSDN等各大平台更新&#xff0c;可加入粉丝群与博主交流:838681355&#xff0c;为了老板大G共同努力。 一、入口文件(单入口文件模式) 看一下Index.php文件代码&#xff1a;引入了php_safe.php文件 查看一下php_safe.php防御文件&#xff1a; 对变量e…

2019_41 考研408

2019年(单链表)41.(13分)设线性表采用带头结点的单链表保存&#xff0c;链表中的结点定义如下:typedef struct node {int data;struct node* next;}NODE;请设计一个空间复杂度为O(1)且时间上尽可能高效的算法&#xff0c;重新排列L中的各结点&#xff0c;得到线性表L(q,a,,a,an…

【正则表达式】获取html代码文本内所有<script>标签内容

文章目录一. 背景二. 思路与过程1. 正则表达式中需要限定<script>开头与结尾2. 增加标签格式的限定3. 不限制<script>首尾的内部内容4. 中间的内容不能出现闭合的情况三. 结果与代码四. 正则辅助工具一. 背景 之前要对学生提交的html代码进行检查&#xff0c;在获…

牛客小白月赛66

牛客小白月赛66_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)冒着期末挂科的风险打了打&#xff0c;缓解了一下网瘾&#xff0c;感觉还行最近为了期末鸽了很多期的div3&#xff0c;一学期末就手痒想训&#xff0c;感觉再不打人要没了&#xff0c;结果…

linux性能优化-内存回收

linux文件页、脏页、匿名页 缓存和缓冲区&#xff0c;就属于可回收内存。它们在内存管理中&#xff0c;通常被叫做文件页&#xff08;File-backed Page&#xff09;。通过内存映射获取的文件映射页&#xff0c;也是一种常见的文件页。它也可以被释放掉&#xff0c;下次再访问的…

DOM编程-显示网页时钟

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>显示网页时钟</title> </head> <body bgcolor"antiquewhite"> <script type"text/javascrip…

剑指offer(中等)

目录 二维数组中的查找 重建二叉树 矩阵中的路径 剪绳子 剪绳子② 数值的整数次方 表示数值的字符串 树的子结构 栈的压入、弹出序列 从上到下打印二叉树① 从上到下打印二叉树③ 二叉搜索树的后序遍历序列 二叉树中和为某一值的路径 复杂链表的复制 二叉搜索树与…

C++复习笔记8

泛型编程&#xff1a;编写的是与类型无关的通用代码&#xff0c;是代码复用的一种手段&#xff0c;模板是泛型编程的基础。 1.函数模板&#xff1a;类型参数化&#xff0c;增加代码复用性。例如对于swap函数&#xff0c;不同类型之间进行交换都需要进行重载&#xff0c;但是函数…

K_A12_003 基于STM32等单片机采集光敏二极管模块参数 串口与OLED0.96双显示

K_A12_003 基于STM32等单片机采集光敏二极管模块参数 串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RC光敏二极管模块1.2、STM32F103C8T6光敏二极管模块五、基础知识…

面向 3DoF+的虚拟视图合成算法研究(陈 莹)

面向 3DoF的虚拟视图合成算法研究&#xff08;陈 莹&#xff09;论文贡献多视点联合的虚拟视图合成算法视图合成中多视点伪影消除算法面向虚拟视图合成算法的 3DoF系统基于深度的虚拟视图合成算法视点映射&#xff08;3D-Warping&#xff09;三维空间映射变换&#xff08;3D-Wa…

TYPE-C 手机/电脑同时充电直播 视频采集卡方案

Type-C音视频采集卡有什么作用&#xff1f; ​能够帮助专业用户和游戏玩家迅速搭建简单、高性价比的音视频解决方案。可将新闻联播、体育竞赛、视频教学课程、网络视频等&#xff0c;通过HDMI高清视频信号分段或整体录制在本地计算机共享使用。支持多种带HDMI接口的游戏机设备…

生物素-琥珀酰亚胺酯Biotin-NHS;CAS号:35013-72-0;可对溶液中的抗体,蛋白质和任何其他含伯胺的大分子进行简单有效的生物素标记。

结构式&#xff1a; ​ 生物素-琥珀酰亚胺酯Biotin NHS CAS号&#xff1a;35013-72-0 英文名称&#xff1a;Biotin-NHS 中文名称&#xff1a;D-生物素 N-羟基琥珀酰亚胺酯&#xff1b;生物素&#xff0d;琥珀酰亚胺酯 CAS号&#xff1a;35013-72-0 密度&#xff1a;1.50.1 …

vue项目第二天

项目中使用element-ui库中文网https://element.eleme.cn/#/zh-CN安装命令npm install element-ui安装按需加载babel插件npm install babel-plugin-component -Dnpm i //可以通过npm i 的指令让配置刷新重新配置一下项目中使用element-ui组件抽离文件中按需使用element ui &…

sqoop 数据同步方案理解+问题解决

sqoop数据同步——问题与解决方案 1、sqoop导出oracle数据&#xff0c;数据源无法选择表空间&#xff0c;只能指定默认表空间的表。 方案&#xff1a;不指定数据源的表名&#xff0c;而是使用–query&#xff0c;利用sql语句把数据带出来。 例&#xff1a;--query "SELE…

【游戏逆向】内存构造发包结构体实现协议发送简单代码

捕捉到游戏的封包以后 我们可以对其进行发送来实现功能 基本有两种方式 第一种直接调用明文发包函数 第二种构造明文封包以后&#xff0c;再调用加密算法&#xff0c;然后通过send等发包函数对其进行发送 如果能够把加密算法分析透彻的话&#xff0c;第二种方式是最好的 …

element Ui树状图控件 spring boot Vue 实现角色授权功能

目录 前言&#xff1a; 二. element ui 2.1官网提供的核心代码 三.表结构 ​编辑 四.后端 4.1功能分析 4.2实体类 4.3 查询全部权限显示的结果 4.2修改角色权限的后台方法 五.vue 5.0代码总览 5.1树形图 5.2所需要的绑定数据 5.3所需方法 前言&#xff1a; 先上图…

微搭低代码从入门到精通04-创建自定义应用

微搭中的应用分为两类&#xff0c;模型应用和自定义应用。上一篇我们介绍了模型应用的创建方法&#xff0c;本篇我们介绍一下自定义应用的创建方法。 登录微搭的控制台&#xff0c;在左侧的菜单里点击应用&#xff0c;点击新建应用&#xff0c;选择新建自定义应用 输入应用的名…

logstash毫秒时间戳转日期以及使用业务日志时间戳替换原始@timestamp

文章目录问题解决方式参考问题 在使用Kibana观察日志排查问题时发现存在很多组的timestamp 数据一样&#xff0c;如下所示 详细观察内部数据发现其中日志数据有一个timestamp字段保存的是业务日志的毫秒级时间戳&#xff0c;经过和timestamp数据对比发现二者的时间不匹配。经…

1630_GNU的二进制分析工具nm简单使用探索

全部学习汇总&#xff1a; GreyZhang/toolbox: 常用的工具使用查询&#xff0c;非教程&#xff0c;仅作为自我参考&#xff01; (github.com) GNU有一套二进制的分析工具&#xff0c;之前是用过objdump的&#xff0c;但是也没有系统掌握。如果做底层软件的设计&#xff0c;这些…

OpenWrt路由器设置域名动态解析手把手教程

文章目录0、前言1、准备工作2、详细步骤2.1、OpenWrt路由器软件包安装2.2、防火墙放行入站数据&#xff08;修改为“接受”并保存应用&#xff09;2.3、域名解析服务商对域名的解析设置2.4、路由器中动态域名插件的设置0、前言 因为一直用着内网穿透&#xff08;zerotier或者是…