使用 Clojure 进行 OpenCV 开发简介

  返回:OpenCV系列文章目录(持续更新中......)

上一篇:如何将OpenCV Java 与Eclipse结合使用

下一篇: OpenCV4.9.0在Android 开发简介

​警告
本教程可以包含过时的信息。

从 OpenCV 2.4.4 开始,OpenCV 支持使用与 Android 开发几乎相同的界面进行桌面 Java 开发

Clojure 是一种由 Java 虚拟机托管的现代 LISP 方言,它提供了与底层 JVM 的完全互操作性。这意味着我们甚至应该能够使用 Clojure REPL(读取评估打印循环)作为底层 OpenCV 引擎的交互式可编程接口。

我们将在本教程中执行的操作

本教程将帮助您设置一个基本的 Clojure 环境,以便在完全可编程的 CLojure REPL 中以交互方式学习 OpenCV。

教程源代码

您可以在 OpenCV 存储库的文件夹中找到该示例的可运行源代码。按照教程中的说明安装 OpenCV 和 Clojure 后,发出以下命令以从命令行运行示例。

cd path/to/samples/java/clojure/simple-sample
lein run

序言

有关安装具有桌面 Java 支持的 OpenCV 的详细说明,请参阅相应的教程”。

如果您赶时间,以下是在 Mac OS X 上安装 OpenCV 的最低快速入门指南:

注意:

我假设你已经安装了 xcode、jdk 和 Cmake。

cd ~/
mkdir opt
git clone https://github.com/opencv/opencv.git
cd opencv
git checkout 2.4
mkdir build
cd build
cmake -DBUILD_SHARED_LIBS=OFF
make -j8
# optional
# make install

安装 Leiningen

一旦你安装了支持桌面 java 的 OpenCV,唯一的其他要求就是安装 Leiningeng,它允许你管理 CLJ 项目的整个生命周期。

可用的安装指南非常容易遵循:

  1. 下载脚本 script
  2. 建议放在你系统路径目录下的cf./bin 比较好
  3. 将脚本设置为可执行。(i.e. chmod 755/bin/lein).

如果是 Windows系统 请参照: this instruction

说明操作

现在,您已经拥有了 OpenCV 库和完全安装的基本 Clojure 环境。现在需要的是配置 Clojure 环境以与 OpenCV 库进行交互。

安装 localrepo Leiningen 插件

Leiningen 原生支持的命令集(莱宁根术语中的任务)可以很容易地通过各种插件进行扩展。其中之一是 lein-localrepo 插件,它允许将任何 jar lib 作为工件安装在您机器的本地 maven 存储库中(通常位于用户名的 /.m2/repository 目录中)。

我们将使用这个 lein 插件将 Java 和 Clojure 使用 opencv 库所需的 opencv 组件添加到本地 maven 存储库中。

一般来说,如果你只想在项目基础上使用一个插件,可以直接将其添加到lein创建的CLJ项目中。

相反,当您希望插件可用于用户名空间中的任何 CLJ 项目时,您可以将其添加到 /.lein/ 目录中的 profiles.clj。

ein-localrepo 插件在其他 CLJ 项目中对我有用,在这些项目中,我需要调用由 Java 接口包装的原生库。因此,我决定将其提供给任何 CLJ 项目:

mkdir ~/.lein

在 /.lein 目录下创建一个名为 profiles.clj 的文件,并将以下内容复制到该文件中:

{:user {:plugins [[lein-localrepo "0.5.2"]]}}

在这里,我们说 lein-localrepo 插件的版本版本“0.5.2”将可用于 lein 创建的任何 CLJ 项目的 :user 配置文件。

您无需执行任何其他操作即可安装该插件,因为在您第一次发出任何 lein 任务时,它将自动从远程存储库下载。

将特定于 java 的库安装为本地存储库

如果您遵循了在计算机上安装 OpenCV 的标准文档,您应该在构建 OpenCV 的目录下找到以下两个库:

  • the build/bin/opencv-247.jar java lib
  • the build/lib/libopencv_java247.dylib native lib (or .so in you built OpenCV a GNU/Linux OS)

它们是JVM与OpenCV交互所需的唯一opencv 库。

拆解所需的 opencv 库。

创建一个新目录以存储在上述两个库中。首先将 opencv-247.jar 库复制到其中。

cd ~/opt
mkdir clj-opencv
cd clj-opencv
cp ~/opt/opencv/build/bin/opencv-247.jar

第一个库完成。

现在,为了能够将 libopencv_java247.dylib 共享的原生库添加到本地 maven 存储库中,我们首先需要将其打包为 jar 文件。

本机库必须复制到模仿操作系统和体系结构名称的目录布局中。 X86 64 位架构的 Mac OS X。布局如下:

mkdir -p native/macosx/x86_64
Copy into the x86_64 directory the libopencv_java247.dylib lib.
cp ~/opt/opencv/build/lib/libopencv_java247.dylib native/macosx/x86_64/

如果您从不同的操作系统/架构对运行OpenCV,以下是您可以选择的映射摘要。

操作系统

Mac OS X -> macosx

Windows -> windows

Linux -> linux

SunOS -> solaris

CPU架构

amd64 -> x86_64

x86_64 -> x86_64

x86 -> x86

i386 -> x86

arm -> arm

sparc -> sparc

将本机库打包为jar

接下来,您需要使用jar命令将本机库打包到jar文件中,以从目录创建新的jar文件。

jar -cMf opencv-native-247.jar native

 注意,eheM选项指示jar命令不为工件创建MANIFEST文件

tree
.
|__ native
| |__ macosx
| |__ x86_64
| |__ libopencv_java247.dylib
|
|__ opencv-247.jar
|__ opencv-native-247.jar
3 directories, 3 files

在本地安装jar

现在,我们准备在lein-localrepo插件的帮助下将这两个jar作为工件添加到本地maven存储库中。

lein localrepo install opencv-247.jar opencv/opencv 2.4.7

在这里,localrepo安装任务创建2.4.7。从opencv-247.jar库中释放opencv/opencvmaven工件,然后将其安装到本地maven存储库中。然后,opencv/opencv工件将可用于任何符合maven的项目(Leiningen内部基于maven)。

对之前包装在新jar文件中的本机库执行相同的操作。

lein localrepo install opencv-native-247.jar opencv/opencv-native 2.4.7

注意:这两个工件的groupIdopencv是相同的。现在,我们准备创建一个新的CLJ项目来开始与OpenCV交互。

创建项目

使用终端中的leinnew任务创建新的CLJ项目。

# cd in the directory where you work with your development projects (e.g. ~/devel)
lein new simple-sample

基于“默认”模板生成一个名为simple-sample的项目。
要查看其他模板(应用程序、lein插件等),请尝试“leinhelpnew”。
上述任务创建以下简单示例目录布局:

tree simple-sample/
simple-sample/
|__ LICENSE
|__ README.md
|__ doc
| |__ intro.md
|
|__ project.clj
|__ resources
|__ src
| |__ simple_sample
| |__ core.clj
|__ test
|__ simple_sample
|__ core_test.clj
6 directories, 6 files

我们需要添加两个opencv工件作为新创建的项目的依赖项。打开project.clj并修改其依赖项部分,如下所示:

(defproject simple-sample "0.1.0-SNAPSHOT"
description "FIXME: write description"
url "http://example.com/FIXME"
license {:name "Eclipse Public License"
url "http://www.eclipse.org/legal/epl-v10.html"}
dependencies [[org.clojure/clojure "1.5.1"]
[opencv/opencv "2.4.7"] ; added line
[opencv/opencv-native "2.4.7"]]) ;added line

注意,Clojure编程语言也是一个jar工件。这就是Clojure被称为托管语言的原因。

要验证一切正常,请发出leindeps任务。第一次运行lein任务时,在执行任务本身之前,需要一些时间来下载所有必需的依赖项。

cd simple-sample
lein deps
...

deps任务从project.clj和/.lein/profiles.clj文件中读取并合并simple-sample项目的所有依赖项,并验证它们是否已缓存在本地maven存储库中。如果任务返回时没有关于无法检索两个新工件的消息,则您的安装是正确的,否则请返回并仔细检查您的操作是否正确。

使用OpenCV进行REPLing

现在cd在simple-sample目录中并发出以下lein任务:

cd simple-sample
lein repl
...
...

nREPL服务器在主机127.0.0.1上的端口50907上启动

REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=>

您可以通过发出任何要计算的CLJ表达式来立即与REPL交互。

user=> (+ 41 1)
42
user=> (println "Hello, OpenCV!")
Hello, OpenCV!
nil
user=> (defn foo [] (str "bar"))
#'user/foo
user=> (foo)
"bar"

当从基于lein的项目的主目录运行时,即使leinrepl任务自动加载所有项目依赖项,您仍然需要加载opencv原生库才能与OpenCV进行交互。

user=> (clojure.lang.RT/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME)
nil

然后,您只需引用其类的完全限定名称即可开始与OpenCV交互。

注意
在这里,您可以找到完整的OpenCVJavaAPI。

user=> (org.opencv.core.Point. 0 0)
#<Point {0.0, 0.0}>

在这里,我们创建了一个二维opencvPoint实例。即使OpenCV的java接口中包含的所有java包都可以立即从CLJREPL获得,但作为Point的前缀还是非常烦人的。具有完全限定包名称的实例构造函数。

幸运的是,CLJ提供了一种非常简单的方法来克服这种烦恼,方法是直接导入Point类。

user=> (import 'org.opencv.core.Point)
org.opencv.core.Point
user=> (def p1 (Point. 0 0))
#'user/p1
user=> p1
#<Point {0.0, 0.0}>
user=> (def p2 (Point. 100 100))
#'user/p2

我们甚至可以检查实例的类,并验证符号的值是否是Pointjava类的实例。

user=> (class p1)
org.opencv.core.Point
user=> (instance? org.opencv.core.Point p1)
true

如果我们现在想使用opencvRect类来创建一个矩形,我们再次必须完全限定它的构造函数,即使它留在Point类的同一个org.opencv.core包中。

user=> (org.opencv.core.Rect. p1 p2)
#<Rect {0, 0, 100x100}>

同样,CLJ导入工具非常方便,可让您一次映射更多符号。

user=> (import '[org.opencv.core Point Rect Size])
org.opencv.core.Size
user=> (def r1 (Rect. p1 p2))
#'user/r1
user=> r1
#<Rect {0, 0, 100x100}>
user=> (class r1)
org.opencv.core.Rect
user=> (instance? org.opencv.core.Rect r1)
true
user=> (Size. 100 100)
#<Size 100x100>
user=> (def sq-100 (Size. 100 100))
#'user/sq-100
user=> (class sq-100)
org.opencv.core.Size
user=> (instance? org.opencv.core.Size sq-100)
true

显然,您也可以在实例上调用方法。

user=> (.area r1)
10000.0
user=> (.area sq-100)
10000.0
Or modify the value of a member field.
user=> (set! (.x p1) 10)
10
user=> p1
#<Point {10.0, 0.0}>
user=> (set! (.width sq-100) 10)
10
user=> (set! (.height sq-100) 10)
10
user=> (.area sq-100)
100.0

如果您发现自己不记得OpenCV类的行为,REPL让您有机会轻松搜索相应的javadoc文档:

user=> (javadoc Rect)
"http://www.google.com/search?btnI=I%27m%20Feeling%20Lucky&q=allinurl:org/opencv/core/Rect.html"

在REPL中模拟OpenCVJava教程示例

现在,让我们尝试将OpenCVJava教程示例移植到Clojure。我们不是将其写入源文件,而是在REPL中对其进行评估。

以下是引用示例的原始Java源代码。

​import org.opencv.core.Mat;
import org.opencv.core.CvType;
import org.opencv.core.Scalar;
class SimpleSample {
static{ System.loadLibrary("opencv_java244"); }
public static void main(String[] args) {
Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0));
System.out.println("OpenCV Mat: " + m);
Mat mr1 = m.row(1);
mr1.setTo(new Scalar(1));
Mat mc5 = m.col(5);
mc5.setTo(new Scalar(5));
System.out.println("OpenCV Mat data:\n" + m.dump());
}
}

向项目添加注入

在开始编码之前,我们希望消除在任何时候启动新的REPL以交互方式加载原生opencv库以交互方式与之交互的无聊需求。

首先,通过在REPL提示符下计算(exit)表达式来停止REPL。

user=> (exit)

Bye for now!

然后打开project.clj文件并对其进行编辑,如下所示:

(defproject simple-sample "0.1.0-SNAPSHOT"
...
injections [(clojure.lang.RT/loadLibrary org.opencv.core.Core/NATIVE_LIBRARY_NAME)])

在这里,我们说的是,每当我们运行REPL时,都要加载opencv原生库,这样我们就不必再记住手动执行此操作了。

重新运行leinrepl任务

lein repl
nREPL server started on port 51645 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=>
Import the interested OpenCV java interfaces.
user=> (import '[org.opencv.core Mat CvType Scalar])

nREPL服务器在主机127.0.0.1上的端口51645上启动

REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=>
Import the interested OpenCV java interfaces.
user=> (import '[org.opencv.core Mat CvType Scalar])
org.opencv.core.Scalar

我们将几乎逐字逐句地模仿原始的OpenCVjava教程:

创建一个5x10矩阵,其所有元素初始化为0
将第二行的每个元素的值更改为1
将第6列的每个元素的值更改为5
打印所得矩阵的内容

user=> (def m (Mat. 5 10 CvType/CV_8UC1 (Scalar. 0 0)))
#'user/m
user=> (def mr1 (.row m 1))
#'user/mr1
user=> (.setTo mr1 (Scalar. 1 0))
#<Mat Mat [ 1*10*CV_8UC1, isCont=true, isSubmat=true, nativeObj=0x7fc9dac49880, dataAddr=0x7fc9d9c98d5a ]>
user=> (def mc5 (.col m 5))
#'user/mc5
user=> (.setTo mc5 (Scalar. 5 0))
#<Mat Mat [ 5*1*CV_8UC1, isCont=false, isSubmat=true, nativeObj=0x7fc9d9c995a0, dataAddr=0x7fc9d9c98d55 ]>
user=> (println (.dump m))
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0;
1, 1, 1, 1, 1, 5, 1, 1, 1, 1;
0, 0, 0, 0, 0, 5, 0, 0, 0, 0;
0, 0, 0, 0, 0, 5, 0, 0, 0, 0;
0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
nil

如果你习惯了一种功能性语言,那么所有这些被滥用和变异的名词都会激怒你对动词的偏好。即使CLJ互操作语法非常方便和完整,任何OOP语言和任何FP语言(beinScala是一种混合范式编程语言)之间仍然存在阻抗不匹配。

要退出REPL,请在REPL提示符下键入(exit)、ctr-D或(quit)

user=> (exit)
Bye for now!

以交互方式加载和模糊图像

在下一个示例中,您将学习如何使用以下OpenCV方法以交互方式从REPL加载、模糊和图像化:

Highgui类中的imreadstatic方法,用于从文件中读取图像
Highgui类中的imwritestatic方法,用于将图像写入文件
Imgproc类中的GaussianBlur静态方法,用于模糊原始图像

我们还将使用Mat类,该类从imread方法返回,并被接受为GaussianBlur和imwrite方法的主要参数。

将图像添加到项目

首先,我们要将图像文件添加到新创建的目录中,用于存储项目的静态资源。

lena.png

mkdir -p resources/images
cp ~/opt/opencv/doc/tutorials/introduction/desktop_java/images/lena.png resource/images/

阅读图片

现在像往常一样启动REPL,然后首先导入我们将要使用的所有OpenCV类:

lein repl
nREPL server started on port 50624 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> (import '[org.opencv.core Mat Size CvType]
'[org.opencv.imgcodecs Imgcodecs]
'[org.opencv.imgproc Imgproc])
org.opencv.imgproc.Imgproc
Now read the image from the resources/images/lena.png file.
user=> (def lena (Highgui/imread "resources/images/lena.png"))
#'user/lena
user=> lena
#<Mat Mat [ 512*512*CV_8UC3, isCont=true, isSubmat=false, nativeObj=0x7f9ab3054c40, dataAddr=0x19fea9010 ]>

如您所见,通过简单地计算lena符号,我们知道lena.png是512x512的CV_8UC3元素类型的矩阵。让我们创建一个具有相同维度和元素类型的新Mat实例。

user=> (def blurred (Mat. 512 512 CvType/CV_8UC3))
#'user/blurred
user=>

现在应用一个GaussianBlur滤镜,使用lena作为源矩阵,模糊作为目标矩阵。

user=> (Imgproc/GaussianBlur lena blurred (Size. 5 5) 3 3)
nil
As a last step just save the blurred matrix in a new image file.
user=> (Highgui/imwrite "resources/images/blurred.png" blurred)
true
user=> (exit)
Bye for now!

以下是莉娜的新模糊图像。

blurred.png

​后续步骤

本教程仅介绍为能够在CLJREPL中与OpenCV交互而设置的最基本环境。

我建议任何Clojure新手阅读ClojureJavaInterop一章,了解与任何未包含在Clojure中的普通Java库进行互操作所需的所有知识,以使其在Clojure中以更惯用和更实用的方式使用。

OpenCVJavaAPI不会根据Qt包装highgui模块功能(例如namedWindow和imshow.如果您想在从REPL与OpenCV交互时创建窗口并在其中显示图像,那么目前您只能自己动手了。您可以使用JavaSwing来填补空白。

许可证:

版权所有© 2013 Giacomo (Mimmo) Cosenza aka Magomimmo

根据BSD3条款许可证分发。


参考文献:

1、《Introduction to OpenCV Development with Clojure》Mimmo Cosenza

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

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

相关文章

挑战设计极限!电路仿真软件成功案例大揭秘,助您圆梦创新之路

在电子设计领域&#xff0c;电路仿真软件扮演着至关重要的角色。它们不仅能够帮助工程师们模拟和分析电路的性能&#xff0c;还能够加速设计过程&#xff0c;降低成本&#xff0c;提高产品的质量和可靠性。今天&#xff0c;让我们一起挑战设计极限&#xff0c;揭秘电路仿真软件…

Java基础---反射

什么是反射&#xff1f; 反射允许对成员变量&#xff0c;成员方法和构造方法的信息进行编程访问。 这么说可能比较抽象&#xff0c;可以简单理解为&#xff1a;反射就是一个人&#xff0c;可以把类里面的成员变量&#xff0c;成员方法&#xff0c;构造方法都获取出来。 并且可…

Springcloud智慧工地APP云综合平台源码 SaaS服务

目录 智慧工地功能介绍 一、项目人员 二、视频监控 三、危大工程 四、绿色施工 五、安全隐患 具体功能介绍&#xff1a; 1.劳务管理&#xff1a; 2.施工安全管理&#xff1a; 3.视频监控管理&#xff1a; 4.机械安全管理&#xff1a; 5.危大工程监管&#xff1a; …

ctf_show笔记篇(web入门---反序列化)

目录 反序列化 254&#xff1a;无用&#xff0c;是让熟悉序列化这个东西的 255&#xff1a;直接使$isViptrue 256&#xff1a;还是使用变量覆盖 257&#xff1a;开始使用魔法函数 258&#xff1a;将序列化最前面的过滤了&#xff0c;使用绕过 259: 这一题需要看writeup才…

windows10 WSL启动Ubuntu虚拟机,安装DolphinScheduler

文章目录 1. 启动WSL与虚拟机2. 安装Docker与DolphinScheduler容器 1. 启动WSL与虚拟机 使用管理员权限运行命令&#xff1a; Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux重启后即可创建虚拟机 在Microsoft Store中搜索Ubuntu&…

研二双9找个日常实习都找不到,哎!

投了几家日常&#xff0c;要不就面完没反应&#xff0c;要不就秒挂&#xff0c;看不透了。是最近都在忙着处理春招和暑期实习吗&#xff0c;怎么连个日常实习都找不到&#xff1f; 个人背景双9&#xff0c;lc以前刷过200道&#xff0c;最近没怎么碰过。 腾讯 3.13 一面&#xf…

给老婆整了个短剧搜索机器人APP

最近短剧挺火&#xff0c;很多群友们都在做一些资源分享&#xff0c;老胡于是基于这些资源做了个短剧搜索引擎&#xff0c;挺多朋友喜欢看的&#xff0c;我老婆也在看哈哈&#xff0c;真上头&#xff0c;废话不多说&#xff0c;上短剧机器人。 短剧机器人 直接在微信群输入&…

麒麟 V10 一键安装 Oracle 11GR2(231017)单机版

Oracle 一键安装脚本&#xff0c;演示 麒麟 V10 一键安装 Oracle 11GR2 单机版过程&#xff08;全程无需人工干预&#xff09;&#xff1a;&#xff08;脚本包括 ORALCE PSU/OJVM 等补丁自动安装&#xff09; ⭐️ 脚本下载地址&#xff1a;Shell脚本安装Oracle数据库 脚本第…

提升合规性!Zoho如何优化CRM产品合规性?

在企业数字化和信息化高速发展的今天&#xff0c;CRM管理系统成为越来越多企业的选择。然而&#xff0c;不是所有CRM供应商都有合规意识。合规性不应当只是一项法律规定&#xff0c;更是保证CRM供应商持续发展、赢得客户信赖以及应付监管压力的关键支撑。Zoho对企业合规性的重视…

Python探索反距离加权空间插值方法的深度

介绍 反距离加权 (IDW) 是一种广泛用于地理信息系统 (GIS) 和环境科学的空间插值技术,用于根据附近位置的值估计任何位置的缺失值。其基本原理很直观:距离兴趣点较近的位置比距离较远的位置更相似。本文深入探讨了 IDW 的方法、应用、优势和局限性,深入探讨了其在空间分析中…

招聘必备知识:求职者跟进邮件如何写?

写一封正确的招聘跟进邮件是一门艺术。在面试结束后给你的候选人发一封好的后续邮件可以为招聘工作创造奇迹&#xff0c;甚至最终入职的候选人也是如此。 与候选人保持良好的沟通&#xff0c;可以确保他们一直参与其中&#xff0c;给予他们应得的尊重和赞赏。然而&#xff0c;…

机器学习——终身学习

终身学习 AI不断学习新的任务&#xff0c;最终进化成天网控制人类终身学习&#xff08;LLL&#xff09;&#xff0c;持续学习&#xff0c;永不停止的学习&#xff0c;增量学习 用线上收集的资料不断的训练模型 问题就是对之前的任务进行遗忘&#xff0c;在之前的任务上表现不好…

HarmonyOS系统开发ArkTS常用组件按钮及参数

Button组件有两种使用方式&#xff0c;分别是不包含子组件和包含子组件两种方式。不同方式Button 组件所需的参数有所不同。 1、不包含子组件 Button(label?: string, options?: { type?: ButtonType, stateEffect?: boolean }) label为按钮上显示的文字内容options.type…

21个 JVM 技术点详解(附面试解答)

最近兄弟们面试&#xff0c;都逃不过被 JVM 问题轰炸的命运&#xff0c;为啥面试官喜欢拿 JVM 说事呢&#xff1f;V 哥认为&#xff0c;除了要问倒你&#xff0c;就是要压你薪水&#xff0c;咱绝对不能怂&#xff0c;俗话说的好&#xff1a;兵来将挡&#xff0c;水来土掩&#…

模拟面试

1.TCP通信中的三次握手和四次挥手过程 三次握手 1.客户端像向服务器端发送连接请求 2.服务器应答连接请求 3.客户端与服务器简历连接 四次挥手&#xff1a; 客户端或服务器端发起断开请求,这里假设客户端发送断开请求 1.客户端向服务器发送断开请求 2.服务器应答断开请求 3.服…

JavaSE(上)-Day6

JavaSE&#xff08;上&#xff09;-Day6 数组数组的定义数组的初始化打印数组分析数组索引数组内存图 方法方法的定义和调用方法的重载方法的内存图 二维数组二位数组的创建和初始化二维数组的内存图 数组 1.数组是一种容器&#xff0c;可以一次存储多个相同类型的数据 数组的…

opengl日记9-opengl使用纹理示例

环境 系统&#xff1a;ubuntu20.04opengl版本&#xff1a;4.6glfw版本&#xff1a;3.3glad版本&#xff1a;4.6cmake版本&#xff1a;3.16.3gcc版本&#xff1a;10.3.0 直接上代码 CMakeLists.txt cmake_minimum_required(VERSION 3.5) set(CMAKE_C_STANDARD 11) set(CMAKE_…

【linux线程(三)】生产者消费者模型详解(多版本)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; Linux线程 1. 前言2. 初识生产…

【GameFramework框架内置模块】10、本地化(Localization)

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【GameFramework框架】系列教程目录&#xff1a; https://blog.csdn.net/q7…

哔哩哔哩秋招Java二面

前言 作者&#xff1a;晓宜 个人简介&#xff1a;互联网大厂Java准入职&#xff0c;阿里云专家博主&#xff0c;csdn后端优质创作者&#xff0c;算法爱好者 一面过后面试官叫我别走&#xff0c;然后就直接二面&#xff0c;二面比较简短&#xff0c;记录一下&#xff0c;希望可以…