同事又在代码里“下毒”,血压拉满...
The following article is from 码农参上 Author Dr Hydra
文章来源:【公众号:码农参上】
前言
瞒天过海
舍近求远
颠倒黑白
化整为零
釜底抽薪
最后
前言
前几天,正巧赶上组里代码 review,一下午下来,感觉整个人都血压拉满了。五花八门的代码让我不禁感叹,代码规范这条道路还是任重而道远…
那么今天就来给大家总结一波 Java 中的代码作死小技巧,熟练掌握这些小技巧后,保证能让你写出同事看不懂的代码~
至于为啥要写出同事看不懂的代码,通过这次教训,我发现好处还是挺多的。
简单举几个例子:
同事无法轻易修改你的代码,避免团队协作不当引入 bug 塑造个人能力的不可替代性,规避被辞退的风险 代码 review 时,帮助同事治疗好多年的低血压
好了,一本正经的胡说八道环节就此打住……废话不多说了,下面正式开始。没用的知识又要增加了…
瞒天过海
我打赌你肯定想不到,有人居然会在注释里下了毒。看看下面的代码,简单到 main 方法中只有一行注释。
public static void main(String[] args) {
// \u000d System.out.println("coder Hydra");
}
coder Hydra
看到这你是不是一脸懵逼,为什么注释中的代码会被执行?
其实原理就在于大家熟悉的 unicode 编码,上面的 \u000d 就是一个 unicode 转义字符,它所表示的是一个换行符。
而 java 中的编译器,不仅会编译代码,还会解析 unicode 编码将它替换成对应的字符。
public static void main(String[] args) {
//
System.out.println("coder Hydra");
}
public static void main(String[] args) {
int a=1;
// \u000d \u0061\u002b\u002b\u003b
System.out.println(a);
}
执行结果会打印 2,同理,因为后面的 unicode 编码的转义后表示的是 a++;。
//\u000d\u0054\u0068\u0072\u0065\u0061\u0064\u002e\u0073\u006c\u0065\u0065\u0070\u0028\u0032\u0030\u0030\u0030\u0029\u003b
舍近求远
要想写出别人看不懂的代码,很重要的一个小技巧就是把简单的东西复杂化。
public void judge(int x){
if (x>0){
//...
}else if (x<0){
//...
}
}
public void judge2(int x){
if (x>>>31==0){
//...
}else if (x>>>31==1){
//...
}
}
怎么样,这么写的话是不是逼格一下子就支棱起来了!别人看到这多少得琢磨一会这块到底写了个啥玩意。
11111111111111111111111111111101
01111111111111111111111111111110
所以,当一个 int 类型的数字在无符号右移 31 位后,其实在前面的 31 位高位全部是 0,剩下的最低位是原来的符号位,因此可以用来判断数字的正负。
int ZERO=Integer.MAX_VALUE>>31>>1;
通过上面的知识,相信大家可以轻易理解,因为在将一个数字无符号右移 32 位后,二进制的所有位上全部是 0,所以最终会得到 0。
那么问题来了,我为什么不直接用 Integer.MAX_VALUE>>32,一次性右移 32 位呢?
颠倒黑白
古有赵高指鹿为马,今有码农颠倒真假。阻碍同事阅读你代码的有力武器之一,就是让他在遇到条件判断时失去基本判断能力,陷入云里雾里,不知道接下来要走的是哪一个分支。
public class TrueTest {
public static void main(String[] args) {
Boolean reality = true;
if(reality) {
System.out.println("true");
} else {
System.out.println("false");
}
}
}
没错,只要大家了解布尔类型就知道这不符合逻辑,但是,经过下面的改造就可以让它变为现实。
static {
try {
Field trueField = Boolean.class.getDeclaredField("TRUE");
trueField.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(trueField, trueField.getModifiers() & ~Modifier.FINAL);
trueField.set(null, false);
} catch(IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
}
然后再运行上面的程序,你就会发现神奇地打印了 false。
public static final Boolean TRUE = new Boolean(true);
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
这时的 b 为 true,而 TRUE 实际上是 false,因此不满足第一个表达式,最终会返回 false。
化整为零
接下来要介绍的这个技巧就有点厉害了,可以将原有的一段串行逻辑改写成判断逻辑中的不同分支,并且保证最后能够正常执行。
public static void judge(String param){
if (/*判断条件*/){
System.out.println("step one");
}else {
System.out.println("step two");
}
}
如果我说只调用一次这个方法,就能同时输出 if 和 else 中的打印语句,你肯定会说不可能,因为这违背了 java 中判断逻辑的基本常识。
没错,在限定了上面的修饰语只调用『一次』方法的条件下,谁都无法做到。但是如果在判断条件中动一点点手脚,就能够实现上面提到的功能。
public class IfTest {
public static void main(String[] args) {
judge("Hydra");
}
public static void judge(String param){
if (param==null ||
new IfTest(){{ IfTest.check(null); }}.equals("Hydra")){
System.out.println("step one");
}else {
System.out.println("step two");
}
}
}
step one
step two
惊不惊喜、意不意外?其实它能够执行的秘密就在 if 的判断条件中。
当第一次调用 judge() 方法时,不满足或运算中的第一个条件,因此执行第二个条件,会执行匿名内部类内的实例化初始块代码,再次执行 judge() 方法,此时满足 if 条件,因此执行第一句打印语句。
而实例化的新对象不满足后面的 equals() 方法中的条件,所以不满足 if 中的任意一个条件,因此会执行 else 中的语句,执行第二句打印语句。
釜底抽薪
在程序员的世界里,不同语言之间一直存在鄙视链,例如写 c 的就看不起写 java 的,因为直接操作内存啥的看上去就很高大上不是么?那么我们今天就假装自己是一个 c 语言程序员,来在 java 中操作一把内存。
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe =(Unsafe) unsafeField.get(null);
void test(){
long addr = unsafe.allocateMemory(4);
unsafe.putInt(addr,1);
int a=unsafe.getInt(addr);
System.out.println(a);
unsafe.freeMemory(addr);
}
首先通过 allocateMemory 方法申请 4 字节的内存空间后,然后通过 putInt 方法写入一个 1,再从这个地址读取一个 int 类型长度的变量,最终实现了把 1 赋值给 a 的操作。
void test(){
long addr = unsafe.allocateMemory(4);
unsafe.setMemory(addr,4, (byte) 1);
System.out.println(unsafe.getInt(addr));
unsafe.freeMemory(addr);
}
上面的代码中,通过 setMemory 方法向每个字节写入 byte 类型的 1,最后调用 getInt 方法一次性读取 4 个字节作为一个 int 型变量的值。
00000001 00000001 00000001 00000001
void test2(){
long addr = unsafe.allocateMemory(4);
long addr2 = unsafe.reallocateMemory(addr, 4 * 2);
unsafe.putInt(addr, 1);
for (int i = 0; i < 2; i++) {
unsafe.copyMemory(addr,addr2+4*i,4);
}
System.out.println(unsafe.getInt(addr));
System.out.println(unsafe.getLong(addr2));
unsafe.freeMemory(addr);
unsafe.freeMemory(addr2);
}
1
4294967297
100000000000000000000000000000001
最后
最后建议大家,在项目中这样写代码的时候,搭配红花油、跌打损伤酒一起使用,可能效果更佳。
扫码免费获取600+页石杉老师原创精品文章汇总PDF
原创技术文章汇总
点个在看你最好看