Unity 数据持久化【PlayerPrefs】

1、数据持久化

在这里插入图片描述

文章目录

  • 1、数据持久化
    • PlayerPrefs基本方法
      • 1、PlayerPrefs概念
      • 2、存储相关
      • 3、读取相关
      • 4、删除数据
      • 思考 信息的存储和读取
    • PlayerPrefs存储位置
      • 1、PlayerPrefs存储的数据在哪个位置
      • 2、PlayerPrefs 数据唯一性
      • 思考 排行榜功能
  • 2、Playerprefs实践
    • 1、必备知识点-反射知识小补充
    • 2、需求分析 Playerprefs数据管理类创建
    • 3、反射存储数据-常用成员、List成员、Dic成员、自定义类成员
    • 4、反射读取数据-常用成员、List成员、Dic成员、自定义类成员
    • 4、加密思路
    • 5、生成资源包

概念

将【变量数据】在内存和硬盘之间的存储或读取

内容

PlayerPrefs的基本方法
PlayerPrefs在不同平台的存储位置
利用反射结合PlayerPrets制作通用存诸工具

PlayerPrefs基本方法

1、PlayerPrefs概念

是unity提供的可以用于存储读取玩家数据的公共类

2、存储相关

PlaverPrefs的数据存储类似于键值对存储一个键对应一个值
提供了存储3种数据的方法int float string
键:string类型
值:int float string对应3API 
    PlayerPrefs.SetInt("myAge", 18);
    PlayerPrefs.SetFloat("myHeight", 183.5f);
    PlayerPrefs.SetString("myName", "姓名");
    PlayerPrefs.Save();

	bool sex = true; //sex若为true存1,sex若为flase则存1
	PlayerPrefs.SetInt("sex", sex ? 1 : 0);

如果用同一个键名,会进行覆盖
	PlayerPrefs.SetFloat("myAge", 18.3f);
	//键名是唯一的

3、读取相关

Set之后也能读取信息,读取顺序为:内存 > 硬盘

1int
    int age = PlayerPrefs.GetInt("myAge");
    print(age); //0 被覆盖
    age = PlayerPrefs.GetInt("myAge", 18); //18 设置的初始默认值
    print(age);

2float
    float height = PlayerPrefs.GetFloat("myHeight", 100f);
	print(height);

3string
    string name = PlayerPrefs.GetString("myName");
	print(name);

是否存在的键名
    if (PlayerPrefs.HasKey("myName"))
    {
    	print("存在myName对应的键值对数据");
    }

4、删除数据

删除指定键值对
    PlayerPrefs.DeleteKey("myAge");

删除所有
    PlayerPrefs.DeleteAll();

思考 信息的存储和读取

玩家信息类,装备信息类
用List存储装备信息
添加标识,存储多个玩家信息
将信息存储读取

using System.Collections.Generic;
using UnityEngine;

public class Item
{
    public int id;
    public int num;
}
public class Player
{
    public string name;
    public int age;
    public int atk;
    public int def;

    public List<Item> itemList;
    
    //用于存储或读取的标识
	private string keyName;

    /// <summary>
    /// 存储数据
    /// </summary>
    public void Save()
    {
        PlayerPrefs.SetString(keyName + "_name", name);
        PlayerPrefs.SetInt(keyName + "_age", age);
        PlayerPrefs.SetInt(keyName + "_atk", atk);
        PlayerPrefs.SetInt(keyName + "_def", def);

        PlayerPrefs.SetInt(keyName + "_ItemNum", itemList.Count);
        for (int i = 0; i < itemList.Count; i++)
        {
            PlayerPrefs.SetInt(keyName + "_itemID" + i, itemList[i].id);
            PlayerPrefs.SetInt(keyName + "_itemNum" + i, itemList[i].num);
        }

        PlayerPrefs.Save();
    }
    /// <summary>
    /// 读取数据
    /// </summary>
    public void Load(string keyName)
    {
        //记录传入的标识
        this.keyName = keyName;

        name = PlayerPrefs.GetString(keyName + "_name", "未命名");
        age = PlayerPrefs.GetInt(keyName + "_age", 18);
        atk = PlayerPrefs.GetInt(keyName + "_atk", 20);
        def = PlayerPrefs.GetInt(keyName + "_def", 2);

        //获取数量
        int num = PlayerPrefs.GetInt(keyName + "_ItemNum", 0);
        //初始化容器
        itemList = new List<Item>();
        Item item;
        for (int i = 0; i < num; i++)
        {
            item = new Item();
            item.id = PlayerPrefs.GetInt(keyName + "_itemID" + i);
            item.num = PlayerPrefs.GetInt(keyName + "_itemNum" + i);
            itemList.Add(item);
        }
    }
}
public class Test1_Exercises : MonoBehaviour
{
    void Start()
    {
        Player p = new Player();
        p.Load();
        //print(p.name);
        //print(p.age);
        //print(p.atk);
        //print(p.def);

        print("不同类型道具数量:"+p.itemList.Count);
        for (int i = 0; i < p.itemList.Count; i++)
        {
            print("道具id:" + p.itemList[i].id);
            print("道具数量:" + p.itemList[i].num);
        }

        Item item = new Item();
        item.id = 1;
        item.num = 99;
        p.itemList.Add(item);

        item = new Item();
        item.id = 2;
        item.num = 99;
        p.itemList.Add(item);

        p.Save();
        
        //其他玩家
        Player p2 = new Player();
        p2.Load("Player2");
        p2.Save();
    }
}

PlayerPrefs存储位置

1、PlayerPrefs存储的数据在哪个位置

不同平台存储位置不同

Windows
    PlayerPrefs 存储在
    HKCU\Software\[公司名称]\[产品名称]项下的注册表中
    其中公司和产品名称是在"Project Settings"中设置的名称

    运行 regedit
    HKEY_CURRENT_USER
        SOFTWARE
            Unity
                UnityEditor
                    公司名称
                    产品名称
Android
	/data/data/应用程序包名/shared_prefs/pkg-name.xml
IOS
	/Library/Preferences/[应用ID].plist

2、PlayerPrefs 数据唯一性

PlayerPrefs 中不同数据的唯一性
由key决定,不同key决定了不同的数据
同一项目中,如果不同数据key相同,会造成数据丢失

思考 排行榜功能

排行榜主要记录玩家名,玩家得分,玩家通关时间
using System.Collections.Generic;
using UnityEngine;

public class RankListInfo
{
    public List<RankInfo> rankList;

    public RankListInfo() { Load(); }

    public void Add(string name, int score, int time)
    {
        rankList.Add(new RankInfo(name, score, time));
    }

    public void Save()
    {
        PlayerPrefs.SetInt("rankListNum", rankList.Count);
        for (int i = 0; i < rankList.Count; i++)
        {
            RankInfo info = rankList[i];
            PlayerPrefs.SetString("rankInfo" + i, info.playerName);
            PlayerPrefs.SetInt("rankInfo" + i, info.playerScore);
            PlayerPrefs.SetInt("rankInfo" + i, info.playerTime);
        }
    }
    private void Load()
    {
        int num = PlayerPrefs.GetInt("rankListNum", 0);
        rankList = new List<RankInfo>();
        for (int i = 0;i < num;i++)
        {
            RankInfo info = new RankInfo(PlayerPrefs.GetString("rankInfo" + i), PlayerPrefs.GetInt("rankScore" + i), PlayerPrefs.GetInt("rankTIme" + i));
            rankList.Add(info);
        }
    }
}

public class RankInfo
{
    public string playerName;
    public int playerScore;
    public int playerTime;

    public RankInfo(string name, int score, int time)
    {
        playerName = name;
        playerScore = score;
        playerTime = time;
    }
}
public class Test2_Exercises : MonoBehaviour
{
    void Start()
    {
        RankListInfo rankList = new RankListInfo();
        print(rankList.rankList.Count);
        for (int i = 0; i < rankList.rankList.Count; i++)
        {
            print("姓名" + rankList.rankList[i].playerName);
            print("分数" + rankList.rankList[i].playerScore);
            print("时间" + rankList.rankList[i].playerTime);

        }

        rankList.Add("玩家", 100, 88);
        rankList.Save();
    }
}

2、Playerprefs实践

1、必备知识点-反射知识小补充

Type	用于获取类的所有信息:字段、属性、方法 等
Assembly	用于获取程序集,通过程序集获取Type
Activator	用于快速实例化对象
    
using System;
using System.Collections.Generic;
using UnityEngine;
public class Father { }
public class Son : Father { }
public class Reflection : MonoBehaviour
{
    void Start()
    {
        1、判断A对象是否让B对象分配空间
        //父类装子类
        //是否可以从某一个类型的对象为自己分配空间
        Type fatherType = typeof(Father);
        Type sonType = typeof(Son);
        //调用者通过IsAssignableFrom方法进行判断,是否可以通过传入的类型为自己分配空间
        if (fatherType.IsAssignableFrom(sonType))
        {
            print("可以分配");
            Father f = Activator.CreateInstance(sonType) as Father;
            print(f);
        }
        else
        {
            print("不能分配");
        }

        2、通过反射获取泛型类型
        List<string> list = new List<string>();
        Type listType = list.GetType();
        //通过得到泛型类的类型,得到泛型具体的类型
        Type[] types = listType.GetGenericArguments();
        print(types[0]);

        Dictionary<string,float> dict = new Dictionary<string,float>();
        Type dicType = dict.GetType();
        types = dicType.GetGenericArguments();
        print(types[0]);
        print(types[1]);
    }
}

2、需求分析 Playerprefs数据管理类创建

Test

using System.Collections.Generic;
using UnityEngine;

public class PlayerInfo
{
    public int age = 10;
    public string name = "姓名";
    public float height = 188.5f;
    public bool sex = true;

    public List<int> list = new List<int>() { 1, 2, 3, 4, };

    public Dictionary<int, string> dic = new Dictionary<int, string>()
    {
        {1,"123" },
        {1,"123" }
    };

    public ItemInfo itemInfo = new ItemInfo(3, 33);
    public List<ItemInfo> items = new List<ItemInfo>() { new ItemInfo(1, 99), new ItemInfo(2, 22) };
    public Dictionary<int, ItemInfo> itemDic = new Dictionary<int, ItemInfo>() { { 4, new ItemInfo(4, 44) }, { 5, new ItemInfo(5, 55) } };
}
public class ItemInfo
{
    public int num;
    public int id;

    public ItemInfo() { }

    public ItemInfo(int id, int num)
    {
        this.id = id;
        this.num = num;
    }
}
public class Test : MonoBehaviour
{
    void Start()
    {
        PlayerInfo p = new PlayerInfo();
        PlayerPrefsDataMgr.Instance.SaveData(p, "Player1");
    }
}

3、反射存储数据-常用成员、List成员、Dic成员、自定义类成员

using System;
using System.Collections;
using System.Reflection;
using UnityEngine;
/// <summary>
/// PlayerPrefs数据管理类,同一管理数据的存储和读取
/// </summary>
public class PlayerPrefsDataMgr
{
    private static PlayerPrefsDataMgr instance = new PlayerPrefsDataMgr();
    public static PlayerPrefsDataMgr Instance
    {
        get { return instance; }
    }
    private PlayerPrefsDataMgr() { }
    /// <summary>
    /// 存储数据
    /// </summary>
    /// <param name="data">数据对象</param>
    /// <param name="keyName">数据对象的唯一key,自己控制</param>
    public void SaveData(object data, string keyName)
    {
        //通过Type得到传入数据对象的所有字段,结合PlayerPrefs来存储

        //1、获取传入数据对象的所有字段


        Type dataType = data.GetType();
        //得到所有字段
        FieldInfo[] infos = dataType.GetFields();
        //2、自己定义一个key的规则,进行数据存储
        //keyName_数据类型_字段类型_字段名
        //3、遍历字段,进行数据存储
        string saveKeyNmae = "";
        FieldInfo info;
        for (int i = 0; i < infos.Length; i++)
        {
            //对每一个字段,进行数据存储
            //得到具体的字段信息
            info = infos[i];
            //通过FieldInfo可以直接获取到字段的类型和字段的名字
            //    字段的类型 info.FieldType.Name
            //    字段的名字 info.Name

            //根据key生成key
            //    Player1_PlayerInfo_Int32_age
            saveKeyNmae = keyName + "_" + dataType.Name + "_" + info.FieldType.Name + "_" + info.Name;
            //获取值
            //info.GetValue(data)
            SaveData(info.GetValue(data), saveKeyNmae);
        }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="value">类型</param>
    /// <param name="keyName">存储的key名称</param>
    private void SaveValue(object value, string keyName)
    {
        Type fieldType = value.GetType();
        if (fieldType == typeof(int))
        {
            Debug.Log("存储int" + keyName);
            PlayerPrefs.SetInt(keyName, (int)value);
        }
        else if (fieldType == typeof(float))
        {
            Debug.Log("存储float" + keyName);
            PlayerPrefs.SetFloat(keyName, (float)value);
        }
        else if (fieldType == typeof(string))
        {
            Debug.Log("存储string" + keyName);
            PlayerPrefs.SetString(keyName, value.ToString());
        }
        else if (fieldType == typeof(bool))
        {
            Debug.Log("存储bool" + keyName);
            PlayerPrefs.SetInt(keyName, (bool)value ? 1 : 0);
        }
        //通过IList判断这个类是否为List
        else if (typeof(IList).IsAssignableFrom(fieldType))
        {
            Debug.Log("存储List" + keyName);
            IList list = value as IList;
            //存储List数量
            PlayerPrefs.SetInt(keyName, list.Count);
            int index = 0;
            foreach (object obj in list)
            {
                SaveValue(obj, keyName + index);
                index++;
            }
        }
        else if (typeof(IDictionary).IsAssignableFrom(fieldType))
        {
            Debug.Log("存储Dictionary" + keyName);
            IDictionary dic = value as IDictionary;
            //存储字典长度
            PlayerPrefs.SetInt(keyName,dic.Count);
            //遍历存储Dic里面的具体值
            int index = 0;
            foreach (object key in dic.Keys)
            {
                SaveValue(key, keyName + "_key_" + index);
                SaveValue(dic[key], keyName + "_value_" + index);
                index++;
            }
        }
        else
        {
            SaveData(value, keyName);
        }

    }

    /// <summary>
    /// 读取数据
    /// </summary>
    /// <param name="type">想要读取数据的数据类型</param>
    /// <param name="keyName">数据对象的唯一key</param>
    /// <returns></returns>
    public object LoadData(Type type, string keyName)
    {
        //只需要传入一个Type,typeof(Player),就可以在内部动态创建一个对象返回出来

        //根据传入的类型和keyName,依据存储数据时key的拼接规则来进行数据的获取赋值,然后返回出去
        return null;
    }
}

4、反射读取数据-常用成员、List成员、Dic成员、自定义类成员

test

using System.Collections.Generic;
using UnityEngine;

public class PlayerInfo
{
    public int age;
    public string name = "姓名";
    public float height;
    public bool sex;

    public List<int> list;

    public Dictionary<int, string> dic;

    public ItemInfo itemInfo;
    public List<ItemInfo> itemList;
    public Dictionary<int, ItemInfo> itemDic;
}
public class ItemInfo
{
    public int num;
    public int id;

    public ItemInfo() { }

    public ItemInfo(int id, int num)
    {
        this.id = id;
        this.num = num;
    }
}
public class Test : MonoBehaviour
{
    void Start()
    {
        //PlayerInfo p = new PlayerInfo();
        将数据对象的信息存储到硬盘
        //PlayerPrefsDataMgr.Instance.SaveData(p, "Player1");
        //PlayerPrefs.DeleteAll();

        //读取数据
        PlayerInfo p = PlayerPrefsDataMgr.Instance.LoadData(typeof(PlayerInfo), "Player1") as PlayerInfo;

        //游戏逻辑
        p.age = 18;
        p.name = "姓名";
        p.height = 183;
        p.sex = true;

        p.itemList.Add(new ItemInfo(1,99));
        p.itemList.Add(new ItemInfo(2,22));

        p.itemDic.Add(3, new ItemInfo(3, 33));
        p.itemDic.Add(4, new ItemInfo(4, 44));

        //游戏数据存储
        PlayerPrefsDataMgr.Instance.SaveData(p, "player1");
    }
}

PlayerPrefsDataMgr

using System;
using System.Collections;
using System.Reflection;
using UnityEngine;
/// <summary>
/// PlayerPrefs数据管理类,同一管理数据的存储和读取
/// </summary>
public class PlayerPrefsDataMgr
{
    private static PlayerPrefsDataMgr instance = new PlayerPrefsDataMgr();
    public static PlayerPrefsDataMgr Instance
    {
        get { return instance; }
    }
    private PlayerPrefsDataMgr() { }
    /// <summary>
    /// 存储数据
    /// </summary>
    /// <param name="data">数据对象</param>
    /// <param name="keyName">数据对象的唯一key,自己控制</param>
    public void SaveData(object data, string keyName)
    {
        //通过Type得到传入数据对象的所有字段,结合PlayerPrefs来存储

        //1、获取传入数据对象的所有字段


        Type dataType = data.GetType();
        //得到所有字段
        FieldInfo[] infos = dataType.GetFields();
        //2、自己定义一个key的规则,进行数据存储
        //keyName_数据类型_字段类型_字段名
        //3、遍历字段,进行数据存储
        string saveKeyNmae = "";
        FieldInfo info;
        for (int i = 0; i < infos.Length; i++)
        {
            //对每一个字段,进行数据存储
            //得到具体的字段信息
            info = infos[i];
            //通过FieldInfo可以直接获取到字段的类型和字段的名字
            //    字段的类型 info.FieldType.Name
            //    字段的名字 info.Name

            //根据key生成key
            //    Player1_PlayerInfo_Int32_age
            saveKeyNmae = keyName + "_" + dataType.Name + "_" + info.FieldType.Name + "_" + info.Name;
            //获取值
            //info.GetValue(data)
            SaveData(info.GetValue(data), saveKeyNmae);
        }
        PlayerPrefs.Save();
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="value">类型</param>
    /// <param name="keyName">存储的key名称</param>
    private void SaveValue(object value, string keyName)
    {
        Type fieldType = value.GetType();
        if (fieldType == typeof(int))
        {
            Debug.Log("存储int" + keyName);
            PlayerPrefs.SetInt(keyName, (int)value);
        }
        else if (fieldType == typeof(float))
        {
            Debug.Log("存储float" + keyName);
            PlayerPrefs.SetFloat(keyName, (float)value);
        }
        else if (fieldType == typeof(string))
        {
            Debug.Log("存储string" + keyName);
            PlayerPrefs.SetString(keyName, value.ToString());
        }
        else if (fieldType == typeof(bool))
        {
            Debug.Log("存储bool" + keyName);
            PlayerPrefs.SetInt(keyName, (bool)value ? 1 : 0);
        }
        //通过IList判断这个类是否为List
        else if (typeof(IList).IsAssignableFrom(fieldType))
        {
            Debug.Log("存储List" + keyName);
            IList list = value as IList;
            //存储List数量
            PlayerPrefs.SetInt(keyName, list.Count);
            int index = 0;
            foreach (object obj in list)
            {
                SaveValue(obj, keyName + index);
                index++;
            }
        }
        else if (typeof(IDictionary).IsAssignableFrom(fieldType))
        {
            Debug.Log("存储Dictionary" + keyName);
            IDictionary dic = value as IDictionary;
            //存储字典长度
            PlayerPrefs.SetInt(keyName,dic.Count);
            //遍历存储Dic里面的具体值
            int index = 0;
            foreach (object key in dic.Keys)
            {
                SaveValue(key, keyName + "_key_" + index);
                SaveValue(dic[key], keyName + "_value_" + index);
                index++;
            }
        }
        else
        {
            SaveData(value, keyName);
        }

    }

    /// <summary>
    /// 读取数据
    /// </summary>
    /// <param name="type">想要读取数据的数据类型</param>
    /// <param name="keyName">数据对象的唯一key</param>
    /// <returns></returns>
    public object LoadData(Type type, string keyName)
    {
        //只需要传入一个Type,typeof(Player),就可以在内部动态创建一个对象返回出来

        //根据传入的类型和keyName,依据存储数据时key的拼接规则来进行数据的获取赋值,然后返回出去
        
        //根据传入的Type创建一个对象,用于存储数据
        object data = Activator.CreateInstance(type);
        //要在这个new出来的对象中存储数据
        FieldInfo[] infos = type.GetFields();
        //用于拼接key的字符串
        string loadKeyName = "";
        //用于存储单个字段信息的对象
        FieldInfo info;
        for (int i = 0; i < infos.Length; i++)
        {
            info = infos[i];
            loadKeyName = keyName + "_" + type.Name + "_" + info.FieldType.Name + "_" + info.Name;
            //填充数据到data中
            info.SetValue(data, LoadValue(info.FieldType, loadKeyName));
        }

        return data;
    }
    /// <summary>
    /// 得到单个数据的方法
    /// </summary>
    /// <param name="fieldType">字段类型,用于判断API的读取</param>
    /// <param name="keyName">唯一key,获取Value</param>
    /// <returns></returns>
    private object LoadValue(Type fieldType,string keyName)
    {
        //根据字段类型
        if (fieldType == typeof(int))
        {
            return PlayerPrefs.GetInt(keyName, 0);
        }
        else if (fieldType == typeof(float))
        {
            return PlayerPrefs.GetFloat(keyName, 0);
        }
        else if (fieldType == typeof(string))
        {
            return PlayerPrefs.GetString(keyName, "");

        }
        else if(fieldType == typeof(bool))
        {
            return PlayerPrefs.GetInt(keyName, 0) == 1 ? true : false;
        }
        else if (typeof(IList).IsAssignableFrom(fieldType))
        {
            //得到List长度
            int count = PlayerPrefs.GetInt(keyName, 0);
            //实例化一个List对象类进行赋值
            IList list = Activator.CreateInstance(fieldType) as IList;
            for (int i = 0; i < count; i++)
            {
                //得到List中泛型的类型
                list.Add(LoadValue(fieldType.GetGenericArguments()[0], keyName + i));
            }
            return list;
        }
        else if (typeof(IDictionary).IsAssignableFrom(fieldType))
        {
            //得到字典dictionary的长度
            int count = PlayerPrefs.GetInt(keyName, 0);
            //实例化字典对象
            IDictionary dic = Activator.CreateInstance(fieldType) as IDictionary;
            Type[] kvType = fieldType.GetGenericArguments();
            for (int i = 0; i < count; i++)
            {
                dic.Add(LoadValue(kvType[0], keyName + "_key_" + i), LoadValue(kvType[1], keyName + "_value_" + i));
            }
            return dic;
        }
        else
        {
            return LoadData(fieldType, keyName);
        }
    }
}

4、加密思路

//为int数据加密
int rValue = (int)value;
rValue += 10;
PlayerPrefs.SetInt(keyName, rValue);
//解密
return PlayerPrefs.GetInt(keyName, 0) - 10;

5、生成资源包

Export Package

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文化创新与社交媒体:探索Facebook的足迹

在过去的十多年里&#xff0c;Facebook从一个简单的校园社交网络发展成为全球最大的社交媒体平台之一。它不仅改变了人们的沟通方式&#xff0c;更在许多方面推动了文化的创新和变革。本文将深入探索Facebook如何通过其平台的演进和功能创新&#xff0c;成为文化创新的重要推动…

SpringBoot实战(二十八)集成 Collabora Online 实现在线编辑

目录 一、什么是 Collabora Online?二、Docker 下载并启动 CODE2.1 拉取镜像2.2 启动镜像2.3 访问界面2.4 补充:nextcloud 的镜像启动三、SpringBoot 实现 WOPI 服务3.1 什么是WOPI?3.2 Spring Boot 简单实现3.3 另一种实现方式3.4 总结四、补充:coolwsd.xml 核心配置介绍c…

SpringBoot集成beetl模板快速入门

在pom文件引入maven依赖 <dependency><groupId>com.ibeetl</groupId><artifactId>beetl-framework-starter</artifactId><version>1.1.81.RELEASE</version></dependency>写一个controller /*** author * create * descripti…

Java开发-实际工作经验和技巧-0005-使用MapStruct进行两个实体类的转换,出现所有属性值都为null的情况

Java开发-实际工作经验和技巧-0005-使用MapStruct进行两个实体类的转换,出现所有属性值都为null的情况 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;Code…

推荐系统三十六式学习笔记:原理篇.MAB问题|16|简单却有效的Bandit算法

目录 推荐就是选择MAB问题Bandit算法1.汤普森采样算法2.UCB算法3.Epsilon贪婪算法4.效果对比 冷启动总结 推荐系统的使命就是建立用户和物品之间的连接。建立连接可以理解成;为用户匹配到最佳的物品&#xff1b;但也有另一个理解就是&#xff0c;在某个时间某个位置为用户选择最…

Redis 管道(Pipeline)是什么?有什么用?

目录 1. redis 客户端-服务端模型的不足之处 2. redis 管道是什么&#xff1f;有什么好处&#xff1f; 3. 管道的使用场景 4. 管道使用的注意事项 1. redis 客户端-服务端模型的不足之处 众所周知&#xff0c;redis 是一个客户端-服务端的模型设计&#xff0c;客户端向服务…

Zoom视颊会议软件使用

GPT-3.5 (OpenAI) Zoom是一款极受欢迎的视频会议软件。使用Zoom可以方便地进行视频会议、远程授课、在线研讨会等活动。以下是Zoom的使用步骤&#xff1a; 1. 下载Zoom客户端 可以在Zoom官网上下载对应平台的Zoom客户端。下载并完成安装后&#xff0c;双击打开客户端。 2. 创建…

大数据开发中如何计算用户留存及SQL示例

在大数据开发领域&#xff0c;用户留存是一个关键指标&#xff0c;它反映了产品吸引并保留用户的能力。 留存率的计算不仅有助于评估产品的健康状况&#xff0c;还能为产品优化和市场策略提供重要依据。 本文将详细介绍如何在大数据开发中计算用户留存&#xff0c;并附带具体…

大数据之路 读书笔记 Day2

大数据之路 读书笔记 Day2 日志采集——浏览器的页面采集 一、分类 #mermaid-svg-8c9sRexRDdSB9pWA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-8c9sRexRDdSB9pWA .error-icon{fill:#552222;}#mermaid-svg-8c9…

【论文解读】CVPR2024:DUSt3R: Geometric 3D Vision Made Easy

论文“”https://openaccess.thecvf.com/content/CVPR2024/papers/Wang_DUSt3R_Geometric_3D_Vision_Made_Easy_CVPR_2024_paper.pdf 代码&#xff1a;GitHub - naver/dust3r: DUSt3R: Geometric 3D Vision Made Easy DUSt3R是一种旨在简化几何3D视觉任务的新框架。作者着重于…

002-关于Geogebra软件的介绍及与MatLab的区别

为什么要学Geogebra&#xff1f; 因为和MatLab的科学计算相比&#xff0c;GeoGebra重点突出教学展示&#xff0c;对于教师、学生人群来讲再合适不过了&#xff0c;尤其是可以融入到PPT里边呈现交互式动画&#xff0c;想想听众的表情&#xff01;这不就弥补了看到PPT播放数学公…

邮箱smtp发送邮件失败的原因?怎么做排查?

邮箱smtp发送邮件失败的解决方法&#xff1f;SMTP错误代码解析&#xff01; 在使用SMTP发送邮件时&#xff0c;我们时常会遇到各种问题&#xff0c;导致邮件发送失败。了解这些问题的根本原因可以帮助我们更好地解决它们。AoKSend将详细探讨邮箱SMTP发送邮件失败的几大原因&am…

在 WebGPU 与 Vulkan 之间做出正确的选择(Making the Right Choice between WebGPU vs Vulkan)

在 WebGPU 与 Vulkan 之间做出正确的选择&#xff08;Making the Right Choice between WebGPU vs Vulkan&#xff09; WebGPU 和 Vulkan 之间的主要区别WebGPU 是什么&#xff1f;它适合谁使用&#xff1f;Vulkan 是什么&#xff1f;它适合谁使用&#xff1f;WebGPU 和 Vulkan…

mac 上 Docker Desktop的免费开源的替代工具Colima

当谈到在macOS上运行容器时&#xff0c;Docker长期以来一直是首选。但是&#xff0c;必须解决使用适用于macOS的Docker Desktop时出现的一些限制&#xff0c;特别是对于大中型公司&#xff0c;最大的问题是需要购买许可证。另外&#xff0c;macOS 版Docker Desktop的性能问题也…

单调栈(左小大,右小大)

①寻找每个数左边第一个比它小的数 给定一个长度为 N 的整数数列&#xff0c;输出每个数左边第一个比它小的数&#xff0c;如果不存在则输出 −1。 输入样例&#xff1a; 3 4 2 7 5 输出样例&#xff1a; -1 3 -1 2 2 从左到右遍历&#xff0c;用单调递增&#xff08;栈底到栈顶…

c->c++(二):class

本文主要探讨C类的相关知识。 构造和析构函数 构造函数(可多个)&#xff1a;对象产生时调用初始化class属性、分配class内部需要的动态内存 析构函数&#xff08;一个&#xff09;&#xff1a;对对象消亡时调用回收分配动态内存 C提供默认构造和析构,…

行人检测技术:思通数科大模型在自动驾驶安全中的应用

在自动驾驶技术飞速发展的今天&#xff0c;行人检测已成为确保道路交通安全的关键技术之一。本文将探讨如何结合思通数科大模型和计算机视觉技术&#xff0c;实现在城市交通环境中对行人的高效检测&#xff0c;为自动驾驶车辆提供必要的行人安全保障。 引言 行人检测技术是利…

Dubbo内部通信流程

我当时在学习的过程中搭建过demo&#xff0c;具体流程就是&#xff0c;我先定义了一个api接口模块&#xff0c;还定义一个服务提供者模块&#xff0c;然后服务提供方实现该接口&#xff0c;定义该方法具体的实现impl类&#xff0c;服务提供方启动时&#xff0c;将要暴露的服务和…

【架构-20】死锁

什么是死锁&#xff1f; 死锁(Deadlock)是指两个或多个线程/进程在执行过程中,由于资源的互相占用和等待,而陷入一种互相等待的僵局,无法继续往下执行的情况。 产生死锁的四个必要条件: &#xff08;1&#xff09;互斥条件(Mutual Exclusion)&#xff1a;至少有一个资源是非共享…

跨阻放大器

#创作灵感# 最近涉及到微电流的监测项目&#xff0c;而里面的核心就是跨阻放大器&#xff0c;所以这里做一个简单的介绍&#xff0c;后续等项目完成了&#xff0c;再做一个实例的介绍。 #正文# 跨阻放大器&#xff08;Transimpedance Amplifier, TIA&#xff09;是一种将输入电…