提交 47105dd2 编写于 作者: 沉默王二's avatar 沉默王二 💬

新增三篇文章

上级 b7b77850
......@@ -174,6 +174,8 @@
- [详解Java中Comparable和Comparator的区别](docs/basic-extra-meal/comparable-omparator.md)
- [jdk9为何要将String的底层实现由char[]改成了byte[]?](docs/basic-extra-meal/jdk9-char-byte-string.md)
- [为什么JDK源码中,无限循环大多使用for(;;)而不是while(true)?](docs/basic-extra-meal/jdk-while-for-wuxian-xunhuan.md)
- [先有Class还是先有Object?](docs/basic-extra-meal/class-object.md)
- [instanceof关键字是如何实现的?](docs/basic-extra-meal/instanceof-jvm.md)
## Java并发编程
......@@ -262,6 +264,7 @@
## 辅助工具/轮子
- [Tabby:一款逼格更高的开源终端工具](docs/gongju/tabby.md)
- [Warp:一款21世纪人用的终端工具](docs/gongju/warp.md)
- [chiner:一款开源的数据库设计神器](docs/gongju/chiner.md)
- [DBeaver:一款免费的数据库操作工具](docs/gongju/DBeaver.md)
- [knife4j:一款界面更炫酷的API文档生成神器](docs/gongju/knife4j.md)
......
......@@ -234,6 +234,10 @@ export const sidebarConfig = defineSidebarConfig({
"basic-extra-meal/pass-by-value",
"basic-extra-meal/true-generic",
"basic-extra-meal/comparable-omparator",
"basic-extra-meal/jdk9-char-byte-string",
"basic-extra-meal/jdk-while-for-wuxian-xunhuan",
"basic-extra-meal/class-object",
"basic-extra-meal/instanceof-jvm",
],
},
{
......@@ -351,6 +355,7 @@ export const sidebarConfig = defineSidebarConfig({
collapsable: true,
children: [
"gongju/tabby",
"gongju/warp",
"gongju/chiner",
"gongju/DBeaver",
"gongju/knife4j",
......
......@@ -114,5 +114,5 @@ PS:按照首字母的自然顺序排列。
“二哥,你辛苦了,足足 48 个啊,容我好好消化一下。”
<img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png">
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
---
category:
- Java核心
tag:
- Java
---
# 先有Class还是先有Object?
Java 对象模型中:
- 所有的类都是Class类的实例,Object是类,那么Object也是Class类的一个实例。
- 所有的类都最终继承自Object类,Class是类,那么Class也继承自Object。
那到底是先有Class还是先有Object? JVM 是怎么处理这个“鸡·蛋”问题呢?
![](https://cdn.jsdelivr.net/gh/itwanger/toBeBetterJavaer/images/basic-extra-meal/class-object-2f47490c-70b8-41b8-9551-42c2f98eea91.png)
针对这个问题,我在知乎上看到了 R 大的一个回答,正好解答了我心中的疑惑,就分享出来给各位小伙伴一个参考和启发~
>作者:RednaxelaFX,整理:沉默王二,参考链接:https://www.zhihu.com/question/30301819/answer/47539163
-----
“鸡・蛋”问题通常都是通过一种叫“自举”(bootstrap)的过程来解决的。
“鸡蛋问题”的根本矛盾就在于假定了“鸡”或“蛋”的其中一个要先进入“完全可用”的状态。而许多现实中被简化为“鸡蛋问题”的情况实际可以在“混沌”中把“鸡”和“蛋”都初始化好,而不存在先后问题;在它们初始化的过程中,两者都不处于“完全可用”状态,而完成初始化后它们就同时都进入了可用状态。
打个比方,番茄炒蛋。并不是要先把番茄完全炒好,然后把鸡蛋完全炒好,然后把它们混起来;而是先炒番茄炒到半熟,再炒鸡蛋炒到半熟,然后把两个半熟的部分混在一起同时炒熟。
对于**先有Class还是先有Object**这个问题来说,题主假设所有的类都是Class类的实例,Object是类,那么Object也是Class类的一个实例,这个假设就是错的。
`java.lang.Object`是一个Java类,但并不是`java.lang.Class`的一个实例。后者只是一个用于描述Java类与接口的、用于支持反射操作的类型。这点上Java跟其它一些更纯粹的面向对象语言(例如Python和Ruby)不同。
第二个假设“所有的类都最终继承自Object类,Class是类,那么Class也继承自Object”是对的,`java.lang.Class``java.lang.Object`的派生类,前者继承自后者。
虽然第1个假设不对,但“鸡蛋问题”仍然存在:在一个已经启动完毕、可以使用的Java对象系统里,必须要有一个`java.lang.Class`实例对应`java.lang.Object`这个类;而`java.lang.Class``java.lang.Object`的派生类,按“一般思维”,前者应该要在后者完成初始化之后才可以初始化…
事实是:这些相互依赖的核心类型完全可以在“混沌”中一口气都初始化好,然后对象系统的状态才叫做完成了“bootstrap”,后面就可以按照Java对象系统的一般规则去运行。JVM、JavaScript、Python、Ruby等的运行时都有这样的bootstrap过程。
在“混沌”(boostrap过程)里,JVM可以为对象系统中最重要的一些核心类型先分配好内存空间,让它们进入[已分配空间]但[尚未完全初始化]状态。
此时这些对象虽然已经分配了空间,但因为状态还不完整所以尚不可使用。然后,通过这些分配好的空间把这些核心类型之间的引用关系串好。
到此为止所有动作都由JVM完成,尚未执行任何Java字节码。然后这些核心类型就进入了[完全初始化]状态,对象系统就可以开始自我运行下去,也就是可以开始执行Java字节码来进一步完成Java系统的初始化了。
在HotSpot VM里,有一个叫做“Universe”的C++类用于记录对象系统的总体状态。它有这么两个有趣的字段记录当前是处于bootstrapping阶段还是已经完全初始化好:
```
static bool is_bootstrapping() { return _bootstrapping; }
static bool is_fully_initialized() { return _fully_initialized; }
```
然后`Universe::genesis()`函数会在bootstrap阶段中创建核心类型的对象模型,其中会调用`SystemDictionary::initialize()`来初始化对象系统的核心类型,其中会进一步跑到`SystemDictionary::initialize_preloaded_classes()`来创建`java.lang.Object``java.lang.Class`等核心类型。
这个函数在加载了`java.lang.Object``java.lang.Class`等核心类型后会调用`Universe::fixup_mirrors()`来完成前面说的“把引用关系串起来”的动作:
```
// Fixup mirrors for classes loaded before java.lang.Class.
// These calls iterate over the objects currently in the perm gen
// so calling them at this point is matters (not before when there
// are fewer objects and not later after there are more objects
// in the perm gen.
Universe::initialize_basic_type_mirrors(CHECK);
Universe::fixup_mirrors(CHECK);
void Universe::fixup_mirrors(TRAPS) {
// Bootstrap problem: all classes gets a mirror (java.lang.Class instance) assigned eagerly,
// but we cannot do that for classes created before java.lang.Class is loaded. Here we simply
// walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note
// that the number of objects allocated at this point is very small.
// ...
}
```
就是这样:“**Object里有一个成员变量指向Class类实例c,c保存这个Object成员、方法的名字和地址的Map映射用作反射**。”涉及到主类有这么几个:
```
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ade5be2b1758/src/share/vm/memory/universe.hpp#l399
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ade5be2b1758/src/share/vm/memory/universe.cpp#l259
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ade5be2b1758/src/share/vm/classfile/systemDictionary.cpp#l1814
```
分享的最后,二哥要简单说两句,每次看 R 大的内容,总是感觉膝盖忍不住要跪一下,只能说写过 JVM 的男人就是不一样。喜欢研究 CPP 源码的话小伙伴可以再深入学习下,一定会有所收获。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
---
category:
- Java核心
tag:
- Java
---
# instanceof关键字是如何实现的?
小二那天去面试,碰到了这个问题:“**instanceof 关键字是如何实现的**?”面试官希望他能从底层来分析一下,结果小二没答上来,就来问我。
我唯唯诺诺,强装镇定,只好把 R 大的一篇回答甩给了他,并且叮嘱他:“认认真真看,玩完后要是还不明白,再来问我。。。”
>作者:RednaxelaFX,整理:沉默王二,链接:https://www.zhihu.com/question/21574535/answer/18998914
![](https://upload-images.jianshu.io/upload_images/1179389-d1b088bfd8ac0837.gif?imageMogr2/auto-orient/strip)
--------
### 场景一:月薪 3000 元一下的码农职位
用 Java 伪代码来表现instanceof关键字在Java语言规范所描述的运行时语义,是这样的:
```java
// obj instanceof T
boolean result;
if (obj == null) {
result = false;
} else {
try {
T temp = (T) obj; // checkcast
result = true;
} catch (ClassCastException e) {
result = false;
}
}
```
用中文说就是:如果有表达式 `obj instanceof T`,那么如果 obj 不为 null 并且 (T) obj 不抛 ClassCastException 异常则该表达式值为 true ,否则值为 false 。
如果面试官说“这不是废话嘛”,进入场景二。
### 场景二:月薪6000-8000的Java研发职位
JVM有一条名为 instanceof 的指令,而Java源码编译到Class文件时会把Java语言中的 instanceof 运算符映射到JVM的 instanceof 指令上。
javac是这样做的:
- instanceof 是javac能识别的一个关键字,对应到Token.INSTANCEOF的token类型。做词法分析的时候扫描到"instanceof"关键字就映射到了一个Token.INSTANCEOF token。
- 该编译器的抽象语法树节点有一个JCTree.JCInstanceOf类用于表示instanceof运算。做语法分析的时候解析到[instanceof运算符](https://tobebetterjavaer.com/oo/instanceof.html)就会生成这个JCTree.JCInstanceof类型的节点。
- 中途还得根据Java语言规范对instanceof运算符的编译时检查的规定把有问题的情况找出来。
- 到最后生成字节码的时候为JCTree.JCInstanceof节点生成instanceof字节码指令。
回答到这层面就已经能解决好些实际问题了,如果面试官还说,“这不还是废话嘛”,进入场景三。
### 场景三:月薪10000的Java高级研发职位
先简单介绍一下instanceof的字节码:
- 操作:确定对象是否为给定的类型
- 指令格式:instanceof|indexbyte1|indexbyte2
- 指令执行前后的栈顶状态:
- ……,objectref=>
- ……,result
再简单描述下:indexbyte1和indexbyte2用于构造对当前类的常量池的索引,objectref为reference类型,可以是某个类,数组的实例或者是接口。
基本的实现过程:对indexbyte1和indexbyte2构造的常量池索引进行解析,然后根据java规范判断解析的类是不是objectref的一个实例,最后在栈顶写入结果。
基本上就是根据规范来 YY 下实现,就能八九不离十蒙混过关了。
如果面试官还不满意,进入场景四。
### 场景四:月薪10000以上的Java资深研发职位
这个岗位注重性能调优什么的,R 大说可以上论文了:
>https://dl.acm.org/doi/10.1145/583810.583821
论文我也看不懂,所以这里就不 BB 了。(逃
篇论文描述了HotSpot VM做子类型判断的算法,这里简单补充一下JDK6至今的HotSpot VM实际采用的算法:
```java
S.is_subtype_of(T) := {
int off = T.offset;
if (S == T) return true;
if (T == S[off]) return true;
if (off != &cache) return false;
if ( S.scan_secondary_subtype_array(T) ) {
S.cache = T;
return true;
}
return false;
}
```
HotSpot VM的两个编译器,Client Compiler (C1) 与 Server Compiler (C2) 各自对子类型判断的实现有更进一步的优化。实际上在JVM里,instanceof的功能就实现了4份,VM runtime、解释器、C1、C2各一份。
VM runtime的:
>http://hg.openjdk.java.net/jdk7u/jdk7u/hotspot/file/tip/src/share/vm/oops/oop.inline.hpp
分享的最后,二哥简单来说一下。
这个问题涉及语法细节,涉及jvm实现,涉及编译器,还涉及一点点数据结构设计,比较考验一个 Java 程序员的内功,如果要回答到论文的程度,那真的是,面试官也得提前备好知识点,不然应聘者的回答啥也听不懂就挺尴尬的。
反正 R 大回答里的很多细节我都是第一次听,逃了逃了。。。。。。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
......@@ -149,7 +149,7 @@ Windows 用户习惯用 Xshell,macOS 用户习惯用 iTerm2,但这两款工
Tabby 的学习资料还比较少,所以希望二哥的这篇文章能给有需要的小伙伴提供一点点的帮助和启发。
<img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png" width="700px">
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
......
---
category:
- Java企业级开发
tag:
- 辅助工具/轮子
---
# Warp:一款21世纪人用的终端工具
大家好,我是二哥呀!
程序员的一生,用的最多的两个工具,一个是代码编辑器(Code Editor),另外一个就是命令行终端工具(Terminal)。这两个工具对于提高开发效率至关重要。
代码编辑器在过去的 40 年里不断进化,从我上大学敲 Java 代码开始,就经历了 MyEclipse、NetBeans、Eclipse,到如今称王称霸的 Intellij IDEA。
但终端工具,基本上和上个世纪七八十年代差不多。
那本期给大家推荐的这款终端——Warp——绝对会让你大开眼界,用完爱不释手!
>还记得之前给大家推荐的 [Tabby](https://mp.weixin.qq.com/s/HeUAPe4LqqjfzIeWDe8KIg) 吗?是时候喜新厌旧了。
![](https://files.mdnice.com/user/3903/339d626c-2bab-4386-82d9-81c058736f97.png)
Warp,一个超级牛叉的 terminal,号称是 21 世纪的终端,还未正式发布,就获得了两千三百万美元的融资。
>官方网站:[https://www.warp.dev/](https://www.warp.dev/)
Warp 在 GitHub 上也已经开源,目前已经有 2.8k+ 的 star 了。
![](https://files.mdnice.com/user/3903/8ebb72d9-f425-4f2e-b884-5ad59db73d2f.png)
>GitHub 地址:[https://github.com/warpdotdev/Warp](https://github.com/warpdotdev/Warp)
Warp 号称自己“Reinvent the Terminal”,也就是重新定义了终端,用过 vscode 的小伙伴是不是对这句口号似曾相识?
是的,vscode 号称自己“Code editing Redefined”,也就是重新定义了代码编辑器。
### 一、安装 Warp
直接到官网 `warp.dev` 点击「download now」就可以下载最新版了。下载完成后,双击安装包就可以安装了。完成后打开,界面还是非常清爽的。
![](https://files.mdnice.com/user/3903/748e966f-899b-4632-91b4-01d797ea3127.png)
Warp 支持 GitHub 账户登录。不过,如果你在登录的过程中因为某些原因无法完成跳转,可以通过下面的链接自行解决。
>[https://embiid.blog/post/WARP-does-not-work-after-submitting-an-invite-code/](https://embiid.blog/post/WARP-does-not-work-after-submitting-an-invite-code/)
如果顺利登录,会跳转到这个页面。
![](https://files.mdnice.com/user/3903/664c32a7-92fe-47a0-8892-da651cdfa2a6.png)
填写一些 Warp 的调查信息后,就会跳转到 Warp 的初始界面。
![](https://files.mdnice.com/user/3903/fb62c2f1-dcd5-4881-be37-e9f462c8655f.png)
>需要注意的是,Warp 目前仅支持 macOS 版,Linux 和 Windows 用户还需要等待一段时间。
![](https://files.mdnice.com/user/3903/e82cb7fd-8050-4c48-9958-b4ddffb4e295.png)
其实 macOS 版也是刚刚公测,我这份攻略绝壁是热乎乎的。想要第一时间关注 Warp 版本信息的话,可以戳下图中提到的链接填写自己的邮箱。
![](https://files.mdnice.com/user/3903/66d3abf2-b8cd-4058-b63b-5c7a4075bc99.png)
### 二、使用 Warp
Warp 解决的第一个痛点,就是减少配置、方便输入、优化输出,并且增加常用命令的自动提示。
**1)智能提示**
普通的终端在你键入 tab 的时候,是这样提示的,就是简单地帮你罗列下。
![](https://files.mdnice.com/user/3903/47ee4d50-2d55-4f10-9f1f-cbfc37b27a6c.png)
而 Warp 就非常的时髦,会给你滚动可选的列表形式展示出来。
![](https://files.mdnice.com/user/3903/21478ba4-9484-4e55-924b-c2f8302cccbb.png)
Warp 的智能提示也更加“智能化”,它会猜测你下一步的命令到底输入什么。
比如说我的工作目录下有一个 README.md 的文件,那当我输入 `echo '沉默王二' >>`的时候它会把 `README.md` 提示在后面。
![](https://files.mdnice.com/user/3903/047573a9-69b3-4e73-ae1f-74f6bc8d02ce.png)
**2)智能记忆**
Warp 会记录上一次执行的命令,在顶部会有一个提示的按钮,当你点击的时候,它会自动滚动到上一个命令执行的位置。
点击「clear」之前。
![](https://files.mdnice.com/user/3903/4966cc3b-a258-4f09-84f4-c76cb06df9c0.png)
点击「clear」之后。
![](https://files.mdnice.com/user/3903/e36c9f70-c6f1-44d9-8747-9ed8baa414dc.png)
**3)区域选择**
传统的终端,在复制区域命令和输出结果的时候需要全部手动选择,而 Warp 是可以点选的,之后可以通过右键菜单进行复制粘贴(可以选择只复制命令或者输出,也可以都选),非常方便。
![](https://files.mdnice.com/user/3903/8021dcc3-b82a-442c-9157-122cad00dec9.png)
**4)历史命令**
传统的终端在通过 up-down 键选择历史命令的时候,一次只能提示一个命令。而 Warp 会把历史命令做成一个滚动的可以选择的列表。
![](https://files.mdnice.com/user/3903/c271f291-194a-4bbb-b86f-ddd3bcb4d867.png)
**5)命令导航**
同时按下 Ctrl+Shift+R 可以打开命令导航,Warp 集成了很多工具的命令导航。比如说我们要执行 `git reset` 命令,那么到底格式什么,应该怎么执行,Warp 都提示的非常到位。
![](https://files.mdnice.com/user/3903/90b3d18b-f694-45fb-aa5c-c8c2c698c6b5.png)
这让我想起了 macOS 的效率工具 Alfred,可以搜索任何你想要的命令。
**6)AI 植入**
Warp 还提供了 AI 智能搜索,快捷键可以在 setting→keyboard shortcuts 中找得到,键入 AI 关键字即可。
可调整为自己喜欢的快捷键。我目前设置的是 `Ctrl+shift+>`
![](https://files.mdnice.com/user/3903/f5547fba-ed52-4075-b8d3-66b40ab306bc.png)
比如说我问它“how many lines were changed in the last 2 commits?”
![](https://files.mdnice.com/user/3903/d3aec963-5b03-4c79-ad54-7c035466eac6.png)
Warp 解决的第二个痛点是增加协作功能。不过由于我目前没有邀请其他用户参与,还无法使用共享功能,后面有小伙伴体验的话,可以通过我分享的链接下载试一波。
>https://app.warp.dev/referral/25KR3Y
![](https://files.mdnice.com/user/3903/1ea837e4-fd61-4d36-ad8d-e36142fd523d.png)
### 三、配置 Warp
输入 Command+P 快捷键可以打开 Warp 的命令面板。
![](https://files.mdnice.com/user/3903/dcd95676-6887-4534-9056-13f3882a03dc.png)
键入 `sett` 关键字就可以打开配置页。
比如说在「Appearance」选项卡里可以设置 Warp 的主题、字体,以及紧凑型模式。
大概有十多种主题可选,比如说这个女生非常喜欢的粉色系。
![](https://files.mdnice.com/user/3903/3fcb594a-7e5f-43a9-855c-05ad14f5de40.png)
更多主题可以到 GitHub 仓库的 theme 页。
>[https://github.com/warpdotdev/themes](https://github.com/warpdotdev/themes)
至于快捷键配置,如果不确定有哪些快捷键可以尝试,直接点击 Warp 顶部的这个温馨提示「welcome tips」就可以了。
![](https://files.mdnice.com/user/3903/be7b55cc-3547-42a0-9127-56b6174a5448.png)
### 四、总结
最后总结一波吧。
这波着实属于尝鲜了,市面上应该还木有 Warp 终端的普及安利文章,我这期应该属于大姑娘坐花轿———头一回。
害,登录折腾了好久,原因我就不多说了,小伙伴们自行体会哈。反正我是没被劝退。
幸好是没放弃,所以才体验到了 Warp 的强大之处,真的是改变了我对终端 terminal 的认知——太特喵的炫酷了!
这个过程就有点陶渊明《桃花源记》里那句“初极狭,复行数十步,豁然开朗”的赶脚。
喜欢的小伙伴一定要尝试一把,你会来感谢我的。好了,这期就先聊到这吧,毕竟 Warp 刚公测,后面有机会再来给大家详细地说。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
\ No newline at end of file
......@@ -184,6 +184,8 @@ headerDepth: 1
- [详解Java中Comparable和Comparator的区别](basic-extra-meal/comparable-omparator.md)
- [jdk9为何要将String的底层实现由char[]改成了byte[]?](basic-extra-meal/jdk9-char-byte-string.md)
- [为什么JDK源码中,无限循环大多使用for(;;)而不是while(true)?](basic-extra-meal/jdk-while-for-wuxian-xunhuan.md)
- [先有Class还是先有Object?](basic-extra-meal/class-object.md)
- [instanceof关键字是如何实现的?](basic-extra-meal/instanceof-jvm.md)
### Java并发编程
......@@ -270,6 +272,7 @@ headerDepth: 1
### 辅助工具/轮子
- [Tabby:一款逼格更高的开源终端工具](gongju/tabby.md)
- [Warp:一款21世纪人用的终端工具](docs/gongju/warp.md)
- [chiner:一款开源的数据库设计神器](gongju/chiner.md)
- [DBeaver:一款免费的数据库操作工具](gongju/DBeaver.md)
- [knife4j:一款界面更炫酷的API文档生成神器](gongju/knife4j.md)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册