Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method.

2025/05/3111:46:39 hotcomm 1151

Hello, I am Waiwai.

A few days ago, a friend sent me a screenshot like this:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

He said he didn't understand why he didn't report an error like this.

I said I didn’t understand either. Assigning a boolean type to the int type, how could there be no error? Then I asked him: Where did this code screenshot come from?

He said it was automatically generated by Lombok's @Data annotation.

It's a coincidence. I have a little understanding of Lombok before, so the moment I heard the answer to this, I seemed to understand something in a flash: because Lombok uses bytecode enhancement technology to directly operate the bytecode file, can it directly bypass the problem of variable type mismatch?

But soon I thought about it, it was impossible: If all this thing can be bypassed, Java will also play with yarn.

So I decided to study it and finally found that this matter is actually very simple: it is a bug in idea. I used the plugin again with

, so I quickly recreated it locally.

source file is like this, I just added @Data annotation:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

The class file compiled by Maven install is like this:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

You can see that @Data annotation has helped us do a lot of things: it generates parameterless constructors, get/set methods for name fields, equals methods, toStrong methods, and hashCode methods.

Actually, you click on the source code of the @Data annotation, and it also explains it to you. This is a composite annotation:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Therefore, the annotation that really generates the hashCode method should be @EqualsAndHashCode.

So, in order to eliminate interference items, I will focus on the hashCode method, I replaced the @Data annotation with @EqualsAndHashCode:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

The result is still the same, but the default generated methods are much less, and I don't care about those methods.

Now, it is true. Why is the first line of code in the hashCode method here like this:

int PRIME = true;

Intuition tells me that there must be a trick here.

I first thought of another decompilation tool, jd-gui, just it:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Sure enough, after dragging the class file into jd-gui, the hashCode method is as follows:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

is the number 59, not true.

However, this PRIME variable seems to be useless in the hashCode method. There is no hurry to do this problem, throw it out and put it here first, and let it talk about it later.

In addition, I also thought of a way to view the bytecode directly:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

You can see the integer stacking instruction used in the first command of the hashCode method that you see in this way. Bipush number 59.

After jd-gui and bytecode verification, I have reason to suspect that int PRIME = true is displayed in idea! right! yes! BUG!

is happy and found a bug again. Isn’t the material here?

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

I was so happy at that time, just like the expression of the child below.

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

clues

So I searched online and didn't find any information on this, and I didn't get any gains. The inner OS is: "Ah, it must be that my posture is wrong, do it again."

expanded the search range and searched again.

"Why is there still no clue? It doesn't make sense! No, there must be clues."

So I looked around again.

"Well, there is really no clue. Wasting me for a few hours, garbage, that's it.”

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

I spent all my life learning and looked through the Internet. I really couldn’t find any idea why it is displayed here int PRIME = true Such a line of code.

The only relevant question I found is this:

https://stackoverflow.com/questions/70824467/lombok-hashcode-1-why-good-2-why-no-compile-error/70824612#70824612

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

In this question, the guy who asked the question said why he saw int result = true There is no compilation error in this code?

is a bit similar to what I saw, but it is not exactly the same. I found that his Test class has no parameters, and the UserInfo I tested has a name parameter.

So I also made a non-parameter look:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

I have no problem here, it shows int result = 1.

Then someone asked if it is because your Test class has no fields, just take a look at it.

When it adds two fields, the compiled class The file is the same as what I saw:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

But there is only one valid answer to this question below:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

The guy who answered this answer said: You see the hashCode method like this, maybe it is because of a problem with the tool you use to generate bytecode.

Inside the tool you use, boolean true and false are represented by 1 and 0 respectively.

Some bytecode decompilers blindly translate 0 into false and translate 1 into true, this may be the situation you encountered.

The guy who wants to express is also: this is the bug of the tool.

Although I always think it is almost the same, let’s not talk about what’s wrong. Press the table, let’s continue to read it first.

In this answer, a feature of lombok is also mentioned delombok. I want to talk about this first:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

delombok

What is this?

tells you a scenario. Suppose you like to use Lombok annotations, so you provide the API you provide to the outside world. Relevant annotations are used in the package.

, but the classmate who quotes your API package does not like Lombok annotations, nor has he done related dependencies and configurations. Then you provide the past API package and others will definitely not be able to use it.

So what should I do?

delombok comes in handy.

can directly generate java that has parsed lombok annotations Source code. The description of this on the official website of

The following is:

https://projectlombok.org/features/delombok

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

In other words, you can use it to see what the java file generated by lombok looks like.

I'll take you to take a look at what it looks like.

From the description on the official website, you can see delombok There are many different ways to open:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

For us, the easiest solution is to use maven plugin directly.

https://github.com/awhitford/lombok.maven

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Just paste this configuration into the project's pom.xml.

But it should be noted that there is another paragraph below this configuration, and the first sentence at the beginning is very important:

Place the java source code with lombok annotations in src/main/lombok (instead of src/main/java).

Place the java source code with lombok annotations in src/main/lombok path instead of src/main/java.

So, I created a lombok folder and moved the UserInfo.java file inside.

and then execute the install operation of maven. You can see that there is an additional UserInfo.java file under the target/generated-sources/delombok path:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

This file is a java file processed by the delombok plug-in. You can directly put it into the API and provide it with it if the other party does not use the lombok plug-in.

Then we take a look at this file. I got this file mainly to see what the hashCode method looks like:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

sees it, int PRIME = true in the hashCode method is gone, and instead final int PRIME = 59.

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

This is already a java file. If this place is still true, then it will be a complete compilation error:

And the source code generated through delombok also answered my previous question:

When looking at the class file, I felt that the PRIME variable has not been used, so what is its meaning?

But looking at the java file obtained after delombok compiled, I understand. PRIME is actually used:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

So why does PRIME become true?

Looking at the source code generated by delombok, my eyes suddenly lit up, what do you think is this:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

This is the final type of local variable .

Note: Yes! Final! kind! type!

In order to better introduce the probability I want to talk about below, I will first write you a very simple thing:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Did you see it? Why and mx have become true, which is equivalent to directly modifying the test method to this:

public int test() {return 3;}

Show you the bytecode may be more intuitive:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

The left side is not added to final, and the right side is final.

You can see that after adding final, there is no iload operation to access local variables at all. What is this thing called

?

This is "constant folding".

I was fortunate to see JVM a long time ago. The big guy R-master interpreted this phenomenon. I thought it was very interesting at the time, so I had a little impression.

When I see final int PRIME = 59, the memory is ignited.

So I found the link I read before:

https://www.zhihu.com/question/21762917/answer/19239387

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

In the R big answer, there is such a small paragraph, I will give you a screenshot:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

At the same time, I will show you the constant variable. This thing is in Java Definition in the language specification:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

A variable of primitive type or type String, that is final and initialized with a compile-time constant expression , is called a constant variable.

A variable of primitive type or String type. If it is modified by final, it will be initialized at compile time, which is called constant variable (constant variable).

So final int PRIME = 59 The PRIME in is a constant variable.

Since String is mentioned here, I will give you an example:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

You see the test2 method, using final, and in the final class file, the string after the splicing is completed.

Why?

Don’t ask, ask is the rule.

https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

I'm just here to show you a way out. If you are interested, you can go and read it yourself.

In addition, it also confirmed that the following display of the class file is indeed an idea bug, and it has nothing to do with lombok, because I don't use it at all here lombok:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

At the same time, there is also a related discussion about the above problem in lombok's github:

https://github.com/projectlombok/lombok/issues/523

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

https://github.com/projectlombok/lombok/issues/523

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

https://github.com/projectlombok/lombok/issues/523

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

https://github.com/projectlombok/lombok/issues/523

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

https://github.com/projectlombok/lombok/issues/523

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

https://github.com/projectlombok/lombok/issues/523

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

https://github.com/projectlombok/lombok/issues/523

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

https://github.com/projectlombok/lombok/issues/523

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Variables seem to be useless code, because they have not been used in this local method.

The official answer is: Brother, I suspect you are seeing an optimization of javac. If you look at the code generated by delombok, you will see that PRIME is being used. It should be that javac is inlined this constant. Why is

59

We once again focused our attention on the hashCode method generated by delombok:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Why is 59 used here? Shouldn't the factors in hashCode be used brainlessly 31?

I think there is a story here, so I dug it up again.

My idea of ​​digging clues is like this.

First I found how the number 59 comes from? It must be from a file in lombok.

Then I pulled down the source code of lombok and checked the submission or changes for this value in the corresponding file. Under normal circumstances, this magic value will not come for no reason. When submitting the code, there is a high probability that the value will be explained.

I just need to find that paragraph of instructions.

First, I found this class based on the place where @EqualsAndHashCode calls:

lombok.javac.handlers.HandleEqualsAndHashCode

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Then in this class, we can see the familiar "PRIME":

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Then, searching for this keyword, I found this place:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

The method here is 59 Source:

lombok.core.handlers.HandlerUtil#primeForHashcode

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

The first step is completed, and then we have to check out the submission records of the HandlerUtil class in lombok:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

The result is very smooth. The second submission of this class is about why it is not useful 31.

According to the commit information, the one you should have used before was 31, and the reason for using this number is because "Effective Java" is recommended to use. But according to the point of view in issue#625, maybe 277 is a better value.

It can also be seen from the submitted code that 31 was indeed used before, and it was written directly:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

In this submission, it was modified to 277 and mentioned a constant of HandlerUtil:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

However, this is not the 59 I want to find, so I continued to look for.

Soon, I found this change from 277 to 59:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

also pointed to issue#625.

Waiting for me to hum a song and sing, and when I was about to go to issue#625 to find out, I was stunned:

https://github.com/projectlombok/lombok/issues/625

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

issue#625 What I said has nothing to do with hashCode.

And this question was only proposed on July 15, 2015, but the code was submitted in January 2014.

So lombok's issues must have lost a large part, which has led to me not being able to match the account now.

This behavior is poisoned in the code, and I am a poisoned person.

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Things look like they are walking into a dead end.

But soon, the loop turned around because another possible answer flashed through my little cerebral, that is changelog:

https://projectlombok.org/changelog

As a matter of course, in the changelog, I found a new clue issue#660:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Open issue#660 At first glance, well, this time, I should have gone the wrong way:

https://github.com/projectlombok/lombok/issues/660

In this issues, first Maaartinus gave a piece of code, and then he explained:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

In my example, if the hashCode method generated by lombok uses this factor 31, for 256 generated objects, there are only 64 unique hash values, which means that it will produce a lot of collisions.

But if lombok uses a better factor, this number will increase to 144, which is relatively better.

and almost any odd number will do. Using 31 is one of the few bad choices. After seeing the official report, I quickly replied:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

After reading it, I thought what I said makes sense. I used 31 before, because this is what I suggested in "Effective Java" and I didn't think too much about it.

In addition, I decided to use the number 277 instead of 31 as a new factor. Why is

277?

Don’t ask, it’s very lucky!

77 is the lucky winner

So why did you change it from 277 to 59 in the end?

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Because of using such a "huge" factor of 227, there will be a performance loss of about 1-2%. So you need to change a number.

finally decided to choose 59, although there was no specific reason:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

But combined with changelog, I have reason to guess one of the reasons is to choose a number less than 127, because -128 to 127 is within the cache range of Integer:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

IDEA

Speaking of IDEA's bug, I stepped on an impressive "BUG" in my early years.

was debugging ConcurrentLinkedQueue before, and it made the mentality crash.

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

You may encounter a huge pit, for example, our test code is as follows:

public class Test {public static void main(String[] args) {ConcurrentLinkedQueueObject queue = new ConcurrentLinkedQueue();queue.offer(new Object());}}

is very simple, add an element to the queue.

Due to initialization head=tail=new Node(null):

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

So the item pointing in the link list structure after the add method is called should be like this:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

We add several output statements to the offer method:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

The log after execution is like this:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Why is the output log not after the last line of output? Where is null-@723279cf?

Because this method will call the first method to obtain the real head node, that is, the node whose item is not null:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Everything is normal here. However, it is different when you operate in debug mode: the item of the head node of

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

is no longer null! The next node of the head node is null, so a null pointer exception is thrown.

The result of the code running directly in the case of a single thread is inconsistent with the result of the Debug running ! Isn't this a ghost?

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

I checked it online and found that there are still many netizens who have encountered ghosts.

Finally found this place:

https://stackoverflow.com/questions/55889152/why-my-object-has-been-changed-by-intellij-ideas-debugger-soundlessly

The problem this buddy encountered was exactly the same as we did:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

There is only one answer below this question:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Do you know who the buddy answered this question? Product Manager of

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

IDEA, presented my respect.

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

The final solution is to close these two configurations of IDEA:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

Because IDEA will actively call the toString method in Debug mode, and in the toString method, the iterator will be called.

And the CLQ iterator will trigger the first method. This will modify the head element:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

. The truth is revealed.

And the problem in this article:

Because IDEA will actively call the toString method for us in Debug mode, and the iterator will be called in the toString method. - DayDayNews

I have reason to be sure that it is IDEA's problem, but I have not found the authentication of authoritative people like the problem in this section.

So what I said before is almost meaningful, that's what I mean.

--- This article was first published on the official account why technology.

hotcomm Category Latest News