Interviewer: Do you back a few familiar faces questions on say Java source code? Sorry, we do not recruit sources we will not see people

If you do not see the source code, please patience to watch

First, my real experience

Title I is a Fortune 500 company 2019.6.28 in Shenzhen interview when the interviewer told me to say, even now think of it, also think the endless shame, because of their stupidity, laziness and arrogance, my first game to Shenzhen the interview will blundered.

I'm sure my life will not forget that hot morning, the first day I received an interview K's, this is my first interview in Shenzhen to offer. After receiving the message, I was moved to K seems to have received the company's offer, I checked the Internet dedicated to K's face was found that a lot of people say they pay attention to the source code reading capabilities, almost every time to ask about the source of some the classic problem, so I went online to find a few articles on String, HashMap, etc., learned a lot about Java source code. I am very confident after reading it, I thought with all the problems of tomorrow I am sure can answer it, contented sleep.

Interview that morning, I was nine o'clock came downstairs Company K, then is to call up a contact with me, waiting for an interview in the waiting room, about 9:30, when the front desk called my little sister's name, I followed her enter together into a small room, which made two people, evidently are doing technology (as little bald), a start is going smoothly, and then asked a question, "says on your resume that you are familiar with Java source code, that I asked you a question, String class can be inherited it, "of course, is not inherited, the articles are written, String is final modified, can not be inherited, and then I said on a number of interview questions content, the interviewer then asked a question

"Please briefly about the implementation process of the substring"

Yes, I have not seen this problem, usually when used, will not see the source of this method, I can not answer prevarication, I can feel my blush to hot. He seemed to see my distress, then went on to say, "Do you really read what the source? Substring is a very simple way, if you really read, can not know" to this point, I had to confess I have not read the source code, yes I am actually not even realize how simple substring do not know, I even can not find the source of the String class.

The interviewer said that sentence on the title, then I failed the interview.

I want to thank this experience of failure, so I opened up a new world, I began to try to see the source code, source code from jdk to Spring, then SpringBoot source, the more I see the more admire those chiefs to write this excellent framework their ideas, code logic, design patterns, are so good and appropriate. Not only that, I also began to try to write their own frameworks, first hand training framework is "simple handwritten version of the Spring Framework --YzSpring", it took me a week, every day at home after an hour or two to knock off work at night and then finished YzSpring, I feel I really understand Spring, see the information online before the total feel is minimal and only really go again in order to understand their own handwriting Spring works.

Still later, the partners in my hands "IPayment" project we have been complaining about the slow speed of the interface feedback, I started optimizing code to Redis cache some data, the speed is really fast again, but each must add a data cache two or three lines of code to support, caching less data down does not matter, but as more and more data needs to be written to the cache, the code becomes extremely bloated. One day I saw the injection function @Autowired, I suddenly thought, why can not I write a practical framework that would require these notes marked with cached data, and then treated with the framework it? Went ahead consecutive overtime a week I completed a "fast data cache based on Redis components", after the introduction of the project, needs to be cached data only need @BFastCache for modification, operation as well as optional: operate on the data , selected data source, update the data source, set / modify Key, greatly improving work efficiency. For the first time since writing the wheels, and so well, Big Brother has been affirmed, really happy.

So now I want to ask you three questions:

You see what the source?

You will see the source code it?

You harvest it from the source code?

Second, look at what you can get the source code

1. Quick troubleshooting and reduce errors

When coding, we are generally able to detect RuntimeException, like on a String substring method may sometimes we pass endIndex is greater than the length of the string, so there will be a run-time error

String index out of range: 100

Sometimes sleepwalk right to change the code, but do not know why this abnormality occurs, the next time to write again same problem occurs. If we read the source code, we can know the cause of the abnormal occurrence

public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {//起始坐标小于0
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {//结束坐标大于字符串长度
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {//起始坐标大于结束坐标
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }

Source code gives three possible scenarios above exception is thrown, then we can go to check our code based on the three scenarios, but also pay attention to these issues in the future coding time.

2. Learning Programming Practices

Or above substring source, please pay attention to his return, if it is you, how would you write? If you have not read the source code, I would have written as

        if ((beginIndex == 0) && (endIndex == value.length)) return this;
        return new String(value, beginIndex, subLen);

Although the function is the same, but the use of the ternary operator can solve the problem with a single line of code, and if they do not write the statement, and now I'm hooked on the ternary operator, is actually pretty good.

3. Learn design patterns (for novices)

Ok! I showdown, as a halfway decent programmer, I have not received systematic education, all of which are self-study, before I did not understand design patterns, just know that there are 23 kinds of design patterns, most know Singleton pattern.

Do not understand the design pattern main reason is that there was no actual combat experience, their own writing projects are events, not completely irrelevant design patterns, basically able to run on the line. My first contact with the factory design pattern is a pattern in log4j, when fully understand how to use the factory pattern is a step by step look at the source code log4j learned, and then do their own project when it will intentionally or unintentionally begun to use design mode, here is my project singleton class code configuration mode acquiring

import java.util.ResourceBundle;

public class Configration {
	private static Object lock              = new Object();
	private static Configration config     = null;
	private static ResourceBundle rb        = null;
	
	private Configration(String filename) {
		rb = ResourceBundle.getBundle(filename);
	}

	
	public static Configration getInstance(String filename) {
		synchronized(lock) {
			if(null == config) {
				config = new Configration(filename);
			}
		}
		return (config);
	}
	
	public String getValue(String key) {
		String ret = "";
		if(rb.containsKey(key))
		{
			ret = rb.getString(key);
		}
		return ret;
	}
}

3. Small summary

You may find a lot of people on top of something very simple, please do not be misled me, because of the above are the most simple example, source code worth studying very much, only you see for yourself in order to understand.

Third, read the source code of correct posture

We here at a very high heat to class HashMap example, and I highly recommend that you use IDEA to read the code, its own decompiler, allows us to quickly and easily see the source code, there are a number of shortcut keys, let us operating cool to fly.

1. Locate the source

In fact, positioning, it also has a variety of situations

Ctrl + Left

Like this, we have to enter only part of HashMap class method, we can directly Ctrl + left you can navigate to the location of the source

Ctrl+Alt+B

The HashMap put method is to rewrite the Map approach, if we use the Ctrl + Left will jump directly to put the method of the Map interface, it's not the result we want, then we should put the mouse cursor over, then press Ctrl + Alt + B, and there have been many rewritten put method of class

We need to find the class to view, left click you can locate a method to put

2. Check the inheritance

Inheritance of a class of very important, especially inherited abstract class, because the method is an abstract class that can be used in a subclass.

The last step we have to locate the source HashMap, now pulled the top, we can see that when the class definition is about inheritance

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable 

Of course, if you want to be more intuitive and more detailed, then there is to showcase inheritance function in IDEA, you can put the mouse on the category you want to view, and then Ctrl + Alt + Shift + U, or right = "Diagrams =" Show Diagram, then we can see inheritance

 Then generally view the next AbstractMap abstract class, because there may be wait for the next use.

3. Check the class constants

When we enter into HashMap constructor, we found the following code

public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

We only know initialCapacity we passed the initial capacity, but did not know what the DEFAULT_LOAD_FACTOR is, how much lower reading is equal to the source, we can first look briefly constants of this class have, leaving the impression like, help, etc. , Ctrl + left-locate to the amount of position, and then found that there is both good and annotation few constants, constants above, we look at, which helps us to understand these constants

    //序列号
    private static final long serialVersionUID = 362498820763181265L;

    /**
     * 初始容量,必须是2的幂数
     * 1 << 4 = 10000 = 16
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 初始默认值二进制1左移四位 = 16

    /**
     * 最大容量
     * 必须是2的幂数 <= 1<<30.
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * 加载因子,构造函数中没有指定时会被使用
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * 从链表转到树的时机
     */
    static final int TREEIFY_THRESHOLD = 8;

    /**
     * 从树转到链表的时机
     */
    static final int UNTREEIFY_THRESHOLD = 6;

    /**
     * The smallest table capacity for which bins may be treeified.
     * (Otherwise the table is resized if too many nodes in a bin.)
     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
     * between resizing and treeification thresholds.
     */
    static final int MIN_TREEIFY_CAPACITY = 64;

In this way, we have an understanding of the role and significance of the constants of the HashMap

4. Check the constructor

We generally look at a class, this class is the first to look at how to build, that is, to achieve the constructor

    /**
     * 构造一个空的,带有初始值和初始加载因子的HashMap
     * @param  initialCapacity the initial capacity.
     * @throws IllegalArgumentException if the initial capacity is negative.
     */
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

Obviously, the above constructor points to another constructor, then we go in and see the point

    /**
     *
     * @param  initialCapacity the initial capacity
     * @param  loadFactor      the load factor
     * @throws IllegalArgumentException if the initial capacity is negative
     *         or the load factor is nonpositive
     */
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

Here is where we constructor to achieve, and we have to go line by line analysis:

1. Our argument is that we initialCapacity beginning passed in 16, loadFactor is the last step with the default parameters 0.75f

2. Analyzing the initial capacity is less than 0, less than 0 will throw an exception, the next step is not less than 0

3. determining whether the initial capacity greater than the maximum capacity (1 << 30), if greater than the maximum capacity to take

4. Analyzing the load factor is less than or equal to 0 or is a number, the next exception is thrown, or

5. Initialize the load factor of the HashMap

6. The last line is HashMap expansion mechanism to determine the actual capacity based on our capacity to size, we look at the source code of the method

    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

This step is actually larger than we seek to set the minimum capacity of a power of two, as a true value to this initial capacity, rather than a set value, this is the place for subsequent operations. Now we explain the above calculation:

To cap = 13, for example, the initial n = 12, n binary number is 00001100, followed by a right one and once with n or operation to the first example, first | = operator the right to unsigned a right, then the right value 00000110, or when the operation is performed with the n-00001110, to the last step of the iterative computation, n = 00001111, then return when it was returned to n + 1, which is 16.

So far, we have completed the initialization of an empty HashMap, HashMap now ready to operate.

5. Check Logic Method

We generally use HashMap time, put the method used more, and the content he will be more involved, to position now to put method of HashMap

    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

What put and call a method putVal method, and the parameters of decomposition, key, and value have nothing to say, let's look at the hash (key) This method is done

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

If the current key is null, then return directly to the hash value of 0, if it is not null, then get the current key of the hash value is assigned to h, and returns a hash key high current 16-bit and 16-bit low bit different or value, this method allows the high and low are involved in the operation can greatly reduce the probability of a hash collision.

OK! Extra three parameters, where the content hash values ​​we already know, but three values ​​do not know what's the use, do not worry, we enter putVal method

    /**
     * Implements Map.put and related methods.
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value
     * @param evict if false, the table is in creation mode.
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

 Look at the top of a pile of code, is not it began a headache, do not be afraid of him, we break down line by line, he will become very easy.

The first step is to look at comments, which have been translated well, please enjoy

    /**
     * 继承于 Map.put.
     *
     * @param hash key的hash值
     * @param key key
     * @param value 要输入的值
     * @param onlyIfAbsent 如果是 true, 不改变存在的值
     * @param evict if false, the table is in creation mode.
     * @return 返回当前值, 当前值不存在返回null
     */

Then look at the content

1. Create several variables, where Node is HashMap underlying data structure, which is generally the following properties

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
}

2. determining whether the current length of the table is empty, or whether the table is zero, and n and assignment to the tab, if the condition is satisfied (the current HashMap is empty), then resize performed, and the value given to resize tab, the the length of the tab array given n, lack of space, where no detailed explanation resize () method, which more content, in other articles have said a lot, today's focus is to explain how to read the source code, rather than HashMap.

3. Analyzing the underlying array in a position corresponding to the current value of the hash value of the element has no key element, if not directly to the current element into them

4. Connect the step, if the corresponding locations of the underlying array has a value, then some other operation to write data to the column, and return oldValue.

After going through this process we summarize a few points need attention, such as HashMap.put method in to note is that resize, plug the end, the conversion between the tree and list.

Because of space problems, the contents of this method, I just briefly talk about specific ways to view the source code and similar before, step by step analysis can be.

6. Small summary

View source a few tips

1.Ctrl + Left or Ctrl + Alt + B to locate the correct position of the source

2. Check the amount of some kind inside, there is a general understanding

3. Check to see examples of the constructor to initialize status

4. If the code is more complex, decomposing the code, every step

The other source of reading can follow this routine to analyze

IV Summary

Author = Meng new, if wrong, please point out

Reading the source code is absolutely every programmer skills needed, even if the beginning is difficult to read, but also slowly get used to

If you like, welcome thumbs, comments, favorites, attention

Published 55 original articles · won praise 526 · views 180 000 +

Guess you like

Origin blog.csdn.net/shouchenchuan5253/article/details/105196154