jenv 是和 pyenv 一个类型的工具,应对多版本 java 的需求进行管理。简单记录一下 jenv 安装使用方法。官方教程。需要注意的是在配置文件里添加完设置之后需要重起终端,不然文件夹什么还没有创建出来。
CMDs
1 | # 安装 |
jenv 是和 pyenv 一个类型的工具,应对多版本 java 的需求进行管理。简单记录一下 jenv 安装使用方法。官方教程。需要注意的是在配置文件里添加完设置之后需要重起终端,不然文件夹什么还没有创建出来。
1 | # 安装 |
一个最简单的例子,当我们在 IDE 中写入 Hello World 代码,并右键运行后,控制台会打印出来 Hello World!
的字符串,那么这中间到底发生了什么?
1 | public class Hello { |
写入 IDE 里的代码都是存到 .java
文件中的,在保存后 IDE 会将它编译为 .class
文件。这个文件也叫字节码文件,有自己的一套规则。之后当我们运行这个字节码文件时,一个 JVM 虚拟机被启动,解析这个文件,将文件中的各种变量,方法分配到虚拟机的各功能区。运行代码中的打印逻辑,并输出到终端。
从 java 文件到 class 的功能可以简单概括为 javac 命令的功能。其中主要涉及到编译器的相关只是,可以参考 编译原理 加深了解。简单概括步骤有:词法分析 -> 语法分析 -> 语义分析 -> 字节码生成
运行主要涉及到 JVM 启动,类加载,逻辑执行,可以通过看 深入理解JVM虚拟机 加深了解
运行示例代码,通过 ps -ef | grep Hello
拿到线程 pid. 然后使用 jmap -heap <pid>
查看对象情况。结果失败。。。
PS: jps 可以很方便的查看 java 程序 pid
1 | Jack > ~ > jmap -heap 68202 |
操作系统为 MacOS, java1.8。一开始说是权限问题,但是用了 root 也不顶用,然后说是 1.8 以前不支持。本地安装 j14 然后按照之前的步骤运行 cmd 还是一样的错误。在 14 版本中,命令变了,j9 之后需要使用 jhsdb jmap --heap --pid 68633
做查询。难道是 MacOS 需要什么特殊设置 (´Д` ) 容我找太其他系统的机子试试水先。。。
可能就是系统问题把,或者公司的机子有什么限制?用家里的 Windows 试了下是可以 work 的
1 | PS C:\Users\jack> jhsdb jmap --heap --pid 10648 |
使用 histo 参数查看对象大小
1 | PS C:\Users\jack> jhsdb jmap --histo --pid 10648 |
打开 DBeaver -> Preferences -> 搜索 Maven -> Add, 填入信息 http://maven.aliyun.com/nexus/content/groups/public/
,调整一下顺序,放到第一位。打完收工~
PS: 设置只有在新建 connection 时生效,所以已经创建的,删了重建即可
最近在调查一个 build issue 的时候发现有一段函数声明大致如下
1 | public class ParameterTest { |
但是就感觉很好奇,test(String list[])
这样的声明竟然能通过编译检测。查了下资料,这中做法是合法的,是 C 语言中数组的声明方式,大概是早期为了让 C 程序员能更好的迁移过来做的兼容把,表达的语意和 test(String[] list)
是完全一样的。
果然一个老项目里面什么情况都能遇到 ╮( ̄▽ ̄””)╭
记录平时遇到的一些精巧的小代码段
摘自 On Java 8 泛型章节。元组的定义:用户只能取值而不能设置值,所以这里没有使用 getter/setter 的封装形式,而是使用 public + final 关键字实现了该功能。
1 | public class Tuple2<A, B> { |
1 | public class TestLambda { |
1 | Arrays.asList(1, 2, 3).stream.anyMatch(sub -> sub > 3); |
记录一下泛型的定义,历史,使用案例等。素材主要来源于 On Java 8, Thinking in Java 和 Effective Java。
1.5 版本引入,主要动机是支持 Collection 类
把这一块放到最前面时为了避免理解上的误区,泛型方法和泛型类,泛型接口没有从属关系,就算是普通的 Utils 方法也可以声明泛型方法
1 | public class GenericUtils { |
即在声明类时添加类型声明,最常见的如 Collection 系列下的 ArrayList
1 | public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { ... } |
泛型接口只是在接口定义的时候在接口名称后接上类型声明而已。使用 lang 包中自带的 Supplier
接口为例,接口在声明时指定类型,并在 get() 方法中指定返回类型。
1 | // 1.8 中引入的接口,充当工厂方法的角色 |
记录一下工作生活中遇到的具体使用案例
公司代码重构时遇到下面这种情况:
比如原来有个类叫 Background, 重构时为他抽了一个 interface IBackground。但是在替换一些集合相关的代码时出现了不兼容的问题。
1 | // before |
上面的这种转换失败就是由泛型转化异常造成的
可以使用泛型方法
1 | public void <T extends Sup> T getSometing() {}; |
这种用法称为 multi-level wildcards,参考 这篇 文章中的定义
子类现有方法为
1 | public Map<String, List<Sub>> getResult() { |
想要给他一个抽 interface 类似 Map<String, List<? extends Sup>> getResult();
但是会编译错误,需要怎么写?
先说答案,可以使用 Map<String, ? extends List<? extends Sup>> getResult();
这样的语法来适配上面说的这种场景
关于这个问题的几个点:
List<? extends Sup>
这样的语法List<List<?>>
适配所有的参数类型的 listList<? extends List<String>>
适配任何 List 及其子类List<? extends List<?>>
适配任何 list 及其子类,并且适配所有参数类型Code sample:
1 | public interface Sup { } |
PS: List 前的 ? extends
是不可少的,不然 Override 方法会编译错误,应为实现中是用 ArrayList 这个子类实现的,所以接口定义时语意上要有这个声明
1 | // 下面两个方法有没有区别? |
没有。。。看了一下这两个方法编译出来的字节码是完全一样的,除了行号。
1 | // access flags 0x401 |
但是这两种表达方式在实现的时候还是有区别的,用界限符(?)的这种,要求在集合类型前面也加上界限符。。。
List<? extends Number> list = new ArrayList<>(); list.add(3);
向该 list 中添加数据 3 有编译错误。这是应为通过 List<? extends Number> list
声明的 list 可以存储 Number 及其子类,效果上来看下面这些声明的集合只是 ? extends Number
的一部分,那么我们加 3 这个行为在类型一致这个前提下就会有与以上的错误。一般这种声明方式拿到的结果只用于读操作。
1 | List<? extends Number> foo3 = new ArrayList<Number>(); // Number "extends" Number |
声明一个 list 类型是 <? extends Number>
我们还有一个方法参数列表 Class<T> clz1, T clz2
这种情况下怎么兼容。
1 | public class TestGeneric { |
语法上就兼容不了,无解,最后通过重新理解 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 | public class Person { |
自己创建的注解类:
1 | @Retention(RetentionPolicy.RUNTIME) |
测试用例:
1 | @Test |
终端打印:
1 | Method: getName has marked annotation. |
从这个例子可以看出来,Annotation 都是处理 class level 的问题的,和类延伸出来的实例基本没关系了
记录一下新系统常用配置和软件安装
cmd + shift + .
官网推荐的通过 curl raw 文件安装,本地没有 proxy 的话 pass,基本不动。可以直接通过 git clone https://github.com/Homebrew/install
这个 repo 然后 cd
到 install 文件夹下执行 /bin/bash -c ./install.sh
来触发任务
运行如下命令,查看是哪个步骤速度比较慢
1 | brew update --verbose |
1 | jack@PC /usr/local/Homebrew/stable brew update --verbose |
1 | # 替换brew.git: |
如果这个源挂了可以试试清华的
brew update 抛 warning
1 | Updating /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core... |
存在 /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/rebase-apply
这样的备份文件,通过 rm -rf rebase-apply
删掉就好了
可以通过下载 官方 zip 包离线安装,也可以通过 brew 安装 brew cask install iterm2
。brew 会比较慢
修改提示符
1 | prompt_context () { |
最新版的系统已经默认支持这个配色方案了,打开 iterm2 终端,cmd + ,
打开配置窗口。 Preferences -> Profiles -> Colors -> Color Presets -> Solarized Dark
官方 git 地址, 应为网络原因选择 clone repo 安装: git clone https://github.com/ohmyzsh/ohmyzsh.git
+ sh -c './install.sh
重启后终端抛出 warning
1 | Last login: Mon Aug 3 18:08:08 on ttys000 |
运行如下 cmd 修复
1 | chmod 755 /usr/local/share/zsh |
配置命令高亮: 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, 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
不能补全也是这个原因!!!
MacOS 10.15.6 Catalina 安装 VirtualBox 的时候报错,安装失败,是应为 MacOS 默认设置是禁止安装 Oracle 公司产品的,你可以去 System Preference -> Security & Privacy 页面点一下左下方的小锁,允许安装 Oracle 相关软件。再重新安装一下,就行了。
窗口内容: “No manual entry for
MacOS since 10.14, 官方定义了这个快捷键,和 IDEA 冲突了,Keyboard -> shortcut -> service -> search man page index in terminal 把这个选项 disable 掉,或者替换掉