0%

jenv 是和 pyenv 一个类型的工具,应对多版本 java 的需求进行管理。简单记录一下 jenv 安装使用方法。官方教程。需要注意的是在配置文件里添加完设置之后需要重起终端,不然文件夹什么还没有创建出来。

CMDs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 安装
brew install jenv

# bashrc/zshrc 中添加配置
export PATH="$HOME/.jenv/bin:$PATH"
eval "$(jenv init -)"

# local 已经安装的版本检测
which java

# 查看 brew 安装的 Java 路径
brew list java

# 可以看到安装的路径是 /usr/local/Cellar/openjdk/XXX
# 默认就是从 openjdk repo 下载的
# 如果想安装其他版本可以 special 一下 version: brew list openjdk@11

# jenv 添加 home 路径
jenv add /usr/local/Cellar/openjdk@11/11.0.9

# 查看可用版本
jenv versions

# 如果想要只在某个路径下面指定 java 版本,可以 cd 到目标目录下,使用
jenv local 14

# 删除某个版本
jenv remove 14

一个最简单的例子,当我们在 IDE 中写入 Hello World 代码,并右键运行后,控制台会打印出来 Hello World! 的字符串,那么这中间到底发生了什么?

1
2
3
4
5
6
7
8
public class Hello {
String name = "Jack";
public static void main(String[] args) {
Hello test = new Hello();
System.out.println("Hello " + test.name);
while (true) {}
}
}

写入 IDE 里的代码都是存到 .java 文件中的,在保存后 IDE 会将它编译为 .class 文件。这个文件也叫字节码文件,有自己的一套规则。之后当我们运行这个字节码文件时,一个 JVM 虚拟机被启动,解析这个文件,将文件中的各种变量,方法分配到虚拟机的各功能区。运行代码中的打印逻辑,并输出到终端。

java -> class

从 java 文件到 class 的功能可以简单概括为 javac 命令的功能。其中主要涉及到编译器的相关只是,可以参考 编译原理 加深了解。简单概括步骤有:词法分析 -> 语法分析 -> 语义分析 -> 字节码生成

运行

运行主要涉及到 JVM 启动,类加载,逻辑执行,可以通过看 深入理解JVM虚拟机 加深了解

jmap 查看堆中对象分布

运行示例代码,通过 ps -ef | grep Hello 拿到线程 pid. 然后使用 jmap -heap <pid> 查看对象情况。结果失败。。。

PS: jps 可以很方便的查看 java 程序 pid

1
2
3
4
5
Jack > ~ > jmap -heap 68202
Attaching to process ID 68202, please wait...
ERROR: attach: task_for_pid(68202) failed: '(os/kern) failure' (5)
Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.
sun.jvm.hotspot.debugger.DebuggerException: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.

操作系统为 MacOS, java1.8。一开始说是权限问题,但是用了 root 也不顶用,然后说是 1.8 以前不支持。本地安装 j14 然后按照之前的步骤运行 cmd 还是一样的错误。在 14 版本中,命令变了,j9 之后需要使用 jhsdb jmap --heap --pid 68633 做查询。难道是 MacOS 需要什么特殊设置 (´Д` ) 容我找太其他系统的机子试试水先。。。

可能就是系统问题把,或者公司的机子有什么限制?用家里的 Windows 试了下是可以 work 的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
PS C:\Users\jack> jhsdb jmap --heap --pid 10648
Attaching to process ID 10648, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0.6+8-LTS

using thread-local object allocation.
Garbage-First (G1) GC with 4 thread(s)

Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 2118123520 (2020.0MB)
NewSize = 1363144 (1.2999954223632812MB)
MaxNewSize = 1270874112 (1212.0MB)
OldSize = 5452592 (5.1999969482421875MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 1048576 (1.0MB)

Heap Usage:
G1 Heap:
regions = 2020
capacity = 2118123520 (2020.0MB)
used = 1048576 (1.0MB)
free = 2117074944 (2019.0MB)
0.04950495049504951% used
G1 Young Generation:
Eden Space:
regions = 1
capacity = 15728640 (15.0MB)
used = 1048576 (1.0MB)
free = 14680064 (14.0MB)
6.666666666666667% used
Survivor Space:
regions = 0
capacity = 0 (0.0MB)
used = 0 (0.0MB)
free = 0 (0.0MB)
0.0% used
G1 Old Generation:
regions = 0
capacity = 118489088 (113.0MB)
used = 0 (0.0MB)
free = 118489088 (113.0MB)
0.0% used

使用 histo 参数查看对象大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PS C:\Users\jack> jhsdb jmap --histo --pid 10648
Attaching to process ID 10648, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0.6+8-LTS
Iterating over heap. This may take a while...
Object Histogram:

num #instances #bytes Class description
--------------------------------------------------------------------------
1: 551 357184 char[]
2: 3641 258616 byte[]
3: 1629 98808 java.lang.Object[]
...
304: 1 16 float[]
305: 1 16 boolean[]
306: 1 16 Hello
...

打开 DBeaver -> Preferences -> 搜索 Maven -> Add, 填入信息 http://maven.aliyun.com/nexus/content/groups/public/,调整一下顺序,放到第一位。打完收工~

PS: 设置只有在新建 connection 时生效,所以已经创建的,删了重建即可

最近在调查一个 build issue 的时候发现有一段函数声明大致如下

1
2
3
4
5
6
7
8
9
10
11
public class ParameterTest {

public static void main(String[] args) {
ParameterTest parameterTest = new ParameterTest();
parameterTest.test(new String[]{"Jack"});
}

public void test(String list[]) {
System.out.println(list);
}
}

但是就感觉很好奇,test(String list[]) 这样的声明竟然能通过编译检测。查了下资料,这中做法是合法的,是 C 语言中数组的声明方式,大概是早期为了让 C 程序员能更好的迁移过来做的兼容把,表达的语意和 test(String[] list) 是完全一样的。

果然一个老项目里面什么情况都能遇到 ╮( ̄▽ ̄””)╭

记录平时遇到的一些精巧的小代码段

创建元组

摘自 On Java 8 泛型章节。元组的定义:用户只能取值而不能设置值,所以这里没有使用 getter/setter 的封装形式,而是使用 public + final 关键字实现了该功能。

1
2
3
4
5
6
7
8
9
10
11
public class Tuple2<A, B> {
public final A a1;
public final B a2;
public Tuple2(A a, B b) { a1 = a; a2 = b; }
public String rep() { return a1 + ", " + a2; }

@Override
public String toString() {
return "(" + rep() + ")";
}
}

lambda

实现 interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestLambda {
private MyPrint print;

@Test
public void test() {
print = System.out::println;
print.print("jack");
}
}

interface MyPrint {
void print(String name);
}
// output: jack

判断 collection 中是否包含某元素

1
Arrays.asList(1, 2, 3).stream.anyMatch(sub -> sub > 3);

记录一下泛型的定义,历史,使用案例等。素材主要来源于 On Java 8, Thinking in Java 和 Effective Java。

历史

1.5 版本引入,主要动机是支持 Collection 类

泛型方法

把这一块放到最前面时为了避免理解上的误区,泛型方法和泛型类,泛型接口没有从属关系,就算是普通的 Utils 方法也可以声明泛型方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class GenericUtils {
public static <T> void printParam(T t) {
System.out.println(t);
}
}

@Test
public void test_print() {
GenericUtils.printParam("Jack");
GenericUtils.printParam(1);
}

// Output:
// Jack
// 1

泛型类

即在声明类时添加类型声明,最常见的如 Collection 系列下的 ArrayList

1
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { ... }

泛型接口

泛型接口只是在接口定义的时候在接口名称后接上类型声明而已。使用 lang 包中自带的 Supplier 接口为例,接口在声明时指定类型,并在 get() 方法中指定返回类型。

1
2
3
4
5
6
// 1.8 中引入的接口,充当工厂方法的角色
@FunctionalInterface
public interface Supplier<T> { T get(); }

Supplier<Integer> integerSupplier = () -> (new Random()).nextInt();
System.out.println(integerSupplier.get());

使用案例

记录一下工作生活中遇到的具体使用案例

代码重构

公司代码重构时遇到下面这种情况:

比如原来有个类叫 Background, 重构时为他抽了一个 interface IBackground。但是在替换一些集合相关的代码时出现了不兼容的问题。

1
2
3
4
5
6
7
8
// before
List<Background> list = someClass.getBackgroundList();
// what I prefer to, but compile failed
List<IBackground> list = someClass.getBackgroundList();
// what I should do
List<IBackground> list = new ArrayList<>(someClass.getBackgroundList());
// or
List<? extends IBackground> list = someClass.getBackgroundList();

上面的这种转换失败就是由泛型转化异常造成的

指定泛型返回值为某个类的子类

可以使用泛型方法

1
public void <T extends Sup>  T getSometing() {};

返回 Map 类型的泛型方法?

这种用法称为 multi-level wildcards,参考 这篇 文章中的定义

子类现有方法为

1
2
3
public Map<String, List<Sub>> getResult() {
new HashMap<String, List<Sub>>();
}

想要给他一个抽 interface 类似 Map<String, List<? extends Sup>> getResult(); 但是会编译错误,需要怎么写?

先说答案,可以使用 Map<String, ? extends List<? extends Sup>> getResult(); 这样的语法来适配上面说的这种场景

关于这个问题的几个点:

  1. List<Sub> 并不是 List<Sup> 的子类,想要表达子类的概念,Java 使用的是 List<? extends Sup> 这样的语法
  2. List<List<?>> 适配所有的参数类型的 list
  3. List<? extends List<String>> 适配任何 List 及其子类
  4. 两者结合一下 List<? extends List<?>> 适配任何 list 及其子类,并且适配所有参数类型

Code sample:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface Sup { }

public interface Sub extends Sup { }

public interface Father {
Map<String, ? extends List <? extends Sup>> getNestMap();
}

public class Son implements Father {
@Override
public Map<String, List<Sub>> getNestMap() {
Map<String, List<Sub>> map = new HashMap<>();
List<Sub> list = new ArrayList<>();
list.add(new Sub());
map.put("Jack", list);
return map;
}
}

PS: List 前的 ? extends 是不可少的,不然 Override 方法会编译错误,应为实现中是用 ArrayList 这个子类实现的,所以接口定义时语意上要有这个声明

工作中遇到的问题

1
2
3
4
5
6
// 下面两个方法有没有区别?
public interface WildCardTest {
<T extends Sup> List<T> getList01();

List<? extends Sup> getList02();
}

没有。。。看了一下这两个方法编译出来的字节码是完全一样的,除了行号。

1
2
3
4
5
6
7
8
9
// access flags 0x401
// signature <T::Lcom/playground/genericsample/Sup;>()Ljava/util/List<TT;>;
// declaration: java.util.List<T> getList01<T extends com.playground.genericsample.Sup>()
public abstract getList01()Ljava/util/List;

// access flags 0x401
// signature ()Ljava/util/List<+Lcom/playground/genericsample/Sup;>;
// declaration: java.util.List<? extends com.playground.genericsample.Sup> getList02()
public abstract getList02()Ljava/util/List;

但是这两种表达方式在实现的时候还是有区别的,用界限符(?)的这种,要求在集合类型前面也加上界限符。。。

向 List<? extends Number> 中添加数据失败

List<? extends Number> list = new ArrayList<>(); list.add(3); 向该 list 中添加数据 3 有编译错误。这是应为通过 List<? extends Number> list 声明的 list 可以存储 Number 及其子类,效果上来看下面这些声明的集合只是 ? extends Number 的一部分,那么我们加 3 这个行为在类型一致这个前提下就会有与以上的错误。一般这种声明方式拿到的结果只用于读操作。

1
2
3
List<? extends Number> foo3 = new ArrayList<Number>();  // Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>(); // Double extends Number

方法中同时有 Class T 和 T bean 的情况怎么兼容

声明一个 list 类型是 <? extends Number> 我们还有一个方法参数列表 Class<T> clz1, T clz2 这种情况下怎么兼容。

1
2
3
4
5
6
7
8
9
10
11
public class TestGeneric {
public static void main(String[] args) {
List<Class<? extends Number>> list = Arrays.asList(Integer.class, Double.class, Long.class);
// !testGeneric(list.get(0), 1); // compile failed
testGeneric(Integer.class, 1);
}

public static <T> void testGeneric(Class<T> clz1, T clz2) {
// do something
}
}

语法上就兼容不了,无解,最后通过重新理解 event 系统,根据框架重新安排逻辑绕过了 (; ̄ェ ̄) 等读完泛型相关的章节可以再回头看看,不知道到时会不会有新解

最新消息,上面的有解,只需要在前面加上强转到 Class 类型即可 testGeneric((Class)list.get(0), 1); 资深的还是厉害啊,佩服佩服 (●°u°●)​ 」不过直接把 Class 类强转就能绕过检测我是没想到,六的飞起。

问题记录:

项目由多个 repo 组成,当这些 repo 中存在相同路径,相同名称的类时,JVM 会怎么处理?

问题记录:

在做项目重构的时候遇到如下问题,repo1 下有 class A, 重构时我们在 repo1 中抽象出一个 interface FA 实现 A 的所有的方法,然后修改外部引用使 A 解偶。其中发现一个很有趣的现象,原先 repo2 使用 A 编译出来的 jar, 不做任何修改还是可以和 FA 源码进行编译,但是使用 repo2 的源码和 FA 源码进行编译会抛 mismatch 的 exception。猜测和 Java 编译规则有关系,难道是编译后的文件其实是一样的,所以原来的 jar 可以通用,但是源码的话和编译规则有冲突会挂。

本地试了下,并不能重现,不清楚是重现的不对还是公司的项目有什么特殊的处理方式,有机会再看看把 ╮( ̄▽ ̄””)╭

记录一下 Java 注解的学习过程

快速入门

设计一个测试案例,创建一个名为 Marked 的注解类,该注解可以添加在 method 上用来表示方法是否被标记过。在测试用力中遍历被标记的类并打印信息

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Person {
private String name;
private int age;
private boolean isSelected;

// Getter/Setter methods

@Marked
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Marked(value = true)
public int getAge() {
return age;
}
// ...
}

自己创建的注解类:

1
2
3
4
@Retention(RetentionPolicy.RUNTIME)
public @interface Marked {
boolean value() default false;
}

测试用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void test_print_by_anno() {
Method[] methods = Person.class.getDeclaredMethods();
for (Method m : methods) {
Marked myAnno = m.getAnnotation(Marked.class);
if (myAnno != null) {
System.out.println("Method: " + m.getName() + " has marked annotation.");
System.out.println("Marked value: " + myAnno.value());
} else {
System.out.println("Method: " + m.getName() + " don't has marked annotation.");
}
}
}

终端打印:

1
2
3
4
5
6
7
8
Method: getName has marked annotation.
Marked value: false
Method: setName don't has marked annotation.
Method: getAge has marked annotation.
Marked value: true
Method: setAge don't has marked annotation.
Method: isSelected don't has marked annotation.
Method: setSelected don't has marked annotation.

从这个例子可以看出来,Annotation 都是处理 class level 的问题的,和类延伸出来的实例基本没关系了

记录一下新系统常用配置和软件安装

MacOS 显示隐藏文件

cmd + shift + .

Homebrew

官网推荐的通过 curl raw 文件安装,本地没有 proxy 的话 pass,基本不动。可以直接通过 git clone https://github.com/Homebrew/install 这个 repo 然后 cd 到 install 文件夹下执行 /bin/bash -c ./install.sh 来触发任务

速度测试

运行如下命令,查看是哪个步骤速度比较慢

1
brew update --verbose
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
jack@PC /usr/local/Homebrew/stable brew update --verbose
Checking if we need to fetch /usr/local/Homebrew...
Checking if we need to fetch /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask...
Fetching /usr/local/Homebrew...
Checking if we need to fetch /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core...
Checking if we need to fetch /usr/local/Homebrew/Library/Taps/homebrew/homebrew-services...
Fetching /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core...
Fetching /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask...
remote: Counting objects: 5806, done.
remote: Compressing objects: 100% (2626/2626), done.
remote: Total 5806 (delta 4179), reused 4564 (delta 3087)
Receiving objects: 100% (5806/5806), 1.30 MiB | 203.00 KiB/s, done.
Resolving deltas: 100% (4179/4179), completed with 375 local objects.
From https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew
7b67ac5e3..a4d7bb64a master -> origin/master
* [new tag] 2.1.10 -> 2.1.10
* [new tag] 2.1.11 -> 2.1.11
* [new tag] 2.1.12 -> 2.1.12
* [new tag] 2.1.13 -> 2.1.13
* [new tag] 2.1.14 -> 2.1.14
* [new tag] 2.1.15 -> 2.1.15
* [new tag] 2.1.16 -> 2.1.16
* [new tag] 2.1.3 -> 2.1.3
* [new tag] 2.1.4 -> 2.1.4
* [new tag] 2.1.5 -> 2.1.5
* [new tag] 2.1.6 -> 2.1.6
* [new tag] 2.1.7 -> 2.1.7
* [new tag] 2.1.8 -> 2.1.8
* [new tag] 2.1.9 -> 2.1.9
remote: Counting objects: 71830, done.
remote: Compressing objects: 100% (27226/27226), done.
remote: Total 71830 (delta 53303), reused 62922 (delta 44592)
Receiving objects: 100% (71830/71830), 21.95 MiB | 11.70 MiB/s, done.
Resolving deltas: 100% (53303/53303), completed with 4020 local objects.
From https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core
ea056b500e..6ec9c907ea master -> origin/master
remote: Enumerating objects: 235987, done.
remote: Counting objects: 100% (215906/215906), done.
remote: Compressing objects: 100% (58941/58941), done.
Receiving objects: 45% (92674/205138), 23.64 MiB | 345.00 KiB/s

更新 Brew 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 替换brew.git:
cd "$(brew --repo)"
git remote set-url origin https://mirrors.ustc.edu.cn/brew.git

# 替换homebrew-core.git:
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git

# 替换homebrew-cask.git:
cd "$(brew --repo)"/Library/Taps/homebrew/homebrew-cask
git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-cask.git

# 替换 homebrew bottles 源, zsh 用户:
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.zshrc
source ~/.zshrc

# 替换 homebrew bottles 源, bash 用户:
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.bash_profile
source ~/.bash_profile

如果这个源挂了可以试试清华的

update warning

brew update 抛 warning

1
2
3
4
5
6
7
8
9
Updating /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core...
fatal: It seems that there is already a rebase-apply directory, and
I wonder if you are in the middle of another rebase. If that is the
case, please try
git rebase (--continue | --abort | --skip)
If that is not the case, please
rm -fr ".git/rebase-apply"
and run me again. I am stopping in case you still have something
valuable there.

存在 /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/rebase-apply 这样的备份文件,通过 rm -rf rebase-apply 删掉就好了

Reference

Iterm2

  • 最大化窗口:CMD + Ctrl + F
  • Item2 最大化终端:CMD + Enter

可以通过下载 官方 zip 包离线安装,也可以通过 brew 安装 brew cask install iterm2。brew 会比较慢

修改提示符

1
2
3
prompt_context () {
prompt_segment black default "Jack"
}

配置 solarized 配色方案

最新版的系统已经默认支持这个配色方案了,打开 iterm2 终端,cmd + , 打开配置窗口。 Preferences -> Profiles -> Colors -> Color Presets -> Solarized Dark

oh-my-zsh

官方 git 地址, 应为网络原因选择 clone repo 安装: git clone https://github.com/ohmyzsh/ohmyzsh.git + sh -c './install.sh

重启后终端抛出 warning

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Last login: Mon Aug  3 18:08:08 on ttys000
[oh-my-zsh] Insecure completion-dependent directories detected:
drwxrwxr-x 3 jack admin 96 Aug 3 13:18 /usr/local/share/zsh
drwxrwxr-x 4 jack admin 128 Aug 3 13:22 /usr/local/share/zsh/site-functions

[oh-my-zsh] For safety, we will not load completions from these directories until
[oh-my-zsh] you fix their permissions and ownership and restart zsh.
[oh-my-zsh] See the above list for directories with group or other writability.

[oh-my-zsh] To fix your permissions you can do so by disabling
[oh-my-zsh] the write permission of "group" and "others" and making sure that the
[oh-my-zsh] owner of these directories is either root or your current user.
[oh-my-zsh] The following command may help:
[oh-my-zsh] compaudit | xargs chmod g-w,o-w

[oh-my-zsh] If the above didn't help or you want to skip the verification of
[oh-my-zsh] insecure directories you can set the variable ZSH_DISABLE_COMPFIX to
[oh-my-zsh] "true" before oh-my-zsh is sourced in your zshrc file.

运行如下 cmd 修复

1
2
chmod 755 /usr/local/share/zsh
chmod 755 /usr/local/share/zsh/site-functions

配置命令高亮: brew install zsh-syntax-highlighting 并在 .zshrc 中添加配置行 source /usr/local/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

配置命令自动补全提示: git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions 添加 .zshrc 配置 plugins=(zsh-autosuggestions)

为提示插件绑定快捷键: 在 zshrc 文件中添加配置 bindkey '^ ' autosuggest-accept, MacOS 下这个快捷键和系统默认的输入法切换冲突,在 System Preferences -> keyboard -> shortcuts -> input sources 下将 select the previous input source 和 selet the next input soure menue 的勾选去掉就行了

PS: 这个快捷键在 VSCode 的 terminal 上不能 work, 试着把 vscode 自带的 ctrl + space 都改掉还是没效果(´Д`) 先凑合着用把,干

PPS: 想要重新绑定 shift + space 为补全,不过找不到对应的 zsh code, 擦擦擦。在 linux 下有款终端工具叫 showkey 的貌似可以解决这个问题, 也可以试试终端输入 cat 回车,按键他就会打印出来键符,不过 shift 貌似没给提示。。。

solarized dark 配色和 zsh-autosuggestion 自动提示配色有冲突,会看不到,参考 issue。我本地直接把配色改成系统自带的 Tango Dark 了

设置字体

使用 agnoster 主题时需要加载一个字体,不然很多箭头之类的表示符会显示乱码。下载字体:git clone https://github.com/powerline/fonts.git, 找到 fonts/Meslo Slashed/Meslo LG M Regular for Powerline.ttf 双击安装。 然后打开 iTerm2,按 Command + , 键,打开 Preferences 配置界面,然后Profiles -> Text -> Font -> Chanage Font,选择 Meslo LG M Regular for Powerline 字体。

VSCode

打开 VSCode, CMD + SHIFT + P, 选择 Shell Command: Install 'code' command in PATH 命令,应用会自动安装好,在终端输入 code 测试

配置完 zsh 之后,VSCode 的终端会显示乱码,cmd + shift + p 搜索 ‘Preferences: Open Settings(JSON)’ 添加配置 { "terminal.integrated.fontFamily": "Meslo LG M for Powerline" } 即可修复,保存后可以看到效果。

VSCode 在终端安装 code 命令之后每次重启都会失效,应该是因为我只是把它放在 Document, Download 文件夹下面了。把它放到 Application 下再安装一下 shell 继承命令就可以了。顺带着之前 zsh-autosuggestion 不能补全也是这个原因!!!

安装 VirtualBox

MacOS 10.15.6 Catalina 安装 VirtualBox 的时候报错,安装失败,是应为 MacOS 默认设置是禁止安装 Oracle 公司产品的,你可以去 System Preference -> Security & Privacy 页面点一下左下方的小锁,允许安装 Oracle 相关软件。再重新安装一下,就行了。

使用 IDEA 的快捷键时跳出窗口

窗口内容: “No manual entry for “, Refer to Official IDEA Support

MacOS since 10.14, 官方定义了这个快捷键,和 IDEA 冲突了,Keyboard -> shortcut -> service -> search man page index in terminal 把这个选项 disable 掉,或者替换掉