Java常见面试题总结

来源:互联网 发布:尸者的帝国知乎 编辑:程序博客网 时间:2024/06/06 10:03

1.Map是否能用自定义对象来做key,如果能,有什么要求?

答:只要能保证key的唯一性就可以做key,首先看一下HashMap和TreeMap在添加元素时是如何保证key的唯一性的?

HashMap

HashMap底层的数据结构,是数组加单链表.jdk源码:

/*通过对加进来的key的hashcode进行hash(hash函数,用来使元素均匀分布的)处理,然后找到对应的数组位置,如果该位置已经有元素了,那么就存储在该位置的链表的末位(越先在该位置的越靠前).*//*判断key是否相等的过程:先看hash(hashcode)的值是否相等,然后看==或equals是否相等.如果相等则用新的value替代旧的value,并将旧的value返回.*///hashMap的put方法.public V put(K key, V value) {        return putVal(hash(key), key, value, false, true);}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;    }//hashMap的containsKey方法.public boolean containsKey(Object key) {        return getNode(hash(key), key) != null;}final Node<K,V> getNode(int hash, Object key) {        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;        if ((tab = table) != null && (n = tab.length) > 0 &&            (first = tab[(n - 1) & hash]) != null) {            if (first.hash == hash && // always check first node                ((k = first.key) == key || (key != null && key.equals(k))))                return first;            if ((e = first.next) != null) {                if (first instanceof TreeNode)                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);                do {                    if (e.hash == hash &&                        ((k = e.key) == key || (key != null && key.equals(k))))                        return e;                } while ((e = e.next) != null);            }        }        return null;    }

TreeMap

TreeMap的底层数据结构是二叉树.jdk源码:

/*排序时有两种方式,一种是通过自身的Comparator进行排序,另一种是通过实现了Comparable接口的key进行排序,优先使用第一种方式,当持有的Comparator(默认为null)为null时则采用第二种方式.*//*如果相等则用新的value替代旧的value,并将旧的value返回.*///treeMap的put方法.public V put(K key, V value) {        Entry<K,V> t = root;        if (t == null) {            compare(key, key); // type (and possibly null) check            root = new Entry<>(key, value, null);            size = 1;            modCount++;            return null;        }        int cmp;        Entry<K,V> parent;        // split comparator and comparable paths        Comparator<? super K> cpr = comparator;        if (cpr != null) {            do {                parent = t;                cmp = cpr.compare(key, t.key);                if (cmp < 0)                    t = t.left;                else if (cmp > 0)                    t = t.right;                else                    return t.setValue(value);            } while (t != null);        }        else {            if (key == null)                throw new NullPointerException();            @SuppressWarnings("unchecked")                Comparable<? super K> k = (Comparable<? super K>) key;            do {                parent = t;                cmp = k.compareTo(t.key);                if (cmp < 0)                    t = t.left;                else if (cmp > 0)                    t = t.right;                else                    return t.setValue(value);            } while (t != null);        }        Entry<K,V> e = new Entry<>(key, value, parent);        if (cmp < 0)            parent.left = e;        else            parent.right = e;        fixAfterInsertion(e);        size++;        modCount++;        return null;    }//treeMap的containsKey方法. public boolean containsKey(Object key) {        return getEntry(key) != null; }  final Entry<K,V> getEntry(Object key) {        // Offload comparator-based version for sake of performance        if (comparator != null)            return getEntryUsingComparator(key);        if (key == null)            throw new NullPointerException();        @SuppressWarnings("unchecked")            Comparable<? super K> k = (Comparable<? super K>) key;        Entry<K,V> p = root;        while (p != null) {            int cmp = k.compareTo(p.key);            if (cmp < 0)                p = p.left;            else if (cmp > 0)                p = p.right;            else                return p;        }        return null;    }

2.String类的常见面试题

String s1 = "a";String s3 = "ab";String s4 = s1 + "b";String s5 = "a"+"b";(1)System.out.println(s3 == s4); //false(2)System.out.println(s3 == s5); //true(3)System.out.println(s3.intern() == s5); //true(4)System.out.println(s3.intern() == s5.intern()); //true

Java的String类型的字符串都是不可变的,String类使用final修饰的.所以只要有一个字符串被确定的用双引号声明了以后,就会被放到字符串常量池里面.常量池里面的相同的字符串常量无论是用”==”比较还是”equals方法”比较都是返回true.

解释(1) :所以s3 = “ab”,此时字符串”ab”是会被放到常量池里面,但是s4 = s1 + “b”,中的s4是由变量s1和”b”共同组成的,所以s4其实是一个变量,所以不会被储存在常量池里面,而是储存在堆内存中.

解释(2) : s3和s5都能被确定下来,所以被储存在常量池里面.

解释(3)或(4) : 字符串调用intern()的执行过程是,判断字符串常量池里面是否含有当前字符串,如果含有则直接返回,如果不含有,则把当前字符串放到字符串常量池里面,并返回.(intern()方法之后”==”的结果与字符串调用equals方法的结果一样)

原创粉丝点击