Java 快速转 C# 教程

以下是一个针对 Java 开发者快速转向 C# 的简明教程,重点对比 Java 与 C# 的异同,帮助你快速上手。


项目结构:

  • .sln :解决方案文件,管理多个项目之间的依赖关系。
  • .csproj :项目文件,定义目标框架(如 net6.0)、依赖项(NuGet 包或本地 DLL)。
  • global.json: 控制 .NET SDK 行为
    • 指定 .NET SDK 版本 :确保项目使用特定版本的 SDK 构建(避免本地环境版本不一致)。
    • 控制项目扫描范围 :在多项目解决方案中,指定哪些目录参与构建。
    • 启用/禁用 SDK 安装提示 :控制是否自动下载未安装的 SDK 版本。
  • app.manifest: 应用程序清单文件
    • 声明应用程序权限 (如以管理员身份运行)。
    • 指定兼容性需求 (如支持的 Windows 版本)。
    • 启用 Visual Studio 高 DPI 支持 。
    • 配置应用程序隔离(Side-by-Side Assembly) 。
  • Program.cs :程序入口(包含 Main 方法)。

一、基础语法对比

1. 变量与数据类型

JavaC#
int a = 10;int a = 10;
String name = "Hello";string name = "Hello";
final int MAX = 100;const int MAX = 100;
var list = new ArrayList<>(); (Java 10+)var list = new List<string>();

C# 特色:

  • var 是隐式类型变量(编译器推断类型)。
  • dynamic 类型可动态赋值(类似 Object)。

2. 拓展方法

C# 的扩展方法允许你为现有类型 (包括密封类、接口、甚至第三方库的类型)“添加”方法,而无需修改其源代码或继承。这是 C# 特有的语法特性,Java 中无直接等价物(需通过工具类或继承实现)。

定义扩展方法

  • 必须在静态类 中定义。
  • 第一个参数使用 this 关键字,表示该方法扩展的目标类型
// 静态类:扩展方法容器
public static class StringExtensions {// 扩展 string 类型的方法public static bool IsNullOrEmpty(this string str) {return string.IsNullOrEmpty(str);}
}

使用拓展方法

string name = null;// 调用扩展方法(如同实例方法)
if (name.IsNullOrEmpty()) {Console.WriteLine("Name is null or empty");
}

值得注意的是,拓展方法作为一个语法糖对应的可以解决在Java中 xxUtils 的工具类。同时具有以下注意:

  • 无法访问内部方法/属性
  • 若类型本身有同名方法,实例方法优先于扩展方法
  • 避免过度使用,防止命名冲突(需显式导入命名空间)

3. 空运算符(Null Handling Operators)

C# 提供了强大的空值处理运算符,简化空值检查逻辑,避免 NullReferenceException

1. 空条件运算符(?.

用于安全访问对象的成员,若对象为 null 则返回 null 而非抛出异常。

Person person = GetPerson(); // 可能为 null// 安全访问属性和方法
int length = person?.Name?.Length ?? 0;
person?.SayHello();

对比 Java

  • Java 中需显式判断或使用 Optional

    int length = Optional.ofNullable(person).map(p -> p.getName()).map(String::length).orElse(0);
    
2. 空合并运算符(??

提供默认值,当左侧表达式为 null 时返回右侧值。

string name = null;
string displayName = name ?? "Guest"; // 如果 name 为 null,则使用 "Guest"

对比 Java

  • Java 中使用三元运算符或 Optional

    String displayName = name != null ? name : "Guest";
    // 或
    String displayName = Optional.ofNullable(name).orElse("Guest");
    
3. 空合并赋值运算符(??=

仅当变量为 null 时才赋值(C# 8.0+)。

string message = GetMessage();
message ??= "Default Message"; // 如果 GetMessage() 返回 null,则赋值为默认值

对比 Java

  • Java 中需显式判断:
    if (message == null) {message = "Default Message";
    }
    

4. 非空断言运算符(!

告知编译器某个表达式不为 null(C# 8.0+,用于可空引用类型上下文)。

string name = GetName()!; // 告诉编译器 GetName() 返回值不为 null

注意事项

  • 空条件运算符返回的类型可能是 null(需结合 ?? 使用)。
  • 空合并运算符适用于 null 检查,但不适用于值类型(如 int)。
  • 使用 ?.?? 组合可显著减少防御性代码(如嵌套 if 判断)。

二、面向对象编程

1. 类与对象

public class Person {// 字段private string name;// 属性(推荐封装字段)public string Name {get { return name; }set { name = value; }}// 构造函数public Person(string name) {this.name = name;}// 方法public void SayHello() {Console.WriteLine($"Hello, {name}");}
}

对比 Java:

  • C# 使用 property(属性)替代 Java 的 getter/setter
  • this 关键字用法相同。

2. 继承与接口

// 继承
public class Student : Person {public Student(string name) : base(name) {}
}// 接口
public interface IRunnable {void Run();
}public class Car : IRunnable {public void Run() {Console.WriteLine("Car is running");}
}

对比 Java:

  • C# 使用 : 替代 Java 的 extends/implements
  • 接口方法默认 public,无需显式声明。

三、C# 特有特性

1. 委托与事件(Delegates & Events)

// 委托(类似 Java 的函数式接口)
// 定义一个名为 Notify 的委托类型,它表示一种方法模板,要求方法返回 void 并接受一个 string 参数
// 类比 Java :类似 Java 中的函数式接口(如 Consumer<String>),但 C# 的委托更直接,可以直接绑定方法。
public delegate void Notify(string message);// 事件
public class EventPublisher {// 声明一个事件 OnNotify,其类型是 Notify 委托。事件本质上是委托的安全封装,外部只能通过 +=/-= 订阅/取消订阅,不能直接调用(如 OnNotify.Invoke() 会报错)。public event Notify OnNotify;// 调用 OnNotify?.Invoke(...) 触发事件,?. 是空值保护操作符(避免空引用异常)。只有当至少有一个订阅者时,才会执行。public void TriggerEvent() {OnNotify?.Invoke("Event triggered!");}
}// 使用
EventPublisher publisher = new EventPublisher();
publisher.OnNotify += (msg) => Console.WriteLine(msg);
publisher.TriggerEvent();
  • 订阅事件
    使用 +=运算符将一个 lambda 表达式 (msg) => Console.WriteLine(msg)绑定到 OnNotify 事件。当事件触发时,会执行此方法。

  • 触发事件
    调用 TriggerEvent() 后,所有订阅者都会收到 “Event triggered!” 消息。

2. LINQ(Language Integrated Query)

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var even = numbers.Where(n => n % 2 == 0).ToList();

对比 Java:

  • 类似 Java Stream,但语法更简洁。

3. 异步编程(Async/Await)

public async Task DownloadDataAsync() {var client = new HttpClient();var data = await client.GetStringAsync("https://example.com");Console.WriteLine(data);
}

对比 Java:

  • 类似 CompletableFuture,但语法更直观。

Parallel.Invoke(() => {// 并行执行CPU密集任务
});
  • 多个 CPU 密集型任务并行执行。
  • 任务之间没有依赖。
  • 不需要返回结果。

四、常用工具与框架

JavaC#
Maven/GradleNuGet(包管理)
Spring.NET Core(框架)
JUnitxUnit/NUnit(测试框架)
IntelliJ IDEAVisual Studio / IntelliJ Rider(IDE)

五、项目结构与命名空间

// 文件:Program.cs
using System;
namespace MyApplication;class Program {static void Main(string[] args) {Console.WriteLine("Hello World!");}
}

对比 Java:

  • C# 使用 namespace 组织代码,Java 使用 package
  • 程序入口是 Main 方法(Java 是 main)。

六、Java 到 C# 的常见转换技巧

JavaC#
System.out.println()Console.WriteLine()
ArrayList<T>List<T>
HashMap<K,V>Dictionary<K,V>
interfaceinterface
enumenum
try-catch-finallytry-catch-finally

C# 中,反射(Reflection) 是一种强大的机制,允许在运行时动态地获取类型信息、创建对象实例、调用方法、访问字段和属性等。对于从 Java 转向 C# 的开发者来说,反射的概念是相似的,但 C# 的反射 API 更加简洁、直观,并且与语言特性(如 dynamicnameofLINQ)结合更紧密。


七、反射

反射是指在 运行时(runtime) 动态地:

  • 获取类型信息(如类名、方法、属性等)
  • 创建对象实例
  • 调用方法、访问字段或属性
  • 检查程序集(Assembly)的结构

Java 与 C# 反射的对比

功能JavaC#
获取类型对象MyClass.classobj.getClass()typeof(MyClass)obj.GetType()
获取方法clazz.getMethod("name", params...)type.GetMethod("Name")
调用方法method.invoke(obj, args)method.Invoke(obj, args)
获取属性clazz.getDeclaredField("name")type.GetProperty("Name")
获取程序集无直接等价物Assembly.GetExecutingAssembly()
动态创建实例clazz.newInstance()Activator.CreateInstance(type)
动态访问成员通过 Field/Method 对象通过 PropertyInfo/MethodInfo

1. 获取 Type 对象

// 通过类型名获取
Type type = typeof(string);// 通过对象获取
object obj = new Person();
Type type = obj.GetType();

2. 获取类成员信息(属性、方法、字段)

Type type = typeof(Person);// 获取所有属性
PropertyInfo[] properties = type.GetProperties();// 获取特定方法
MethodInfo method = type.GetMethod("SayHello");// 获取所有字段
FieldInfo[] fields = type.GetFields();

3. 动态创建实例

object person = Activator.CreateInstance(typeof(Person));

4. 调用方法

MethodInfo method = type.GetMethod("SayHello");
method.Invoke(person, null);

5. 访问属性

PropertyInfo prop = type.GetProperty("Name");
prop.SetValue(person, "Alice");
string name = (string)prop.GetValue(person);

6. 访问字段(不推荐,除非必要)

FieldInfo field = type.GetField("age", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(person, 30);
int age = (int)field.GetValue(person);

7. 获取程序集信息

Assembly assembly = Assembly.GetExecutingAssembly();
foreach (Type type in assembly.GetTypes()) {Console.WriteLine(type.Name);
}

8. 动态加载 DLL 并调用方法

Assembly assembly = Assembly.LoadFile("path/to/MyLibrary.dll");
Type type = assembly.GetType("MyNamespace.MyClass");
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("DoSomething");
method.Invoke(instance, null);

9. 使用 dynamic 替代部分反射操作

dynamic person = new ExpandoObject();
person.Name = "Bob";
person.SayHello = new Action(() => Console.WriteLine("Hello"));
person.SayHello(); // 无需反射即可调用

10. 使用 Expression 构建高性能的反射调用

Func<object> factory = Expression.Lambda<Func<object>>(Expression.New(typeof(Person))
).Compile();
object person = factory();

11. 使用 IL EmitSource Generator 优化性能

对于高性能场景(如 ORM、序列化框架),可以使用:

  • System.Reflection.Emit:动态生成 IL 代码
  • Source Generator(C# 9+):编译时生成代码,避免运行时反射

性能问题

  • 反射调用比直接调用慢(约慢 10~100 倍)
  • 频繁使用 GetMethodGetProperty 会增加开销

解决方案

  • 缓存反射结果(如 MethodInfoPropertyInfo
  • 使用 Expression 构建委托
  • 使用 dynamic(在合适场景下)
  • 使用 System.Reflection.DispatchProxy 实现代理
  • 使用 System.Text.JsonNewtonsoft.Json 等库已优化的反射机制

安全性

  • 可以访问私有成员(需设置 BindingFlags.NonPublic
  • 在部分受限环境中(如 UWP、AOT 编译)可能受限

Java 到 C# 反射的转换技巧

JavaC#
Class.forName("MyClass")Type.GetType("MyNamespace.MyClass")
clazz.newInstance()Activator.CreateInstance(type)
method.invoke(obj, args)method.Invoke(obj, args)
clazz.getDeclaredMethods()type.GetMethods()
clazz.getDeclaredFields()type.GetFields()
clazz.getDeclaredField("name")type.GetField("Name")
clazz.getDeclaredMethod("name", params...)type.GetMethod("Name", parameterTypes)
clazz.getInterfaces()type.GetInterfaces()


八、引入包(NuGet 包管理)

在 C# 中,NuGet 是官方推荐的包管理系统,类似于 Java 中的 Maven/Gradle。它用于管理项目依赖项(如第三方库、框架等)。

NuGet 包典型命名规则:[组织名].[功能模块].[平台/框架]

1. NuGet 的作用

  • 管理项目依赖(如 Newtonsoft.JsonEntityFramework 等)
  • 自动下载、安装、更新依赖包
  • 支持跨平台(Windows、Linux、macOS)

2. 常用方式

方法 1:通过 Visual Studio 引入
  1. 右键项目 → Manage NuGet Packages
  2. Browse 标签页搜索包名(如 Newtonsoft.Json
  3. 点击 Install 安装包
  4. 安装完成后,会自动添加到项目中
方法 2:通过 CLI 命令行
# 安装包
dotnet add package Newtonsoft.Json# 更新包
dotnet add package Newtonsoft.Json --version 13.0.1# 卸载包
dotnet remove package Newtonsoft.Json
方法 3:手动编辑 .csproj 文件

在项目文件中添加 <PackageReference>

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net6.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="Newtonsoft.Json" Version="13.0.1" /></ItemGroup>
</Project>

3. NuGet 源配置

默认源是 nuget.org,但也可以配置私有源(如公司内部源):

# 添加私有源
dotnet nuget add source https://mycompany.com/nuget -n MyCompany

4. 对比 Java

功能Java (Maven/Gradle)C# (NuGet)
包管理pom.xml / build.gradle.csproj
安装包mvn install / gradle builddotnet add package
私有仓库settings.xml / repositories { maven { url "..." } }dotnet nuget add source

九、引用本地的 DLL

有时你需要引用本地的 DLL 文件(如团队内部开发的库、第三方未提供 NuGet 包的库),可以通过以下方式实现。

1. 添加本地 DLL 引用

方法 1:通过 Visual Studio 添加
  1. 右键项目 → Add → Reference…
  2. 在弹出窗口中选择 Browse
  3. 浏览并选择本地 DLL 文件(如 MyLibrary.dll
  4. 点击 AddOK
方法 2:手动编辑 .csproj 文件
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net6.0</TargetFramework></PropertyGroup><ItemGroup><Reference Include="MyLibrary"><HintPath>..\Libraries\MyLibrary.dll</HintPath></Reference></ItemGroup>
</Project>

2. 确保 DLL 被正确复制到输出目录

.csproj 中添加以下配置,确保 DLL 被复制到 bin 目录:

<ContentWithTargetPath Include="..\Libraries\MyLibrary.dll"><TargetPath>MyLibrary.dll</TargetPath><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</ContentWithTargetPath>

3. 加载本地 DLL 的运行时行为

  • Windows:直接复制到 bin\Debug\net6.0 目录即可
  • Linux/macOS:确保 DLL 与主程序在同一目录,或设置 LD_LIBRARY_PATH / DYLD_LIBRARY_PATH

4. 注意事项

  • 强名称签名(Strong Name):如果 DLL 是强名称签名的,引用时需确保签名一致
  • 平台相关性:某些 DLL 仅支持特定平台(如 Windows 专用的 DLL)
  • 版本冲突:多个 DLL 依赖相同库的不同版本时,可能出现冲突(需手动绑定重定向)

常见问题与解决方案

1. 无法找到 DLL

  • 原因:DLL 未正确复制到输出目录
  • 解决:检查 .csproj 中是否设置了 <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

2. 加载 DLL 失败

  • 原因:DLL 依赖的其他库缺失
  • 解决:使用 Fusion Log Viewerfuslogvw.exe)查看绑定失败日志

3. 版本冲突

  • 原因:多个 DLL 依赖相同库的不同版本


十、DllImport(平台调用,P/Invoke)

在 C# 中,[DllImport("xxx.dll")]平台调用(Platform Invocation Services,P/Invoke) 的核心特性,用于直接调用 非托管代码(如 Windows API、C/C++ 编写的 DLL)。这是 Java 中没有的特性(Java 需要通过 JNI 调用本地代码)。


1. 基本概念

[DllImport]System.Runtime.InteropServices 命名空间下的特性(Attribute),用于声明某个方法的实现来自外部 DLL。它允许你在 C# 中直接调用 Windows API 或其他非托管函数。


2. 使用步骤

步骤 1:引入命名空间
using System.Runtime.InteropServices;
步骤 2:声明外部方法

使用 [DllImport("dll名称")] 特性修饰方法,指定 DLL 名称和调用约定(Calling Convention)。

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
步骤 3:调用方法
MessageBox(IntPtr.Zero, "Hello from C#", "Greeting", 0);

3. 参数说明

参数说明
dllNameDLL 文件名(如 "user32.dll"
CharSet字符集(CharSet.AnsiCharSet.UnicodeCharSet.Auto
CallingConvention调用约定(默认为 CallingConvention.Winapi,也可指定 ThisCallStdCall 等)
EntryPoint可选,指定 DLL 中函数的入口点(当方法名与 DLL 函数名不同时使用)

4. 常见示例

示例 1:调用 user32.dllMessageBox
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);// 调用
MessageBox(IntPtr.Zero, "Hello from C#", "Greeting", 0);
示例 2:调用 kernel32.dllGetTickCount
[DllImport("kernel32.dll")]
public static extern uint GetTickCount();// 调用
uint tickCount = GetTickCount();
Console.WriteLine($"System uptime: {tickCount} ms");
示例 3:调用 gdi32.dllCreateDC
[DllImport("gdi32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);// 调用
IntPtr hdc = CreateDC("DISPLAY", null, null, IntPtr.Zero);

5. 结构体与指针传参

当调用的函数需要结构体或指针参数时,需使用 refoutIntPtr,并可能需要使用 StructLayoutMarshalAs 来控制内存布局。

示例:调用 user32.dllGetWindowRect
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{public int Left;public int Top;public int Right;public int Bottom;
}[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);// 使用
RECT rect;
bool success = GetWindowRect(hWnd, out rect);
if (success)
{Console.WriteLine($"Window Rect: {rect.Left}, {rect.Top}, {rect.Right}, {rect.Bottom}");
}

6. 注意事项

安全性
  • 调用非托管代码可能带来 安全风险(如缓冲区溢出、非法访问内存)。
  • 需要 Full Trust 权限 才能执行 P/Invoke 操作。
平台依赖性
  • DllImport 仅适用于 Windows 平台(除非使用跨平台兼容的库)。
  • 某些 DLL(如 user32.dllkernel32.dll)是 Windows 系统库,其他平台无法直接使用。
性能
  • P/Invoke 调用比纯托管代码慢(涉及 上下文切换参数封送)。
  • 频繁调用时应考虑缓存结果或使用 unsafe 代码优化。
参数封送(Marshaling)
  • 需要特别注意 数据类型映射(如 int 对应 Int32char* 对应 string)。
  • 使用 MarshalAs 明确指定封送方式(如 UnmanagedType.LPStrUnmanagedType.BStr)。

7. 示例:封装一个 Windows API 工具类

using System;
using System.Runtime.InteropServices;public static class Win32Api
{[DllImport("user32.dll", CharSet = CharSet.Auto)]public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);[DllImport("kernel32.dll")]public static extern uint GetTickCount();[StructLayout(LayoutKind.Sequential)]public struct RECT{public int Left;public int Top;public int Right;public int Bottom;}[DllImport("user32.dll")][return: MarshalAs(UnmanagedType.Bool)]public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
}// 使用
class Program
{static void Main(){// 调用 MessageBoxWin32Api.MessageBox(IntPtr.Zero, "Hello from C#", "Greeting", 0);// 获取系统运行时间uint tickCount = Win32Api.GetTickCount();Console.WriteLine($"System uptime: {tickCount} ms");// 获取窗口位置Win32Api.RECT rect;bool success = Win32Api.GetWindowRect(new IntPtr(0x123456), out rect);if (success){Console.WriteLine($"Window Rect: {rect.Left}, {rect.Top}, {rect.Right}, {rect.Bottom}");}}
}

通过掌握 DllImport 和 P/Invoke,你可以在 C# 中直接调用 Windows API 或其他非托管函数,实现更底层的系统级操作。结合良好的封装和错误处理,可以显著提升程序的功能性和灵活性。

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

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

相关文章

EasyExcel详解

文章目录 一、easyExcel1.什么是easyExcel2.easyExcel示例demo3.easyExcel read的底层逻辑~~4.easyExcel write的底层逻辑~~ 二、FastExcel1.为什么更换为fastExcel2.fastExcel新功能 一、easyExcel 1.什么是easyExcel 内容摘自官方&#xff1a;Java解析、生成Excel比较有名的…

jvm安全点(三)openjdk17 c++源码垃圾回收之安全点结束,唤醒线程

1. VMThread::inner_execute() - 触发安全点​​ cpp 复制 void VMThread::inner_execute(VM_Operation* op) { if (op->evaluate_at_safepoint()) { SafepointSynchronize::begin(); // 进入安全点&#xff0c;阻塞所有线程 // ...执行GC等操作... SafepointSynchronize::…

102. 二叉树的层序遍历递归法:深度优先搜索的巧妙应用

二叉树的层序遍历是一种经典的遍历方式&#xff0c;它要求按层级逐层访问二叉树的节点。通常我们会使用队列来实现层序遍历&#xff0c;但递归法也是一种可行且有趣的思路。本文将深入探讨递归法解决二叉树层序遍历的核心难点&#xff0c;并结合代码和模拟过程进行详细讲解。 …

首个窗口级无人机配送VLN系统!中科院LogisticsVLN:基于MLLM实现精准投递

导读 随着智能物流需求日益增长&#xff0c;特别是“最后一公里”配送场景的精细化&#xff0c;传统地面机器人逐渐暴露出适应性差、精度不足等瓶颈。为此&#xff0c;本文提出了LogisticsVLN系统——一个基于多模态大语言模型的无人机视觉语言导航框架&#xff0c;专为窗户级别…

WPF Datagrid 数据加载和性能

这篇文章并非讨论 WPF Datagrid 的性能数据&#xff0c;而只是简单介绍一下为了使其性能良好&#xff0c;你需要注意哪些方面。我不太想使用性能分析器来展示实际数据&#xff0c;而是尽可能地使用了 Stopwatch 类。这篇文章不会深入探讨处理海量数据的技术&#xff0c;例如分页…

matlab求矩阵的逆、行列式、秩、转置

inv - 计算矩阵的逆 用途&#xff1a;计算一个可逆矩阵的逆矩阵。 D [1, 2; 3, 4]; % 定义一个2x2矩阵 D_inv inv(D); % 计算矩阵D的逆 disp(D_inv);det - 计算矩阵的行列式 用途&#xff1a;计算方阵的行列式。 E [1, 2; 3, 4]; determinant det(E); % 计算行列式 disp…

ridecore流水线解读

文章目录 流水线stage分属前后端PCpipelineIFIDDPDP 与 SW 中间没有latchSWCOM 源码地址 流水线stage分属前后端 IF -> ID -> DP -> SW -> EX -> COM分类阶段说明前端IF指令获取阶段。PC 使用分支预测器&#xff0c;访问指令存储器。典型前端操作。前端ID解码并…

【SpringBoot】关于MP使用中配置了数据库表前缀的问题

problem 使用MP时&#xff0c;在application.yml配置文件中配置了MP匹配数据库表中的表名时的前缀作了规定&#xff0c;如下&#xff1a; 那么当我运行时报错了错误&#xff0c;报错信息如下&#xff1a; 因为我数据库表的书类表名是book&#xff0c;MP在匹配时使用了表名前…

印度Rummy游戏支付通道申请策略:技巧类游戏的合规与创新

本文为印度支付申请科普文&#xff0c;自去年开始&#xff0c;印度Rummy类游戏申请印度支付都需要拥有AIGF的会员及产品证书。 如需要rummy可以通过AIGF审核的源。码&#xff0c;或咨询AIGF的相关内容&#xff0c;可以联。系老妙。 印度作为全球棋牌类游戏增长最快的市场之一&…

日志与策略模式

什么是设计模式 IT⾏业 ,为了让 菜鸡们不太拖⼤佬的后腿, 于是⼤佬们针对⼀些经典的常⻅的场景, 给定了⼀些对应的解决⽅案, 这个就是 设计模式 日志认识 计算机中的⽇志是记录系统和软件运⾏中发⽣事件的⽂件&#xff0c;主要作⽤是监控运⾏状态、记录异常信 息&#xff…

解锁Ubuntu高效部署!自动安装配置文件YAML全解析

我们之前介绍了两种Ubuntu系统的安装方式&#xff0c;分别对应桌面版&#xff08;准备搞OpenStack了&#xff0c;先装一台最新的Ubuntu 23.10&#xff09;和服务器版&#xff08;Ubuntu 22.04 LTS服务器版本安装演示&#xff09;。但对于有些用户&#xff0c;因为技术问题&…

关系代数和关系数据库语言(SQL)

阅读提示&#xff1a;本篇文章较长&#xff0c;建议从目录上选取想看的内容。代码上的话&#xff0c;我习惯用小写&#xff0c;如果看不习惯建议跳过。有问题欢迎讨论&#xff01;&#xff01;&#xff01; 一、基础概念 1.1数据库的概念 数据库(Database)是按照数据结构来组…

EXO 可以将 Mac M4 和 Mac Air 连接起来,并通过 Ollama 运行 DeepSeek 模型

EXO 可以将 Mac M4 和 Mac Air 连接起来&#xff0c;并通过 Ollama 运行 DeepSeek 模型。以下是具体实现方法&#xff1a; 1. EXO 的分布式计算能力 EXO 是一个支持 分布式 AI 计算 的开源框架&#xff0c;能够将多台 Mac 设备&#xff08;如 M4 和 Mac Air&#xff09;组合成…

区块链基本理解

文章目录 前言一、什么是分布式账本(DLT)二、什么是P2P网络?二、共识算法三、密码算法前言 区块链是由一个一个数据块组成的链条,按照时间顺序将数据块逐一链接,通过哈希指针链接,所有的数据块共同维护一份分布式账本(DLT),每个节点(可以理解为一个玩家,一台计算机)都拥…

Node.js中的洋葱模型

文章目录 前言 前言 Node.js中的洋葱模型是一种中间件执行机制&#xff0c;主要用于处理HTTP请求和响应的流程控制。该模型通过层层包裹的中间件结构&#xff0c;实现请求从外到内穿透、响应从内向外返回的顺序执行。以下从核心概念、实现原理、框架差异及实际应用等方面解析&…

UI-TARS Desktop:用自然语言操控电脑,AI 重新定义人机交互

在人工智能技术飞速发展的今天,从文本生成到图像识别,AI 的能力边界不断被打破。而字节跳动近期开源的 UI-TARS Desktop,则将这一技术推向了更复杂的交互场景——通过自然语言直接控制计算机界面,实现了图形用户界面(GUI)的智能化自动化。这款工具不仅降低了操作门槛,更…

一个可拖拉实现列表排序的WPF开源控件

从零学习构建一个完整的系统 推荐一个可通过拖拉&#xff0c;来实现列表元素的排序的WPF控件。 项目简介 gong-wpf-dragdrop是一个开源的.NET项目&#xff0c;用于在WPF应用程序中实现拖放功能&#xff0c;可以让开发人员快速、简单的实现拖放的操作功能。 可以在同一控件内…

C语言中字符串函数的详细讲解

C语言提供了丰富的字符串处理函数&#xff0c;这些函数在<string.h>头文件中声明。以下是一些常用字符串函数的详细讲解&#xff1a; 字符串拷贝函数 strcpy 功能&#xff1a;将源字符串&#xff08;包括结尾的\0&#xff09;复制到目标字符串。原型&#xff1a;char *s…

可视化数据图表怎么做?如何实现三维数据可视化?

目录 一、三维数据可视化的要点 1. 明确数据可视化的目标 2. 筛选与整理数据 3. 选择合适的图表类型 4. 运用专业工具制作 5. 优化图表的展示效果 二、数据可视化图表怎么做&#xff1f; 1. 理解三维数据的特性 2. 数据处理与三维建模 3. 设置光照与材质效果 4. 添加…

在Linux服务器上部署Jupyter Notebook并实现ssh无密码远程访问

Jupyter notebook版本7.4.2&#xff08;这个版本AI提示我Jupyter7&#xff08;底层是 jupyter_server 2.x&#xff09; 服务器开启服务 安装Jupyter notebook 7.4.2成功后&#xff0c;终端输入 jupyter notebook --generate-config 这将在 ~/.jupyter/ 目录下生成 jupyter_…