Original: On the WeChat public
码农参上
, welcome to share, please keep the source for reprinting.
Hello everyone, I haven’t updated Hydra, but I’m busy with my baby at home.
A few days ago, I happened to catch up with the code review in the group. When I came down in the afternoon, I felt that my blood pressure was full. The variety of codes makes me sigh that the road of code specification is still a long way to go…
So today, I will summarize a wave of code- killing tips in Java. After mastering these tips, you are guaranteed to be able to write code that your colleagues can’t understand~
As for why you have to write code that your colleagues can’t understand, through this lesson, I found that there are still many benefits, just to give a few examples:
-
Colleagues cannot easily modify your code to avoid bugs from improper team collaboration
-
Shaping the irreplaceability of personal ability and avoiding the risk of being fired
-
Helping colleagues treat low blood pressure for many years during code review
Alright, let’s stop the serious nonsense part… Not much nonsense, let’s officially begin. Useless knowledge will increase again…
1. Concealing the sky and crossing the sea
I bet you never imagined that someone would actually poison the comments. Take a look at the code below, it’s as simple as a single line of comment in the main
method.
public static void main(String[] args) { // \u000d System.out.println("coder Hydra"); }
Guess how this program works? After execution it actually prints on the console:
coder Hydra
Seeing this, are you confused, why is the code in the comment executed?
In fact, the principle lies in the familiar unicode
encoding. The above \u000d
is a unicode
escape character, which represents a newline character. The compiler in java will not only compile the code, but also parse the unicode
encoding and replace it with the corresponding characters. So, the above code is actually like this after parsing:
public static void main(String[] args) { // System.out.println("coder Hydra"); }
In this way, it can explain why the statement in the comment can be executed. Of course, if you feel that the above code is not enough, and you want to be a little more perfect, then you can write the code as follows.
public static void main(String[] args) { int a=1; // \u000d \u0061\u002b\u002b\u003b System.out.println(a); }
The execution result will print 2
, for the same reason, because the escaped unicode
encoding that follows represents a++;
.
As for the benefit of writing it like this, of course, it is used in some places that you don’t want others to understand, to hide people’s eyes and ears. It is estimated that everyone has seen the following joke.
If you write it like this, if the customer understands the code, it will be easy to read it, but if you write it like this, most of you probably think it is a piece of garbled code:
//\u000d\u0054\u0068\u0072\u0065\u0061\u0064\u002e\u0073\u006c\u0065\u0065\u0070\u0028\u0032\u0030\u0030\u0030\u0029\u003b
IMHO, without decades of skill, I can’t really see that sleep
is implemented here, it’s just perfect.
2. Give up the near and seek the far
To write code that others can’t understand, a very important trick is to complicate simple things . For example, when judging the positive or negative of an int
number, it can be written as follows:
public void judge(int x){ if (x>0){ //... }else if (x<0){ //... } }
But I don’t. I don’t use simple code. I just play. I have to write it as follows:
public void judge2(int x){ if (x>>>31==0){ //... }else if (x>>>31==1){ //... } }
How, if you write it like this, is it forced to stand up all of a sudden! When others see this, they have to ponder for a while what exactly is written in this piece.
In fact, the principle is also very simple, the >>>
used here is an unsigned right shift operation. As a simple example, take -3
as an example, convert it to its complement before shifting:
111111111111111111111111111111101
After unsigned right shift by one bit, it becomes the following form, this number is 2147483646
after conversion to decimal.
011111111111111111111111111111110
Therefore, when a number of int
type is shifted to the right by 31 bits unsigned, all the high bits of the previous 31 bits are 0, and the remaining lowest bit is the original sign bit, so it can be used to judge the positive or negative of the number.
Based on this little knowledge, we can still make a lot of work. For example, instead of a good 0, we can define a 0 in the following way:
int ZERO=Integer.MAX_VALUE>>31>>1;
Through the above knowledge, I believe everyone can easily understand, because after shifting a number unsigned to the right by 32 bits, all the bits in the binary are all 0, so 0 will eventually be obtained. So the question is, why don’t I just use Integer.MAX_VALUE>>32
to shift right by 32 bits at a time?
This is because when the int
-type number is shifted, the modulo 32 remainder operation will be performed on the parameter on the right side of the operator, so if you write 32 directly, it is equivalent to doing nothing, and the original value is obtained. .
3. Reversing black and white
In ancient times, Zhao Gao referred to a deer as a horse, but today there are code farmers who reverse the truth and falsehood. One of the powerful weapons to prevent a colleague from reading your code is to make him lose his basic judgment ability when he encounters a conditional judgment, and he falls into a fog, not knowing which branch to go next.
The following code, I said it will print fasle
, no one will believe it?
public class TrueTest { public static void main(String[] args) { Boolean reality = true; if(reality) { System.out.println("true"); } else { System.out.println("false"); } } }
Yes, as long as you know the boolean type, you know that this is not logical, but the following transformation can make it a reality.
First, find a hidden place in the class and insert the following code:
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(); } }
Then run the above program again, and you will find that false
is magically printed.
In fact, the principle is also very simple, first get the TRUE
variable defined in the Boolean
class through reflection:
public static final Boolean TRUE = new Boolean(true);
Then use reflection, remove its final
modifier, and finally set its value to false
. In the process of using true
to define a variable of type Boolean
, automatic boxing will be performed, and the following method will be called:
public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }
At this time, b
is true
, and TRUE
is actually false
, so the first expression is not satisfied, and it will eventually return false
.
In this way, the above printing results can be explained, but remember, when writing this, you must find a hidden corner in the code, and don’t be found, otherwise it will be easy to be beaten badly…
four, to zero
The technique to be introduced next is a bit powerful. It can rewrite the original serial logic into different branches in the judgment logic, and ensure that it can be executed normally in the end.
One question before we start, is there a way to make both if
and else
statements execute, like in the following example:
public static void judge(String param){ if (/*judgment condition*/){ System.out.println("step one"); }else { System.out.println("step two"); } }
If I say that this method is called only once, the print statements in if
and else
can be output at the same time, you will definitely say that it is impossible, because this violates the basic common sense of judgment logic in java.
That’s right, no one can do it under the condition that the above modifier can only call the method “once” . But if you move a little bit in the judgment conditions, you can achieve the functions mentioned above. Take a look at the modified code:
public class IfTest { public static void main(String[] args) { judge("Hydra"); } public static void judge(String param){ if (param==null || new IfTest().equals("Hydra")){ System.out.println("step one"); }else { System.out.println("step two"); } } }
After running, the console prints:
step one step two
Surprised or not? In fact, the secret that it can execute is in the judgment condition of if
.
When the judge()
method is called for the first time, it is not satisfied with the first condition in the NOT-OR operation, so when the second condition is executed, the instantiated initial block code in the anonymous inner class will be executed, and the judge()
method will be executed again. When the if
condition is satisfied, the first print statement is executed.
The instantiated new object does not meet the conditions in the equals()
method, so it does not meet any of the conditions in if
, so the statement in else
will be executed, and the second print statement will be executed.
In this way, the function of calling the method on the surface and executing the statement block in the if
and else
is realized at the same time. How about splitting a piece of overall logic into two pieces in this way to confuse your colleagues.
Wu, the bottom of the pot
In the programmer’s world, there has always been a chain of contempt between different languages. For example, those who write c look down on those who write java, because those who directly manipulate memory look very tall, don’t they? So today we pretend to be a c language programmer to operate a piece of memory in java.
Specifically how to do it, or to use the magic class Unsafe
in java. Looking at the name, you can also understand that this thing is not very safe if used improperly, so it is more troublesome to obtain the Unsafe
instance, and it needs to be obtained through reflection:
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); unsafeField.setAccessible(true); Unsafe unsafe =(Unsafe) unsafeField.get(null);
After getting this object, we can do whatever we want with the memory. For example, when we implement a simple assignment such as int a=1;
we can make it more complicated and make a bend like the following:
void test(){ long addr = unsafe.allocateMemory(4); unsafe.putInt(addr,1); int a=unsafe.getInt(addr); System.out.println(a); unsafe.freeMemory(addr); }
First, apply for 4 bytes of memory space through the allocateMemory
method, then write a 1 through the putInt
method, and then read a variable of type int
length from this address, and finally realize the operation of assigning 1 to a
.
Of course, there are many more advanced usages, here are just two examples.
void test(){ long addr = unsafe.allocateMemory(4); unsafe.setMemory(addr,4, (byte) 1); System.out.println(unsafe.getInt(addr)); unsafe.freeMemory(addr); }
In the above code, 1 of byte
type is written to each byte through the setMemory
method, and finally the getInt
method is called to read 4 bytes at a time as the value of an int
variable. The final print result of this code is 16843009
, and the corresponding binary is as follows:
00000001 00000001 00000001 00000001
As for memory copying in C language, it is easy to do it with Unsafe
:
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); }
In the above code, an 8-byte memory space is re-allocated by the reallocateMemory
method, and the 4-byte memory space at the beginning of addr
is copied into the memory space of addr2
twice. The above code will print:
1 4294967297
This is because the binary number stored in the new 8-byte memory space addr2
is as follows, which corresponds to 4294967297
after being converted to the decimal long
type.
100000000000000000000000000000001
In addition to directly operating memory space, Unsafe also has practical functions such as thread scheduling, object operation, and CAS operation. If you want to know more about it, you can read this Java Double-edged Sword Unsafe Class Detailed Explanation , which opens the door to a new world .
at last
Well, this is the end of the useless knowledge introduction. I believe that after mastering these skills, everyone can bring their own code confusion halo and write different code.
Finally, I suggest that when you write code like this in the project, it may be better to use it with safflower oil and bruises wine.
So, that’s it for this sharing, I’m Hydra, see you in the next article.
The author’s profile,
码农参上
, a public account that loves to share, interesting, in-depth and direct, chatting with you about technology. Welcome to add friends for further communication.
The text and pictures in this article are from InfoQ
This article is reprinted from https://www.techug.com/post/how-to-write-java-code-that-colleagues-can-t-understand7872239b9abbd184ccab/
This site is for inclusion only, and the copyright belongs to the original author.