Instead of dedication
Always ... no. Never go out in a snowstorm write such a code for nothing but similar fun.
Guillaume - Groovy language development leadReflection evil
One of my friends is a big puzzle lover. Anyone, and programmers including. Here is his last fun:
Write the necessary code in static initializer so that assert stops falling:
public class Test { static {
If you decide to try, do not forget
to include assertions (with the -ea flag) .
Then there will be a decision and some kind of reasoning on the topic, so if you have already done it, or you broke it, boldly under the cat.
Let's start with the solution. There is nothing particularly complicated here, you just need to know reflection and two facts about the Integer class:
- It has a cache for small (more common) values.
- During auto-boxing, this cache is used (here in the designer, for example, the cache is not used)
We also need to know how this cache is called and where it lives, but thanks to the rt.jar sources, this is not a problem. What would you think? This cache is a private field in a private internal class. Cheers cheers.
')
We will do this:
- Take the class object class Integer
- We pull out the list of its internal classes
- Among them we find the right one (here we are lucky - he is only one. However, since we dig where we don’t, there are no guarantees that he will be left alone in future versions, no, yeah.)
- We take the cache field
- It's closed, so we make it accessible (accessible) to get the value.
- This is an array. Change the value of the desired cell from "20" to "30"
Here is the code for you:
static { try { Class<?>[] declaredClasses = Integer.class.getDeclaredClasses(); Field cacheField = declaredClasses[0].getDeclaredField("cache"); cacheField.setAccessible(true); ((Integer[]) cacheField.get(null))[20 + 128] = 30; } catch (Exception e) { e.printStackTrace(); } }
I do not know about you, but as for me it is so - horror-horror. An ugly code that climbs where it does not follow violates the rules of visibility and encapsulation, and it breaks from a half-kick (for example, you should create Integer constructors, not auto-boxing).
And in general, we are just lucky that Integer has this cache that can be tweaked. Otherwise, we can’t turn this trick with the change of plus.
Why is such a simple thing so hard to do? Because Java for such things is not sharpened
(she is feminine, right?) . Java is a static language, and that's great. We can always count on the fact that 20 + 20 = 40. Well, almost always. This is
good .
But what if we still need to do similar tricks (not with redefining plus behavior, of course, but similar ones)? There are better tools for this. For example - Groovy.
We will break correctly!
Here is the Groovy puzzle version:
Practically the same in a puzzle (without disgrace with main (), wacky semicolons and the need for -ea), but because Groovy is a dynamic language, the solution is different. Here is what you need to know:
- Groovy always works with objects only (no auto-boxing)
- Groovy implements operators using methods. Specifically, the operator "+" is implemented by the method (surprise :) "plus ()"
- With Groovy's MetaClass, you can easily replace any method with a closure
This is what we will do:
- We take MetaClass Integer
- Replace the "plus ()" method with an implementation that always returns 60
And all! Here is the code:
Integer.metaClass.plus = {int i -> 60 }
Here, as they say - without comments.
Output exactly two:
- Do not engage in such nonsense in this code.
- Use the right tools for your purposes.
Sivkel!
habrahabr.ru/post/144407