最简单的方法, 就是写个测试类测试一下:
1 | package com.getname.pkg; |
打印结果为:
1 | -----三种方式获取普通类的名字----- |
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站
乱码三千 – 码出一个新世界
最简单的方法, 就是写个测试类测试一下:
1 | package com.getname.pkg; |
打印结果为:
1 | -----三种方式获取普通类的名字----- |
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站
使用 Git 已经好几年了,却始终只是熟悉一些常用的操作。对于 Git Rebase 却很少用到,直到这一次,不得不用。
上线构建的过程中扫了一眼代码变更,突然发现,commit
提交竟然多达 62
次。我们来看看都提交了什么东西:
这里我们先不说 git
提交规范,就单纯这么多次无用的 commit
就很让人不舒服。可能很多人觉得无所谓,无非是多了一些提交纪录。
然而,并非如此,你可能听过破窗效应,编程也是如此!
1.不利于代码 review
设想一下,你要做 code review
,结果一个很小的功能,提交了 60
多次,会不会有一些崩溃?
2.会造成分支污染
你的项目充满了无用的 commit
纪录,如果有一天线上出现了紧急问题,你需要回滚代码,却发现海量的 commit
需要一条条来看。
遵循项目规范才能提高团队协作效率,而不是随心所欲。
基于上面所说问题,我们不难想到:每一次功能开发, 对多个 commit 进行合并处理。
这时候就需要用到 git rebase
了。这个命令没有太难,不常用可能源于不熟悉,所以我们来通过示例学习一下。
1.我们来合并最近的 4 次提交纪录,执行:
1 | git rebase -i HEAD~4 |
2.这时候,会自动进入 vi
编辑模式:
1 | s cacc52da add: qrcodes f072ef48 update: indexeddb hacks 4e84901a feat: add indexedDB floders 8f33126c feat: add test2.js# Rebase 5f2452b2..8f33126c onto 5f2452b2 (4 commands)## Commands:# p, pick = use commit# r, reword = use commit, but edit the commit message# e, edit = use commit, but stop for amending# s, squash = use commit, but meld into previous commit# f, fixup = like "squash", but discard this commit's log message# x, exec = run command (the rest of the line) using shell# d, drop = remove commit## These lines can be re-ordered; they are executed from top to bottom.## If you remove a line here THAT COMMIT WILL BE LOST.## However, if you remove everything, the rebase will be aborted.# |
有几个命令需要注意一下:
按照如上命令来修改你的提交纪录:
1 | s cacc52da add: qrcodes f072ef48 update: indexeddb hacks 4e84901a feat: add indexedDB floderp 8f33126c feat: add test2.js |
3.如果保存的时候,你碰到了这个错误:
1 | error: cannot 'squash' without a previous commit |
注意不要合并先前提交的东西,也就是已经提交远程分支的纪录。
4.如果你异常退出了 vi
窗口,不要紧张:
1 | git rebase --edit-todo |
这时候会一直处在这个编辑的模式里,我们可以回去继续编辑,修改完保存一下:
1 | git rebase --continue |
5.查看结果
1 | git log |
三次提交合并成了一次,减少了无用的提交信息。
1.我们先从 master
分支切出一个 dev
分支,进行开发:
1 | git:(master) git checkout -b feature1 |
2.这时候,你的同事完成了一次 hotfix
,并合并入了 master
分支,此时 master
已经领先于你的 feature1
分支了:
3.恰巧,我们想要同步 master
分支的改动,首先想到了 merge
,执行:
1 | git:(feature1) git merge master |
图中绿色的点就是我们合并之后的结果,执行:
1 | git:(feature1) git log |
就会在记录里发现一些 merge
的信息,但是我们觉得这样污染了 commit
记录,想要保持一份干净的 commit
,怎么办呢?这时候,git rebase
就派上用场了。
4.让我们来试试 git rebase
,先回退到同事 hotfix
后合并 master
的步骤:
5.使用 rebase
后来看看结果:
1 | git:(feature1) git rebase master |
这里补充一点:rebase
做了什么操作呢?
首先,git
会把 feature1
分支里面的每个 commit
取消掉;
其次,把上面的操作临时保存成 patch
文件,存在 .git/rebase
目录下;
然后,把 feature1
分支更新到最新的 master
分支;
最后,把上面保存的 patch
文件应用到 feature1
分支上;
从 commit
记录我们可以看出来,feature1
分支是基于 hotfix
合并后的 master
,自然而然的成为了最领先的分支,而且没有 merge
的 commit
记录,是不是感觉很舒服了。
6.在 rebase
的过程中,也许会出现冲突 conflict
。在这种情况,git
会停止 rebase
并会让你去解决冲突。在解决完冲突后,用 git add
命令去更新这些内容。
注意,你无需执行 git-commit,只要执行 continue
1 | git rebase --continue |
这样 git
会继续应用余下的 patch
补丁文件。
7.在任何时候,我们都可以用 --abort
参数来终止 rebase
的行动,并且分支会回到 rebase
开始前的状态。
1 | git rebase —abort |
git-rebase 存在的价值是:对一个分支做「变基」操作。
1.当我们在一个过时的分支上面开发的时候,执行 rebase
以此同步 master
分支最新变动;
2.假如我们要启动一个放置了很久的并行工作,现在有时间来继续这件事情,很显然这个分支已经落后了。这时候需要在最新的基准上面开始工作,所以 rebase
是最合适的选择。
根据上文来看,git-rebase
很完美,解决了我们的两个问题:
1.合并 commit
记录,保持分支整洁;
2.相比 merge
来说会减少分支合并的记录;
如果你提交了代码到远程,提交前是这样的:
提交后远程分支变成了这样:
而此时你的同事也在 feature1
上开发,他的分支依然还是:
那么当他 pull
远程 master
的时候,就会有丢失提交纪录。这就是为什么我们经常听到有人说 git rebase
是一个危险命令,因为它改变了历史,我们应该谨慎使用。
除非你可以肯定该 feature1
分支只有你自己使用,否则请谨慎操作。
结论:只要你的分支上需要 rebase
的所有 commits
历史还没有被 push
过,就可以安全地使用 git-rebase
来操作。
本文转载自:http://jartto.wang/2018/12/11/git-rebase/
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站
AOP指的是:面向切面编程(Aspect-Oriented Programming)。如果说,OOP如果是把问题划分到单个模块的话,那么AOP就是把涉及到众多模块的某一类问题进行统一管理。
代表框架:
Android 中应用
Android AOP就是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,提高开发效率
在Java中使用aop编程需要用到AspectJ切面框架,AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
1.在build.gradle文件中引入AspectJ
1 | pply plugin: 'com.android.application' |
2.创建注解类
1 | @Retention(RetentionPolicy.CLASS) |
3.创建切面类
1 | /** |
4.使用
1 | @SingleClick(clickIntervals = 2000) |
难点:
AspectJ语法比较多,但是掌握几个简单常用的,就能实现绝大多数切片,完全兼容Java(纯Java语言开发,然后使用AspectJ注解,简称@AspectJ。)
优点:
AspectJ除了hook之外,AspectJ还可以为目标类添加变量,接口。另外,AspectJ也有抽象,继承等各种更高级的玩法。它能够在编译期间直接修改源代码生成class,强大的团战切入功能,指哪打哪,鞭辟入里。有了此神器,编程亦如庖丁解牛,游刃而有余。
APT(Annotation Processing Tool 的简称),可以在代码编译期解析注解,并且生成新的 Java 文件,减少手动的代码输入
代表框架:
1,在android工程中,创建一个java的Module,写一个类继承AbstractProcessor
1 | @AutoService(Processor.class) // javax.annotation.processing.IProcessor |
2,重写AbstractProcessor类中的process方法,处理我们自定义的注解,生成代码:
1 | public class SingleDelegateProcessor implements IProcessor { |
3,在项目Gradle中添加 annotationProcessor project 引用
1 | compile project(':apt-delegate-annotation') |
4,如果有自定义注解的话,创建一个java的Module,专门放入自定义注解。项目与apt Module都需引用自定义注解Module
4-1,主工程:
1 | compile project(':apt-delegate-annotation') |
4-2,apt Module:
1 | compile project(':apt-delegate-annotation') |
5,生成的源代码在build/generated/source/apt下可以看到
难点
就apt本身来说没有任何难点可言,难点一在于设计模式和解耦思想的灵活应用,二在与代码生成的繁琐,你可以手动字符串拼接,当然有更高级的玩法用squareup的javapoet,用建造者的模式构建出任何你想要的源代码
优点
它的强大之处无需多言,看代表框架的源码,你可以学到很多新姿势。总的一句话:它可以做任何你不想做的繁杂的工作,它可以帮你写任何你不想重复代码。懒人福利,老司机必备神技,可以提高车速,让你以任何姿势漂移。它可以生成任何源代码供你在任何地方使用,就像剑客的剑,快疾如风,无所不及
如图所示:
和
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站
在Kotlin中@JvmOverloads注解的作用就是:在有默认参数值的方法中使用@JvmOverloads注解,则Kotlin就会暴露多个重载方法。
可能还是云里雾里,直接上代码,代码解释一切:
如果我们再kotlin中写如下代码:
1 | fun f(a: String, b: Int = 0, c: String="abc"){ |
相当于在Java中声明
1 | void f(String a, int b, String c){ |
默认参数没有起到任何作用。
但是如果使用的了@JvmOverloads注解:
1 | @JvmOverloads fun f(a: String, b: Int=0, c:String="abc"){ |
相当于在Java中声明了3个方法:
1 | void f(String a) |
是不是很方便,再也不用写那么多重载方法了。
注:该注解也可用在构造方法和静态方法。
1 | class MyLayout: RelativeLayout { |
相当Java中的:
1 | public class MyLayout extends RelativeLayout { |
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站
data class就是一个类中只包含一些数据字段,类似于vo,pojo,java bean。一般而言,我们在Java中定义了这个数据类之后要重写一下toString,equals等方法。要生成get,set方法。
然而在Kotlin中这些都不在需要自己手动去敲了,编译器在背后默默给我们生成了如下的东西:
1 | data class User(var id: Int, var name: String) |
就这么一行代码,你已然拥有了一个数据类
主构造函数中的所有参数必须被标记为var或者val,var就表示可读写,val就表示只读,这就相当于表明了数据字段的访问权限
在主构造函数中有多少个参数,就会依次生成对应的component1,component2,component3……这些函数返回的就是对应字段的值
componentN函数是用来实现解构申明的
1 | data class User(var id: Int,var name:String) |
拿上面的例子来说,给id赋值,其实调用的是user.component1(),给name赋值其实调用的是component2()函数。
有了这个解构申明,想在一个函数中返回多个结果,就可以申明一个简单的数据类来返回了,然后取值也很方便。
默认生成的copy函数就是用现在的数据字段生成了一个新的对象。
1 | fun copy(id: Int = this.id,name: String = this.name) = User(id,name) |
如果只想改变其中的某些字段,就可以在调用copy的时候采用命名参数的方法进行调用
1 | fun main(args: Array<String>) { |
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站
在GitHub
上获取个人访问令牌(Personal Access Token, PAT
)的步骤如下:
GitHub
账户。Settings(设置
Developer settings(开发者设置)
Personal access tokens(个人访问令牌)
Generate new token(生成新令牌)
Generate token(生成令牌)
用户名/仓库名
master
token
: xxxxxxxxxx
img/
https://cdn.jsdelivr.net/gh/用户名/仓库名
截图如下:
示例图如下:
本文为作者原创 转载时请注明出处 谢谢
选出最小的一个数与第一个位置的数交换
第1趟比较:拿第1个元素依次和它后面的每个元素进行比较,如果第1个元素大于后面某个元素,交换它们,经过第1趟比较,数组中最小的元素被选出,它被排在第一位
第2趟比较:拿第2个元素依次和它后面的每个元素进行比较,如果第2个元素大于后面某个元素,交换它们,经过第2趟比较,数组中第2小的元素被选出,它被排在第二位
……
第n-1趟比较:第n-1个元素和第n个元素作比较,如果第n-1个元素大于第n个元素,交换它们
1 | public static void selectionSort(int[] nums) { |
使用临时变量存储最小值的角标值,减少交换的次数
1 | public static void selectSort(int[] numbers) { |
时间复杂度:O(n²)
空间复杂度:O(1),只需要一个附加程序单元用于交换
稳定性:选择排序是不稳定的排序算法,因为无法保证值相等的元素的相对位置不变,例如 [3, 4, 3, 1, 5]这个数组,第一次交换,第一个3和1交换位置,此时原来两个3的相对位置发生了变化。
本帖附件
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站
物理层 :负责在物理线路上传输原始的二进制数据(0和1),该层数据以比特流的形式传输
链路层: 负责在通信的实体间建立数据链路连接,该层数据以帧的形式传输
网络层: 负责创建逻辑链路,以及实现数据包的分片和重组,实现拥塞控制、网络互连等功能,该层数据以IP数据报(IP分组)的形式传输
传输层: 负责向用户提供端到端的通信服务,实现流量控制以及差错控制,这一层主要重点是两个协议 : UDP 和 TCP
应用层: 为应用程序提供了网络服务,应用层协议最著名的就是HTTP, FTP了, 还有一个重要的DNS
本帖附件
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站
退出程序 : Alt+F4
重画屏幕 : Ctrl+Alt+Space
完成语法 : Ctrl+E
复制一行 : Ctrl+K
恰好复制该位置右边的该行的字符 : Ctrl+Shift+K
复制到剪贴板 : Ctrl+Del
剪切一行 : Ctrl+U
剪切该位置右边的该行的字符 : Ctrl+;
剪切到剪贴板 : Ctrl+Shift+X
剪切一个字 : Ctrl+,
左边缩进 : F9
右边缩进 : F10
插入一行 : Ctrl+I
插入新行 : Ctrl+Enter
加入一行 : Ctrl+J
从剪切板粘贴 : Ctrl+Ins
粘贴一行 : Ctrl+P
重复上一个动作 : Ctrl+Y
重新编号 : Ctrl+R
重复输入 : Ctrl+
替换 : Ctrl+H
智能重命名 : Ctrl+’
关闭文件 : Ctrl+W
关闭所有文件 : Ctrl+Shift+W
新建 : Ctrl+N
转到下一个文件 : Ctrl+Shift+N
打开 : Ctrl+O
重新装载文件 : Ctrl+Shift+O
另存为 : Ctrl+Shift+S
显示文件状态 : Shift+F10
激活语法窗口 : Alt+L
回到该行的开始 : Home
回到选择的开始 : Ctrl+Alt+[
到块的下面 : Ctrl+Shift+]
到块的上面 : Ctrl+Shift+[
书签 : Ctrl+M
到文件底部 : Ctrl+End, Ctrl+(KeyPad) End
到窗口底部 : (KeyPad) End (小键盘的END)
到一行的尾部 : End
到选择部分的尾部 : Ctrl+Alt+]
到下一个函数 : 小键盘 +
上一个函数 : 小键盘 -
后退 : Alt+,, Thumb 1 Click
后退到索引 : Alt+M
向前 : Alt+., Thumb 2 Click
转到行 : F5, Ctrl+G
转到下一个修改 : Alt+(KeyPad) +
转到下一个链接 : Shift+F9, Ctrl+Shift+L
回到前一个修改 : Alt+(KeyPad) -
跳到连接(就是语法串口列表的地方) : Ctrl+L
跳到匹配 : Alt+]
下一页 : PgDn, (KeyPad) PgDn
上一页 : PgUp, (KeyPad) PgUp
向上滚动半屏 : Ctrl+PgDn, Ctrl+(KeyPad) PgDn, (KeyPad) *
向下滚动半屏 : Ctrl+PgUp, Ctrl+(KeyPad) PgUp, (KeyPad) /
左滚 : Alt+Left
向上滚动一行 : Alt+Down
向下滚动一行 : Alt+Up
右滚 : Alt+Right
选择一块 : Ctrl+-
选择当前位置的左边一个字符 : Shift+Left
选择当前位置右边一个字符 : Shift+Right
选择一行 : Shift+F6
从当前行其开始向下选择 : Shift+Down
从当前行其开始向上选择 : Shift+Up
选择上页 : Shift+PgDn, Shift+(KeyPad) PgDn
选择下页 : Shift+PgUp, Shift+(KeyPad) PgUp
选择句子(直到遇到一个 . 为止) : Shift+F7, Ctrl+.
从当前位置选择到文件结束 : Ctrl+Shift+End
从当前位置选择到行结束 : Shift+End
从当前位置选择到行的开始 : Shift+Home
从当前位置选择到文件顶部 : Ctrl+Shift+Home
选择一个单词 : Shift+F5
选择左边单词 : Ctrl+Shift+Left
选择右边单词 : Ctrl+Shift+Right
到文件顶部 : Ctrl+Home, Ctrl+(KeyPad) Home
到窗口顶部 : (KeyPad) Home
到单词左边(也就是到一个单词的开始) : Ctrl+Left
到单词右边(到该单词的结束) : Ctrl+Right
排列语法窗口(有三种排列方式分别按1,2,3次) : Alt+F7
移除文件 : Alt+Shift+R
同步文件 : Alt+Shift+S
增量搜索(当用Ctrl + F 搜索,然后按F12就会转到下一个匹配) : F12
替换文件 : Ctrl+Shift+H
向后搜索 : F3
在多个文件中搜索 : Ctrl+Shift+F
向前搜索 : F4
搜索选择的(比如选择了一个单词,shift+F4将搜索下一个) : Shift+F4
搜索 : Ctrl+F
浏览本地语法(弹出该文件语法列表窗口,如果你光标放到一个变量/函数等,那么列出本文件该变量/函数等的信息) : F8
浏览工程语法 : F7, Alt+G
跳到基本类型(即跳到原型) : Alt+0
跳到定义出(也就是声明) : Ctrl+=, Ctrl+L Click (select), Ctrl+Double L Click
检查引用 : Ctrl+/
语法信息(弹出该语法的信息) : Alt+/, Ctrl+R Click (select)
高亮当前单词 : Shift+F8
语法窗口(隐藏/显示语法窗口) : Alt+F8
关闭窗口 : Alt+F6, Ctrl+F4
最后一个窗口 : Ctrl+Tab, Ctrl+Shift+Tab
本帖附件
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站
核心级线程设计模型:
由操作系统内核实现, 特点是: 速度快 windows系统采用的是这种设计模型
可以比喻为用自己的大脑控制自己十根手指头
用户级线程设计模型:
操作系统核外实现的线程模式, 特点是: 线程调度在核外 速度不如核内 Linux系统采用的是这种
可以比喻为自己的十根手指头需要借助外力才能动
由上面Linux采用的线程设计模型可知,Linux系统并没有真正意义上的多线程
因此, Linux系统里处理多线程不如Windows强悍
这两个线程库实际上并没有完全按照线程模式进行实现
在Android中, ActivityThead的创建预示着进程的创建
当一个应用启动的时候, 它的进程级别不是保持固定的, Android内部通过Handler进行轮询检测当前进程的状态,ActivityThread掌控的Activity 的生命周期, 如果栈中无Activity存在, 但是有Service存在的情况下, 此时的进程级别就会从前台进程降为服务进程
如果想要查询当前进程的级别, 可以通过ActivityManager .RuningAppProcessInfo进行查询,内部有对应的变量和方法
前见服后空
谐音: 权健服后空 (懂?)
本帖附件
乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站