`

java笔试题

    博客分类:
  • java
 
阅读更多

前段时间我去某知名的医疗领域互联网公司面试架构师,殊不知某司在面试架构师级别人才时也需要做笔试题目

因毫无准备当时我一下子有些懵掉了。结果可想而知,本次面试情况不理想。在此整理一下将题目记录一下。

题目与结果

public class Main implements Comparable<Main> {

	private int _id;

	private int _sort;

	public Main(int id, int sort) {
		this._id = id;
		this._sort = sort;
	}

	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof Main)) {
			return false;
		}
		Main o = (Main) obj;
		return this._id == o._id;
	}

	/**
	 * <p>
	 * Description:
	 * </p>
	 * 
	 * @param o
	 * @return
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	@Override
	public int compareTo(Main o) {
		if (!equals(o)) {
			return Integer.valueOf(o._sort).compareTo(this._sort);
		}
		return 0;
	}

	public String toString() {
		return this._id + ":" + this._sort;
	}

	public static void main(String[] args) {
		TreeSet<Main> set = new TreeSet<Main>();

		set.add(new Main(1, 1));
		set.add(new Main(2, 2));
		set.add(new Main(1, 3));
		set.add(new Main(2, 3));
		set.add(new Main(1, 4));

		Iterator<Main> it = set.iterator();

		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}

}

 要求根据上面的这段程序代码写出相应的输出结果,正确的结果如下:

2:2
1:1

考察点分析

后面我们再回到题目本身去思考,为什么面试官会出这样一条笔试题目呢?下面是我事后分析的结论

1、考察面试者对Object类的equals()方法的理解

2、考察面试者对Object类的toString()方法的理解

3、考察面试者对TreeSet类内部数据结构的理解

结果分析

接下来我们分析一下为什么是这样一个结果呢?首先我们还是从main方法开始分析

1、创建TreeSet后先添加一个Mai(1,1)实例。调试发现TreeSet内部是使用TreeMap存储

接下来我们再查看TreeMap类的put(K key, V value)方法的内部代码结构

 

    public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
	    // TBD:
	    // 5045147: (coll) Adding null to an empty TreeSet should
	    // throw NullPointerException
	    //
	    // compare(key, key); // type check
            root = new Entry<K,V>(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();
            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<K,V>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

通过调试得出执行set.add(new Main(1, 1));时由于root为空执行的应该是以下代码块

  1. Entry<K,V> t = root;  
  2.     if (t == null) {  
  3.  // TBD:  
  4.  // 5045147: (coll) Adding null to an empty TreeSet should  
  5.  // throw NullPointerException  
  6.  //  
  7.  // compare(key, key); // type check  
  8.         root = new Entry<K,V>(key, value, null);  
  9.         size = 1;  
  10.         modCount++;  
  11.         return null;  
  12.     }  

 

2、接下来我们分析执行set.add(new Main(2, 2))代码行的过程,通过调试分析我们会发现由于这个时候比较器comparator还是为空。因此会进入TreeMap的public V put(K key, V value)方法内部的以下代码块

        else {
            if (key == null)
                throw new NullPointerException();
            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);
        }

 通过上面这部分代码我们进一步分析cmp = k.compareTo(t.key);代码行的执行过程,从这里我们可以看出来k==new Main(2, 2),t.key==new Main(1, 1),因此代码会执行到public int compareTo(Main o)方法

 

public int compareTo(Main o) {
		if (!equals(o)) {
			return Integer.valueOf(o._sort).compareTo(this._sort);
		}
		return 0;
	}
 内部首先会执行重写Object类的public boolean equals(Object obj)方法

 

public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof Main)) {
			return false;
		}
		Main o = (Main) obj;
		return this._id == o._id;
	}

 从上面两段代码我们可以分析出来cmp = k.compareTo(t.key);比较的结果为-1,在此过程中do{}while()仅会执行一次,最终结果cmp<0, Mai(2,2)会作为Main(1,1)的左叶子节点,具体执行的过程如下

  do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
            } while (t != null);
        }
        Entry<K,V> e = new Entry<K,V>(key, value, parent);
        if (cmp < 0)
            parent.left = e;

                                                

                                                                TreeMap结构图

 3、接下来我们分析执行set.add(new Main(1, 3))代码行的过程,因此TreeMap的比较器comparator没有设值,因此执行的代码块如下:

 else {
            if (key == null)
                throw new NullPointerException();
            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);
        }

 在这里我们看一下k.compareTo(t.key);这里的k==new Main(1, 3),t.key==new Main(1, 1),因此执行完Main的public int compareTo(Main o)方法后cmp==0。因此new Main(1, 3)由于key重复直接丢弃掉,具体执行的代码块如下:

 else
                    return t.setValue(value);

                                                           

                                                                                   TreeMap结构图

 

 4、接下来我们分析执行set.add(new Main(2, 3))代码行的过程,通过调试分析关键代码行cmp = k.compareTo(t.key)中k==new Main(2, 3),t.key==new Main(1, 1)。通过do{}while()代码块new Main(2, 3)会跟TreeMap现有所有节点从根节点进行逐一比较,第一次比较结果为cmp<0,因此new Main(2, 3)接着跟TreeMap中的左子节点new Main(2, 2)进行比较,第二次比较结果为cmp==0。因此new Main(2, 3)由于key重复直接丢弃掉,具体执行过程如下:

 else {
            if (key == null)
                throw new NullPointerException();
            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);
        }

                                                    
                                                                      TreeMap结构图

5、最后我们分析执行set.add(new Main(1, 4))代码行的过程,通过调试分析关键代码行cmp = k.compareTo(t.key)中k==new Main(1, 4),t.key==new Main(1, 1)。因此第一次k.compareTo(t.key)的结果为cmp = 0,由于存在重复的key直接丢弃new Main(1, 4)。最终的TreeMap结构如下:

                                                   

                                                                     TreeMap结构图
 
 

最后我们把各个Main的添加顺序调整一下,大家可以猜猜输出的结果又会是怎样的呢?

	public static void main(String[] args) {
		TreeSet<Main> set = new TreeSet<Main>();

		set.add(new Main(2, 2));
		set.add(new Main(1, 1));
		set.add(new Main(1, 3));
		set.add(new Main(2, 3));
		set.add(new Main(1, 4));

		Iterator<Main> it = set.iterator();
        
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}

 

 

 

 

 

 

 

 

  • 大小: 20.9 KB
  • 大小: 5.1 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics