Integer is different from String

Let’s start with some code:

package com.utils; public class MemTest { public static void main(String[] args) { Integer i1 = 12; Integer i2 = 12; Integer i3 = 129; Integer i4 = 129; System.out.println(i1 == i2); //trueSystem.out.println(i3 == i4); //false

        String s1 = "wuyue";
        String s2 = "wuyue";
        String s3 = new String("wuyue"); System.out.println(s1 == s2); //trueSystem.out.println(s1 == s3); //false}}Copy the code

Reasons for execution results:

We all know that in the Java world, when the == operator compares objects, it is actually the address of the object being compared. The Integer example in the code above is probably familiar to many of you, too many interview questions, so we’re going to skip the auto-boxing and auto-unboxing section and if you’re interested you can do a search for yourself. There are many examples on the Internet. Here we directly look at the source code:

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
Copy the code

To be clear, the valueOf code here is very simple: if you pass in a value >=low or <= high then go directly to a cache and fetch an object. Otherwise, create an object yourself.

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue ! = null) { try { int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) Assert IntegerCache. High >= 127; } privateIntegerCache() {}}Copy the code

The author of an Integer thinks that most int values are in the range of -128 to 127, so he simply creates all of them. If they are beyond this range, because they are used infrequently, Create it when you need it.

Integer a = new Integer(110);
Integer a = 110;
Integer a = Integer.valueOf(110);
Copy the code

We try to use the latter two notations, otherwise we won’t be able to take advantage of the caching features of INTEGER using the first notation

So with Integer out of the way, let’s look at String.

Now that we know the Integer example, we know the Stringd example as well. It’s just creating new objects and reusing objects. But here’s what we need to note: String, because it’s a String, there are so many different ways to write strings that you can’t predict the properties of different projects. So String designers didn’t use the concept of a pool of objects in Integer, which we can see from the source code, which is created automatically when we start the program. If you create a String object, if it has the same content as the one behind it, you reuse it, otherwise you don’t reuse it, but you have to be careful that as long as you create it using the new keyword, you don’t reuse it.

Inspiration for ordinary business code

Once we understand the special mechanisms of Integer and String, we can use the information revealed in the source code to optimize our code appropriately.

Consider an implementation of a text-and-text mash-up, text editor, which is actually quite common in Android development.

Take a look at the font definition:

public class Character { private Char c; Private Font Font; // private int size; Private int color; // Font color}Copy the code

Suppose the user edits thousands of words, there are thousands of Character objects, but think about it, do we really need that many thousands of full Character objects? I believe that no one writing the font size will constantly change, font color constantly change.

We change the content of the font, but the corresponding font, font size, and font color do not change.

Instead, let’s modify our code by first defining a style.

It contains all the features associated with Font

public class CharacterStyle {
    private Font font;
    private int size;
    private int color;

    public CharacterStyle(Font font, int size, int color) {
        this.font = font;
        this.size = size;
        this.color = color;
    }

    @Override
    public boolean equals(Object o) {
        CharacterStyle otherStyle = (CharacterStyle) o;
        returnfont.equals(otherStyle.font) && size == otherStyle.size && colorRGB == otherStyle.colorRGB; }}Copy the code

Provide a factory to accomplish this reuse object functionality

// The default font is used by most people, and the default font is used by most people. Font public class CharacterStyleFactory {private static final List<CharacterStyle> styles = new ArrayList<>(); public static CharacterStyle getStyle(Font font, int size, int color) {for (CharacterStyle style : styles) {
            if (style.equals(newStyle)) {
                return style;
            }
        }
        CharacterStyle newStyle = new CharacterStyle(font, size, color);
        styles.add(newStyle);
        returnnewStyle; }}Copy the code

If you are not satisfied with the performance, you can speed up the process with o1 time

public class CharacterStyleFactory { private static final Map<Integer, CharacterStyle> styles = new HashMap<>(); public static CharacterStyle getStyle(Font font, int size, Int colorRGB) {//key = font hash + size + colorRGB Int key = font-size. HashCode () + size + colorRGB;if (styles.containsKey(key)) {
            return styles.get(key);
        }
        CharacterStyle newStyle = new CharacterStyle(font, size, colorRGB);
        styles.put(key, newStyle);
        returnnewStyle; }}Copy the code

So our text class becomes content +style

public class Character { private char c; private CharacterStyle style; public Character(char c, CharacterStyle style) { this.c = c; this.style = style; }}Copy the code

When used, it can be:

What changes is the content, but does not change is the font style, so the style is reused, and can save memory, but also omit the process of new objects, reduce the process of GC

public class Editor { private List<Character> chars = new ArrayList<>(); public void appendCharacter(char c, Font font, int size, int colorRGB) { Character character = new Character(c, CharacterStyleFactory.getStyle(font, size, colorRGB)); chars.add(character); }}Copy the code

You can also think about where in your business model you can emulate the design of string and where you can emulate the design of INTEGER.