防御式编程是一种编程策略,主要目的是提高代码的健壮性和可靠性。它假设任何错误都可能发生,并且在设计和编写代码时采取预防措施以防止这些错误导致程序崩溃或产生错误结果。
以下是一些防御式编程的常见实践:
输入验证:总是验证函数、方法或过程的输入参数。如果输入不符合预期,应立即返回错误或异常,而不是继续执行可能出错的代码。
边界条件检查:对于循环、数组访问等操作,始终检查边界条件,以避免越界错误。
使用断言:在开发过程中,使用断言来检查代码中不应该发生的情况。这有助于在早期发现逻辑错误。
错误处理:编写能够优雅地处理错误的代码。这意味着应该捕获异常并提供适当的错误消息或恢复策略,而不是让程序崩溃。
日志记录:记录关键操作和错误信息,以便于调试和问题追踪。
模块化和封装:通过将功能封装到独立的模块或对象中,可以限制错误的影响范围,并使代码更易于测试和维护。
代码审查:定期进行代码审查,以发现潜在的错误和不安全的编码实践。
编写测试:为代码编写单元测试和集成测试,确保其按预期工作,并在修改后仍能保持正确性。
最小权限原则:在可能的情况下,代码和系统组件应只具有完成其任务所需的最少权限,以减少潜在的安全风险。
资源管理:确保正确管理和释放所有资源,如文件句柄、数据库连接和内存,以避免资源泄露。
防御式编程的关键在于“预防胜于治疗”,通过在代码设计和实现阶段采取预防措施,可以显著减少运行时错误和故障,从而提高软件的质量和稳定性。
在Java中,static关键字是一个重要的概念,它用于定义类的静态成员,包括静态变量(也称作类变量)、静态方法和静态代码块。static关键字的主要作用是创建独立于对象的成员,这些成员属于类本身,而不是类的实例。下面详细介绍static的不同方面:
1. 静态变量(Static Variables) 静态变量是类级别的变量,它们与类的所有实例共享。这意味着不论创建了多少个对象,静态变量在内存中只有一个副本。静态变量在类加载时初始化,并且在整个程序运行期间都存在。
例如:
public class MyClass { public static int count = 0; // 静态变量 public MyClass() { count++; // 每创建一个对象,count增加1 } } 在这个例子中,count是一个静态变量,它记录了MyClass对象创建的数量。
2. 静态方法(Static Methods) 静态方法是类级别的方法,它们可以在不创建类的实例的情况下被调用。静态方法只能访问静态成员,不能访问实例成员,因为实例成员需要一个对象才能存在。
例如:
public class MyClass { public static void sayHello() { System.out.println("Hello from static method!"); } } // 调用静态方法 MyClass.sayHello(); 3. 静态代码块(Static Blocks) 静态代码块在类加载时只执行一次,主要用于初始化静态变量。它们通常用于设置静态变量的初始值。
例如:
public class MyClass { public static int x; static { x = 10; // 在类加载时初始化x } } 4.
1、问题描述 impala执行查询:select * from stmta_raw limit 10;
报错信息如下:
Query: select * from sfmta_raw limit 10 Query submitted at: 2018-04-11 14:46:29 (Coordinator: http://mrj001:25000) ERROR: AnalysisException: Failed to load metadata for table: 'sfmta_raw' CAUSED BY: TableLoadingException: Failed to load metadata for table: test.sfmta_raw. Running 'invalidate metadata test.sfmta_raw' may resolve this problem. CAUSED BY: NoClassDefFoundError: org/apache/hadoop/fs/adl/AdlFileSystem CAUSED BY: ClassNotFoundException: org.apache.hadoop.fs.adl.AdlFileSystem 2、集群环境 【操作系统】Centos6.5
【hadoop版本】2.7.1
【impala版本】2.10.0-cdh5.14.0
3、报错分析 3.1、使用日志提示解决方案 #根据日志提示执行 invalidate metadata test.sfmta_raw 3.2、检查依赖lib包依赖 #检查依赖,看是否有依赖没有引入 cd /usr/lib/impala/lib #检查是否存在依赖包 ls -s | grep azure 3.
结构体+内存对齐+实现位段 一.结构体1.结构体的声明2.结构体变量成员访问操作符3.结构体传参4.匿名结构体5.结构的自引用 二.结构体内存对齐1.对齐规则2.为什么存在内存对齐?3.修改默认对齐数 三.结构体实现位段1.什么是位段2.位段的内存分配3.位段的跨平台问题4.位段的应用5.位段使用的注意事项 前言: 学习了数组后发现数组中的元素只能是相同类型的变量,那么有没有可以存放不同类型的变量呢?结构体:一些值的集合,这些值称为成员变量,结构体的每个成员可以是不同类型的变量。 一.结构体 1.结构体的声明 struct tag { member-list;//结构体成员列表 }variable-list;//结构体变量列表 例如:描述一个人
struct Person { int age;//年龄 char name[50];//姓名 float height;//身高 };//封号不能丢 2.结构体变量成员访问操作符 结构体变量.结构体成员名。结构体指针变量->结构体成员名。 #include <stdio.h> struct Person { int age; char name[50]; float height; }p1 = { 20,"zhangsan",185.5 }, * ps;//全局变量(*ps:结构体指针ps) int main() { struct Person p2 = { 18,"lisi",173.2 };//局部变量 struct Person p3 = { 19,"wangwu",180.8 };//局部变量 ps = &p3; printf("%d %s %.1f\n", p1.age, p1.name, p1.
DevOps 的出现是为了满足不断增长的市场和消费者对技术应用程序的需求。它旨在在不牺牲软件质量的情况下创建更快的开发环境。DevOps 还专注于在快速开发生命周期中提高软件的整体质量。它依赖于多种技术、平台和工具的组合来实现所有这些目标。
容器化是一项彻底改变了我们开发、部署和管理应用程序方式的技术。在这篇博文中,我们将了解容器如何融入 DevOps 世界,以及基于容器的 DevOps 交付管道的优缺点
在DevOps实践中,数字化可视性通常通过以下几种方式实现:
监控和日志记录:使用工具如Prometheus、Grafana和ELK栈(Elasticsearch、Logstash、Kibana)来收集和分析应用程序的日志数据,以及监控系统性能。这些数据可以帮助团队及时发现异常,并采取措施防止潜在的问题。
持续集成/持续部署(CI/CD):通过CI/CD管道,开发团队能够自动化代码的构建、测试和部署过程。这些管道的状态和结果应该是可见的,以便所有相关人员都能了解最新的构建和部署情况。
基础设施即代码(IaC):通过将基础设施的配置和管理代码化,团队可以更容易地追踪和审查基础设施的变化。工具如Terraform和Ansible支持基础设施的版本控制和自动化部署。
协同工具和沟通平台:使用Slack、Microsoft Teams等工具来促进团队成员之间的沟通和信息共享。这些平台可以作为单一的真实来源,用于交流项目更新、警报和通知。
仪表板和报告:通过定制的仪表板和自动生成的报告,团队可以直观地看到关键性能指标(KPIs)和项目进度,从而做出基于数据的决策。
通过这些实践,DevOps不仅提高了软件开发的速度和效率,还通过数字化可视性增强了团队的协作能力和响应市场变化的能力。在数字化转型的浪潮中,DevOps正在成为企业实现其技术目标和业务愿景的关键驱动力。
又是睿智OJ,有的题严格判空格和换行符,有的题又不判;有的题必须用 fgets 读入换行符,有的题又不能读入换行符;突出一个逆天。
第二章 线性表 1 顺序表的插入运算 #include <stdio.h> #include <stdlib.h> typedef struct node { int val; struct node *next; } Node, List; List *init(void) { List *s = (List*) malloc(sizeof(List)); Node *tail = s; int n; s->next = NULL, s->val = -1; scanf("%d", &n); for (int i = 0; i < n; ++i) { Node *node = (Node*) malloc(sizeof(Node)); scanf("%d", &node->val); node->next = NULL, tail->next = node, tail = node; } return s; } void insert(List *s) { Node *node = (Node*) malloc(sizeof(Node)), *curr = s; scanf("
一、前言 由于本人在这段时候,看到了一个叫做树莓派的东东,初步了解之后觉得很有意思,于是想把整个过程记录下来。
二、树莓派是什么? Raspberry Pi(中文名为树莓派,简写为RPi,(或者RasPi / RPI) 是为学习计算机编程教育而设计),只有信用卡大小的微型电脑,其系统基于Linux。随着Windows 10 IoT的发布,我们也将可以用上运行Windows的树莓派。自问世以来,受众多计算机发烧友和创客的追捧,曾经一“派”难求。别看其外表“娇小”,内“心”却很强大,视频、音频等功能通通皆有,可谓是麻雀虽小,五脏俱全。
1.用我的话理解 用我的话理解就是树莓派就是一台主机,你可以外接显示器,键盘鼠标,u盘等等外设,因为它体积很小,而且又有很多串口和外接的口,可以直接调用很多底层硬件。
2.市面上的型号 市面上大多是3代B+型,淘宝一搜树莓派一大堆都是,价钱纯主板(不要任何外设)在230+左右,有点小贵,超过我的预算,所以我继续寻找廉价的,终于让我发现了一款100+的树莓派。
3.树莓派zero w 树莓派zero w是一款mini的树莓派,体质只有3b+的1/3。实际到手后,你会发现它真的超级小,超级可爱。以下是我的实物图,你可以看看大小到底有多mini。
你可以看到,最上面是一根普通的黑色签字笔,接下来是一个即插即用型的外接wifi网卡,然后是一个USB读卡器,最底下的就是我们今天的主角zero w。它真的超级小,有木有。真的是完美的诠释了那句“麻雀虽小,五脏俱全”的话。
zero w这款树莓派的主要参数如下:
BCM2835处理器,1GHz主频,512MB RAM
BCM43438 WiFi / BT芯片
micro-USB电源接口
micro-USB OTG接口
miniHDMI端口
复合视频和重置扩展接口
脆弱的CSI摄像头接口
micro-SD卡座,存放操作系统
40-pin GPIO扩展接口
尺寸:65mm*30mm
你别看它的cpu只有1核,内存只有512MB,就觉得它可能什么都做不了,但是实际上它的性能还是很好的,用于跑一个网站真的是小case。
4.更多树莓派 关于更多树莓派型号或者使用教程你可以去树莓派实验室这个网站,上面有丰富的资源。
三、树莓派zero w安装系统 1.准备 你可能提前需要准备的东西如下:
16GB or 32GB 的SanDisk内存卡(注意是以前那种放在手机上,很小的哦)
一根最普通不过的usb安卓数据线(not type-c)
u盘格式化工具(推荐使用 SDFormatter)
系统烧写工具(Win32DiskImager)
树莓派系统(可以去官网下载)
我使用的是Raspbian Stretch Lite这个系统镜像,这个系统是官方制作的,lite是无桌面版的,只有黑漆漆的控制台,优点是体积小,省性能和内存。
名字带有desktop的是有桌面ui的,对不熟悉liunx系统的朋友可能更友好,但是体积很大,占用的性能也会更高。
2.第一步下载系统镜像 下载好你需要的系统镜像后,如下图
一开始只有一个zip的压缩包,大小大概360MB左右,你需要把它解压,得到上图的文件夹
然后进入文件夹可以看到一个img的镜像,大小为1.7GB左右
ps:这个官方的Raspbian镜像,如果是其他第三方的镜像,可能下载后的压缩包解压后不是img镜像,这种情况请另行百度解决
3.使用Win32DiskImager往内存卡中写入镜像 把内存卡插入读卡器后,插入电脑。打开Win32DiskImager软件后,选择img镜像,设备选择你的U盘,然后点击写入就可以了,写入完成后会弹出成功的提示框。
ps: 我上图没有选择设备,因为的没插入读卡器,仅仅是示范而已
4.修改boot分区的文件 先别急着拔出读卡器,此时,我们电脑可以看到u盘中只有一个名为boot的分区,大小可能只有40MB左右,不要着急,因为window不识别内存卡中liunx系统的其他分区。
作者 | 王启隆
责编 | 唐小引
出品丨AI 科技大本营(ID:rgznai100)
已过花甲之年的 Cay Horstmann 是 Java 经典著作《Java 核心技术》和《Java 核心技术:速学版》的作者,帮助了无数 Java 开发者启蒙进阶。截止到今天,Cay 在软件领域已经工作了 40 多年,但他本人与 Java 的结缘方式却不比寻常,始于 Java 萌芽时。
1995 年,Cay 的朋友 Gary Cornell 给他打了个电话:“我们要写一本关于 Java 的书。” 那时,Java 还未正式发布。所以 Cay 回答他:“除了媒体上的报道,我对 Java 一无所知。” 他知道 Gary 的情况也一样,“而且,你对 Java 也一无所知。”
Gary 却说:“但我已经拿到了一份出版合同。” 原来,James Gosling(Java 之父)不愿通过 Sun Microsystems Press 这家出版社发行书籍,双方陷入了扯皮。Gary 得知此消息后,便告知出版社的编辑,他恰好知道合适的人选来执笔此书。
于是,Cay 和 Gary 在那个圣诞节期间疯狂地学习 Java,他们有了三个月的时间来完成这部著作。幸运的是,Cay 当时还没从教授岗位下来,能依据研究许可获取到 Java 的源代码 —— 这件事远早于开源时代,当时的 Java 源码仅向研究者开放。正因为他们能接触到原始源码,清楚 Java 的实际功能,才发现最初版本的 Java 并不完全符合官方文档所述,甚至存在许多漏洞。
一、HTTP状态码是什么 概述
HTTP状态码是一种标准化的机制,用于服务器向客户端传达请求处理的结果。状态码是在HTTP协议中定义的,由三位数字代码组成,每个状态码都传达了不同类型的信息,客户端通过解析服务器响应中的状态码来了解请求的处理情况,并相应地采取适当的行动,HTTP状态码的使用使得客户端和服务器之间的通信更加清晰和可靠。
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求,当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含 HTTP 状态码的信息头(server header)用以响应浏览器的请求,响应分为五类:信息响应(100–199)、成功响应(200–299)、重定向(300–399)、客户端错误(400–499)、服务器错误 (500–599),即响应分别为1开头-5开头。
状态码
1xx,信息性状态码,表示接收的请求正在处理。
2xx,成功状态码,表示请求正常处理完毕。
3xx,重定向状态码,需要后续操作才能完成这一请求。
4xx,客户端错误状态码,表示请求包含语法错误或无法完成。
5xx,服务器错误状态码,服务器在处理请求的过程中发生了错误。
二、常见的HTTP状态码 200 OK
表示服务器已经成功处理了客户端的请求,且返回了请求所需的资源。
304 Not Modified
服务器收到客户端的请求后发现资源未被修改,可以直接使用客户端缓存的版本,从而减少网络流量和加载时间。
400 Bad Request
服务器无法理解客户端发送的请求,可能是因为请求的语法错误、格式不正确或缺少必要的参数。
404 Not Found
服务器无法根据客户端的请求找到所请求的资源,通常是因为请求的URL不存在或输入错误。
500 Internal Server Error
服务器内部错误,表示服务器在处理请求时发生了不可预料的错误,无法完成请求。
三、其他HTTP状态码 100继续
请求者应当继续提出请求,服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
101切换协议
请求者已要求服务器切换协议,服务器已确认并准备切换。
102处理中
由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。
201已创建
请求成功并且服务器创建了新的资源。
202已接受
服务器已接受请求,但尚未处理。
203非授权信息
服务器已成功处理了请求,但返回的信息可能来自另一来源。
204无内容
服务器成功处理了请求,但没有返回任何内容。
205重置内容
服务器成功处理了请求,但没有返回任何内容。
206部分内容
服务器成功处理了部分 GET 请求。
208已经报告
一个DAV的绑定成员被前一个请求枚举,并且没有被再一次包括。
226IM Used
服务器已经满足了请求所要的资源,并且响应是一个或多个实例操作应用于当前实例的结果。
300多种选择
针对请求,服务器可执行多种操作。服务器可根据请求者选择一项操作,或提供操作列表供请求者选择。
301永久移动
请求的网页已永久移动到新位置。服务器返回此响应时,会自动将请求者转到新位置。
302临时移动
服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置进行以后的请求。
303查看其他位置
在Windows API中,要实现鼠标左键按下并拖动以移动窗口中的某个图形,并且同时改变鼠标图标为“手掌”形状(这通常指的是“拖动”或“移动”的图标),你需要执行几个步骤。
以下是一个基本的步骤指南,用于在Windows API应用程序中实现拖动图形并改变鼠标光标:
创建窗口和图形:首先,你需要使用Windows API创建一个窗口,并在该窗口中绘制你想要拖动的图形。处理鼠标消息:在你的窗口消息处理函数中,你需要处理与鼠标相关的事件,特别是 WM_LBUTTONDOWN、WM_MOUSEMOVE 和 WM_LBUTTONUP。 WM_LBUTTONDOWN:当用户按下鼠标左键时触发。在这里,你可以设置一个标志(如布尔变量)来表示鼠标已被按下,并记录下鼠标的初始位置。同时使用SetCursor函数来改变鼠标光标。Windows API提供了一些预定义的光标,如IDC_ARROW(箭头)、IDC_HAND(手掌)、IDC_SIZENWSE(双向箭头)等。你还可以加载自定义的光标资源。WM_MOUSEMOVE:当鼠标在窗口中移动时触发。如果鼠标已被按下(根据你在 WM_LBUTTONDOWN 中设置的标志),你可以更新图形的位置,使其跟随鼠标的移动。这通常涉及到计算鼠标的当前位置与初始位置之间的差值,并将这个差值应用到图形上。WM_LBUTTONUP:当用户释放鼠标左键时触发。在这里,你应该清除鼠标已按下的标志,并可能执行一些清理操作(如重置鼠标的初始位置),同时重置鼠标光标为默认的光标。 绘制图形:在WM_PAINT消息处理中,根据当前图形的位置来绘制图形。这通常涉及到获取设备上下文(DC),使用 GDI 函数绘制图形,然后释放 DC。更新窗口:在移动图形后,你需要调用 InvalidateRect 或 RedrawWindow 函数来使窗口的某个区域(或整个窗口)无效,从而触发系统发送 WM_PAINT 消息来重绘窗口。测试和调试:在开发过程中,不断地测试你的应用程序以确保它按预期工作。使用调试工具(如 Visual Studio 的调试器)可以帮助你跟踪和修复问题 以下是一个简化的代码示例,展示了如何改变鼠标光标并在鼠标拖动时更新图形位置:
// 假设你有一个全局变量来跟踪鼠标是否被按下和图形的位置 BOOL g_mouseDown = FALSE; POINT g_graphicPos; // 图形的当前位置 // 窗口消息处理函数 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_LBUTTONDOWN: g_mouseDown = TRUE; GetCursorPos(&g_mousePos); // 获取鼠标屏幕位置,并转换为窗口坐标(如果需要) // 改变鼠标光标为手掌 SetCursor(LoadCursor(NULL, IDC_HAND)); break; case WM_MOUSEMOVE: if (g_mouseDown) { // 计算鼠标移动的距离,并更新图形的位置 POINT mousePos; GetCursorPos(&mousePos); // 获取当前鼠标屏幕位置 // 将mousePos转换为窗口坐标(如果需要) // .
在Android开发中,AndroidManifest.xml 文件是一个至关重要的组成部分,它位于应用的根目录的 app/src/main/ 文件夹下。这个文件提供了Android系统和其他应用所需的所有关于应用的元数据信息。以下是对 AndroidManifest.xml 文件的详细解析。
1. 文件结构和基本元素 AndroidManifest.xml 的基本结构包括 <manifest> 标签,它包含了应用的根本信息和权限声明。在 <manifest> 标签内,你可以找到以下关键元素:
<application>: 定义应用的全局设置,如主题、图标、标签等。<activity>: 声明一个Activity,Activity是应用中的一个界面。<service>: 声明一个Service,Service是运行在后台的组件,用于执行长时间运行的操作。<receiver>: 声明一个BroadcastReceiver,用于接收系统或应用发送的广播。<provider>: 声明一个ContentProvider,用于在应用之间共享数据。<uses-permission>: 声明应用所需的权限。<permission>: 声明应用定义的权限,可以被其他应用使用。 2. 应用标签 (<application>) <application> 标签包含了许多属性,如 android:label(应用的标签,通常显示在启动器图标下方)、android:icon(应用的图标)、android:theme(应用的默认主题)等。此外,它还可以包含前面提到的 <activity>、<service>、<receiver> 和 <provider> 等子元素。
3. Activity标签 (<activity>) <activity> 标签用于声明一个Activity。它通常包含 android:name 属性,指定Activity的完整类名。此外,还可以包含其他属性,如 android:label(Activity的标签,用于在UI中显示)、android:theme(Activity的主题)等。
4. Service标签 (<service>) <service> 标签用于声明一个Service。与Activity类似,它也包含 android:name 属性来指定Service的完整类名。但Service通常不需要在UI中显示,因此通常不需要 android:label 属性。
5. BroadcastReceiver标签 (<receiver>) <receiver> 标签用于声明一个BroadcastReceiver。除了 android:name 属性外,它还可以包含 <intent-filter> 子元素,用于指定该BroadcastReceiver应该接收哪些类型的广播。
6. ContentProvider标签 (<provider>) <provider> 标签用于声明一个ContentProvider。它包含 android:name 属性来指定ContentProvider的完整类名,以及 android:authorities 属性来指定ContentProvider的唯一标识符。
7. 权限声明 (<uses-permission> 和 <permission>) <uses-permission> 标签用于声明应用所需的权限。这些权限可以是系统定义的(如访问网络、读写文件等),也可以是其他应用定义的。<permission> 标签则用于声明应用定义的权限,这些权限可以被其他应用使用。
前言:在Java编程中,深拷贝(Deep Copy)与浅拷贝(Shallow Copy)是两个非常重要的概念。它们涉及到对象在内存中的复制方式,对于理解对象的引用、内存管理以及数据安全都至关重要。
✨✨✨这里是秋刀鱼不做梦的BLOG
✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客
先让我们看一下本文的大致内容:
目录
1.深拷贝与浅拷贝的概念
(1)浅拷贝
(2)深拷贝
2.浅拷贝的实现
3.深拷贝的实现
4.深浅拷贝的作用
浅拷贝的作用:
深拷贝的作用:
1.深拷贝与浅拷贝的概念 ——在了解Java中是如何实现对象的深浅拷贝之前,我们需要先了解一下什么是深拷贝、浅拷贝:
(1)浅拷贝 在浅拷贝中,只复制对象本身,而不复制对象引用的内容。这意味着,如果对象中包含了引用类型的成员变量,那么这些成员变量的引用将会被复制,但是它们仍然指向相同的内存地址。因此,对于引用类型成员变量的修改会影响到原始对象和拷贝对象。
(2)深拷贝 与浅拷贝不同,深拷贝会递归地复制对象及其所有引用的对象,直到所有对象都被复制到一个新的内存地址上。这样,原始对象和拷贝对象完全独立,彼此的修改不会相互影响。
嗯嗯嗯......感觉看了和没看没什么区别,还是不太能理解到底什么是Java中的深浅拷贝,那么我们使用一个生活中的案例来解释一下:
浅拷贝的情景:
——如果你选择了浅拷贝,那么你会简单地把整个礼物篮进行复制,然后送给你的朋友。在这种情况下,你的朋友会得到一个看起来一模一样的礼物篮。然而,当你的朋友拆开礼物篮,他们发现里面的食品和饰品并没有改变,他们是和你的礼物篮里的相同的食品和饰品。
深拷贝的情景:
——相比之下,如果你选择了深拷贝,那么你会仔细地把礼物篮里的每一样东西都复制一份,然后把这些复制品装进一个新的礼物篮里,送给你的朋友。在这种情况下,你的朋友得到的是一个全新的礼物篮,里面的食品和饰品和你的礼物篮里的完全一样。但是,现在他们拥有的是独立于你的礼物篮的新的食品和饰品。
不知道上面的生活案例有没有使你更好的理解Java中的深浅拷贝,如果还是没有,那么直接往下看即可!
大致的了解了什么是Java中的深浅拷贝之后,那么我们又该如何使用代码去实现它们呢?
2.浅拷贝的实现 在Java中,实现浅拷贝通常使用clone()方法。该方法会创建一个新对象,并将原始对象的所有字段值复制到新对象中。但是需要注意的是,对于引用类型的成员变量,仍然是浅拷贝,即复制的是引用而不是对象本身。
下面是在Java中实现浅拷贝的详细步骤:
1.实现Cloneable接口:
class MyClass implements Cloneable { // 类的定义 } 2.重写clone()方法并调用super.clone():
class MyClass implements Cloneable { // 类的定义 @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } 3.在使用时捕获CloneNotSupportedException异常:
try { MyClass copy = (MyClass) original.clone(); } catch (CloneNotSupportedException e) { e.
最近更新项目分支,编译时报错,提示Null extracted folder for artifact: ResolvedArtifact(依赖库名称。
在网上查了查,这个问题应该是通用问题,不只是针对某一个依赖库。
在网上看了看解决方案,大部分是说要clean project然后重新编译。
反复尝试之后不见效果。
后来跟同事沟通,发现同样的代码,同事就可以正常编译。
那就说明项目代码没问题,是自己编译环境哪里出了问题。
最后通过清缓存,重启android studio以及切换网络的方式修复了,果然项目代码没问题。
针对这类问题,大家可以通过以下步骤来修复。
1、清缓存
找到依赖库的缓存路径。(我是mac电脑)
一般是user-> .gradle (这是个隐藏目录,需要修改一些设置让它显示出来) -> caches -> modules-2 -> files-2.1 -> 依赖库目录
找到这个依赖库的目录,确认好跟依赖库名字相同的文件夹,删除就算是把缓存清了。
2、Android Studio clean project
清除缓存后,在Android Studio里clean project.
3、重启Android Studio或重新Sync项目
重启Android Studio或者重新Sync项目后,会重新下载之前删掉的依赖库。(注意,重新下载时最好使用网速较快较稳定的网络)
这时候可以观察之前找到的目录,如果依赖库的文件夹再次出现,则说明又重新下载了。
之后再观察看看是否编译成功。
这个问题有一部分原因是因为依赖库下载过程中网络问题导致的依赖库下载不全,解压失败。
所以重新执行时一定要注意电脑的网络状态是否快速稳定,网络不好仍然有可能会下载依赖库文件不全。
在编写微信小程序时,也许会用到播放背景音乐的功能,那么如果是自动播放背景音乐,可以在加载页面时就运行播放音乐的函数,若是希望简单实现音乐播放器的功能,那么设计几个按钮,并且设计按钮点击的事件。
接下来我说明按钮实现音乐播放的功能。wxss文件就不讲了,如果需要设置按钮格式,可以定义按钮的类名,在wxss中编写想要的按钮样式。
首先就需要有音乐的API接口,如果没有source,那么就无从谈起使用,可以参考我的API接口文章,里面整理了一些免费API接口,适合新手用。
然后就是在wxml文件中定义button组件,比如下面这个按钮实现“”播放“”的功能。
<button class="button-style1" bindtap="audioPlay">播放</button> 在.js文件中编写相应的点击按钮事件
data: { audioContext: null }, wx.request( { url:'换成自己的音乐API接口', method:'GET', success:(ret)=>{ console.log(ret.data.data)#这里相应的也要改 this.setData( { audio:ret.data.data#这里相应的也要改 } ) } }) }, audioPlay: function () { this.data.audioContext.src = this.data.audio.Music, this.data.audioContext.play() }, 当然有播放就有其他的功能实现,以下有暂停,挑选某一秒播放等。
如: this.data.audioContext.pause() , this.data.audioContext.seek(0) 只需要把 this.data.audioContext.play() 替换成以上的函数就行。
接下来最后一步就是页面加载:
onLoad(options) { this.setData ({ audioContext: wx.createInnerAudioContext() }) }, 至此,可以简单实现音乐播放器功能
在计算机中,小数点及其位置并不是显式表示出来的,而是隐含规定的。根据小数点的位置,可以分为两类:定点数和浮点数。
1 定点数 小数点的位置是固定不变的。根据小数点的具体位置,又可以分为两类:定点小数和定点整数。
定点小数 小数点隐含固定在最高数据位的左边,整数位表示符号位,用于表示一个纯小数。
定点整数 小数点隐含固定在最低数据位的之后,整数位表示符号位,用于表示一个纯整数。
2 浮点数 小数点的位置由阶码确定,因此是浮动的!用于表示实数。在计算机中,通常将浮点数拆分长阶码(exponent)和尾数(mantissa)两部分表示。尾数是规格化的纯小数。
x f p = 尾数 × 基 数 阶码 x_{fp} = 尾数 \times 基数^{阶码} xfp=尾数×基数阶码
举个例子:
( 11100.101 ) 2 = 0.11100101 × 2 5 = 0.11100101 × 2 101 (11100.101)_2 = 0.11100101 \times 2^5 = 0.11100101 \times 2^{101} (11100.101)2=0.11100101×25=0.11100101×2101
其实写法和十进制的科学记数法一致。
0.11100101 × 2 101 0.11100101 \times 2^{101} 0.11100101×2101实际上是由两个定点数组成,分别是(1)表示阶码的定点整数;(2)表示尾数的定点小数。
浮点数的一般存储格式:
16位浮点数(简单例子) 16位浮点数的格式:阶码是5位,尾数是9位,数符和阶符分别是1位。
举个例子:实数28.625的浮点表示。
N = 28.625 = ( 11100.
找往期文章包括但不限于本期文章中不懂的知识点:
个人主页:我要学编程(ಥ_ಥ)-CSDN博客
所属专栏:数据结构(Java版)
目录
深入了解包装类 包装类的由来
装箱与拆箱 面试题 泛型 泛型的语法与使用
泛型如何编译的 泛型的上界
泛型方法 泛型占位符
深入了解包装类 我们在最开始学习Java的数据类型时,就知道了Java的八大基本数据类型有自己对应的包装类,也就是引用类型。今天,我们就来彻底了解它们。
包装类的由来 在Java中,由于基本类型不是继承自Object类,为了在泛型代码中可以支持基本类型,Java给每个基本类型都创造了对应的一个包装类型。如下:
基本类型与其对应的包装类 类型 基本数据类型包装类 类型byteBytechar Character
shortShortintIntegerlongLongfloatFloatdoubleDoublebooleanBoolean 装箱与拆箱 装箱也叫作:装包。就是把基本数据类型转换成其对应的包装类 类型。
例如:
public class Test { public static void main(String[] args) { Integer a = 10; Integer c = new Integer(10); Integer b = Integer.valueOf(10); System.out.println(a); System.out.println(b); System.out.println(c); } } 上面三种写法,都是装箱的操作,即把基本数据类型转换成其对应的包装类 类型。但要注意的是第二种方法,虽然代码可以正常执行,但我们现在不再使用这种方法了。从Java 9开始,这个方法就已经被摒弃了。下面是Java 8 和 Java 17的不同情况:
Java 8:
Java 17: 需要注意的是:这里爆红,但还是可以运行通过的。 拆箱也叫作:拆包。就是把包装类 类型转换成其对应的基本数据类型。
一、常见部署模式分类 1. 按是否依赖外部资源调度 1.1 Standalone 模式 独立模式 (Standalone) 是独立运行的,不依赖任何外部的资源管理平台,只需要运行所有 Flink 组件服务
1.2 Yarn 模式 Yarn 模式是指客户端把 Flink 应用提交给 Yarn 的 ResourceManager, Yarn 的 ResourceManager 会在 Yarn 的 NodeManager 上创建容器。在这些容器上,Flink 会部署 JobManager 和 TaskManager 的实例,从而启动集群。Flink 会根据运行在 JobManger 上的作业所需要的 Slot 数量动态分配 TaskManager 资源
2. 按集群的生命周期和执行位置 2.1 会话模式 会话模式 (Session Mode) 是指先启动一个集群,保持一个会话并且确定所有的资源,然后向集群提交作业,所有提交的作业会竞争集群中的资源,从而会出现资源不足作业执行失败的情况会话模式比较适合于单个规模小、执行时间短的大量作业 2.2 单作业模式 单作业模式 (Per-Job Mode) 是指为每一个提交的作业启动一个集群,由客户端运行应用程序,然后启动集群,作业被提交给 JobManager,进而分发给 TaskManager 执行。作业作业完成后,集群就会关闭,所有资源也会释放。单作业模式在生产环境运行更加稳定,所以是实际应用的首选模式单作业模式一般需要借助一些资源管理框架来启动集群,比如 YARN、Kubernetes 2.3 应用模式 应用模式 (Application Mode) 是指为每一个提交的应用单独启动一个 JobManager,也就是创建一个集群。这个 JobManager 只为执行这一个应用而存在,执行结束之后 JobManager 也就关闭了。这一模式下没有客户端的存在应用模式与单作业模式,都是提交作业之后才创建集群;单作业模式是通过客户端来提交作业的,客户端解析出的每一个作业对应一个集群;而应用模式下,是直接由 JobManager 执行应用程序的,并且即使应用包含了多个作业,也只创建一个集群 二、常见部署模式组合 Standalone + 会话模式Standalone + 应用模式Yarn + 会话模式Yarn + 单作业模式Yarn + 应用模式 三、独立模式安装 1.
1、JDK 22 下载 https://pan.baidu.com/s/16g-5Hci0ygqV_LqeN49hcw?pwd=jdks
2、安装文件 选择路径后,一路默认安装。
3、Windows 系统下配置环境变量 点击我的电脑-属性-高级系统设置
新增配置 JAVA_HOME,为 jdk 的安装路径
D:\Java22\jdk22
编辑配置 Path 变量,配置 jdk 的 bin 的目录
%JAVA_HOME%\bin
验证安装结果
4、Mac 系统下配置环境变量 打开终端,输入命令:vi ~/.bash_profile
编辑文件
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-22.0.1.jdk/Contents/Home
export PATH=$JAVA_HOME/bin:$PATH
保存文件并重新加载配置:source ~/.bash_profile
验证安装结果
引言 近年来,华为在智能汽车领域的布局备受关注,虽然华为创始人任正非曾多次表示华为不造车,但事实证明,华为在汽车产业链的深度参与已让人产生了“华为造车”的错觉。本文将探讨华为在汽车领域的发展历程,分析华为不直接造车的原因及其未来的发展方向。
华为在汽车领域的发展历程 华为在汽车领域的发展可大致分为三个阶段:
阶段一:2009-2013年 华为初入汽车市场,开始布局车载通信模块产品。这一时期,华为主要扮演通信专家的角色,专注于自己的技术领域。
阶段二:2013-2018年 华为开始上升到车联网业务,与奔驰、奥迪、大众、雪铁龙、丰田、通用等国际大厂及国内厂商建立合作。这一阶段,华为依然深耕自己的基本盘,定位明确。
阶段三:2019年至今 华为大举进军汽车业务,成立了智能汽车解决方案业务部(BU),并提升为一级部门,人员规模超过数千人。从这一阶段开始,华为建立了与车企的三种互动方式:
零部件供应商模式:华为作为一级供应商(Tier 1),提供汽车零部件。HI模式:华为提供全栈智能汽车解决方案,如长安阿维塔和北汽极狐。智选车模式:华为通过鸿蒙智行品牌,深度参与车企的产品设计和营销。 华为的深度参与 华为在汽车零部件方面的布局已经相当全面,包括ADS支架、鸿蒙座舱、DriveONE电驱系统、X Motion车身控制系统、DATS动态扭矩系统、X HUD抬头显示、X Pixel智慧大灯等。从零部件到车联网、BMS管理软件、全液冷超充等,华为在智能电动车领域的参与度极高。
鸿蒙智行品牌 通过鸿蒙智行品牌,华为进一步统一了合作车型的设计风格,提升了品牌识别度。虽然华为不直接造车,但其深度参与让消费者对这些车型的认可度大大提升。
华为不直接造车的原因 1. 市场策略 尽管华为具备直接造车的技术实力,但选择不直接造车主要是为了规避风险,并通过合作实现共赢。通过深度参与但不直接造车,华为既能保留与车企的合作关系,又能避免高昂的研发和生产成本。
2. 内部意见分歧 华为内部对于是否造车存在分歧,最终选择了不直接造车,但深度参与汽车业务的妥协方案。这种方式既符合华为的长远战略,又能实现技术方案的市场变现。
3. 避免过度依赖 如果华为直接造车,将会面临与现有车企的直接竞争,这可能导致合作关系的破裂。通过保持技术供应商的角色,华为能够在多个车企中实现技术推广,避免过度依赖单一市场。
未来展望 华为的智能汽车业务在未来几年将继续扩大。鸿蒙智行已经成为造车新势力中的一股重要力量,未来,华为将加大在汽车领域的投入,继续扩展鸿蒙宇宙,形成一个庞大的联盟体系。这些产自不同工厂但拥有同一套设计语言的车型,将成为中国汽车工业中的特殊存在。
结论 华为通过深度参与汽车业务而非直接造车的战略,不仅避免了高风险的投资,也提升了自身在智能汽车领域的影响力。随着技术的不断发展和市场的扩展,华为在汽车领域的角色将愈加重要。未来,我们有理由相信,华为将在智能汽车行业中扮演更加关键的角色,为行业带来更多创新和变革。
目录
关于 HtmlTable
HtmlTable与BaseDataList的区别
准备数据源
范例运行环境
FillTable 方法
设计与实现
模板样例输出
Automatic 模式填充
DynamicRows 模式填充
StaticRows 模式填充
小结
关于 HtmlTable 数据感应也即数据捆绑,是一种动态的,Web控件与数据源之间的交互,HtmlTable 控件表示为一个服务器控件,隶属于 System.Web.UI.HtmlControls 集合,对于客户端输出即 table 标签元素,table 表格的主要作用就是数据输出 ,本文将介绍 C# 实现操作 HtmlTable 服务器控件实现数据集表数据的轻量化输出与显示。
HtmlTable与BaseDataList的区别 HtmlTable 与诸如 DataGrid、GridView 都可用于数据输出 ,主要区别在于:
(1)前者以属于System.Web.UI.HtmlControls 集合,后者 Microsoft.Web.UI.WebControls 集合
(2)HtmlTable 可实现 table 元素的一些操作,如行、列、单元格及样式设置,而 BaseDataList 除可实现 HtmlTable 的基本控制外,还可以绑定数据源、绑定事件、绑定列控件等更加强大的功能。
(3)对于数据集合访问 HtmlTable 通过 Rows ,列集合为 Cells;而 BaseDataList 通过 Items ,列集合为 Colums。
准备数据源 我们在 MS SQL Server 创建 pub_ChinaPay(支付状态代码表),其结构如下表: