Java集合框架面试问题集锦
作者:网络转载 发布时间:[ 2015/1/13 11:47:50 ] 推荐标签:软件开发 java
Q:怎么去选择该使用哪一个呢?
A:使用无序的HashSet和HashMap,还是使用有序的TreeSet和TreeMap,主要取决于你的实际使用场景,一定程度上还和数据的大小以及运行环境有关。比较实际的一个原因是,如果插入和更新都比较频繁的话,那么保证元素的有序可以提高快速和频繁查找的性能。如果对于排序操作(例如产生一个报表合作者运行一个批处理程序)的要求不是很频繁的话,那么把数据以无序的方式存储,然后在需要排序的时候用Collections.sort(…)来进行排序,会比用有序的方式来存储可能会更加高效。这个只是一种可选的方式,没人能给你一个确切的答案。即使是复杂度的理论,例如O(n),成立的前提也是在n足够大的情况下。只要在n足够小的情况下,算是O(n)的算法也可能会比O(log n)的算法更加高效。另外,一个算法可能在AMD处理器上的速度比在Intel处理器上快。如果你的系统有交换区的话,那么你还要考虑磁盘的性能。可以确定的性能测试途径是用大小合适的数据来测试和衡量程序的性能和内存使用量。在你所选择的硬件上来测试这两种指标,是合适的方法。
Q:如何权衡是用无序的数组还是有序的数组呢?
A:有序数组大的优点在于n比较大的时候,搜索元素所花的时间O(log n)比无序素组所需要的时间O(n)要少很多。有序数组的缺点在于插入的时间开销比较大(一般是O(n)),因为所有比插入元素大的值都要往后移动。而无序数组的插入时间开销是常量时间,也是说,插入的速度和元素的数量无关。下面的代码片段展示了向有序数组和无序数组插入元素。
插入元素到一个无序的数组里
packagebigo;
importjava.util.Arrays;
publicclassInsertingElementsToArray{
publicstaticvoidinsertUnsortedArray(StringtoInsert){
String[]unsortedArray={"A","D","C"};
String[]newUnsortedArray=newString[unsortedArray.length+1];
System.arraycopy(unsortedArray,0,newUnsortedArray,0,3);
newUnsortedArray[newUnsortedArray.length-1]=toInsert;
System.out.println(Arrays.toString(newUnsortedArray));
}
publicstaticvoidmain(String[]args){
insertUnsortedArray("B");
}
}
插入元素到一个有序数组
package bigo;
import java.util.Arrays;
public class InsertingElementsToArray {
public static void insertSortedArray(String toInsert) {
String[ ] sortedArray = { "A", "C", "D" };
/*
* Binary search returns the index of the search item
* if found, otherwise returns the minus insertion point. This example
* returns index = -2, which means the elemnt is not found and needs to
* be inserted as a second element.
*/
int index = Arrays.binarySearch(sortedArray, toInsert);
if (index < 0) { // not found.
// array indices are zero based. -2 index means insertion point of
// -(-2)-1 = 1, so insertIndex = 1
int insertIndex = -index - 1;
String[ ] newSortedArray = new String[sortedArray.length + 1];
System.arraycopy(sortedArray, 0, newSortedArray, 0, insertIndex);
System.arraycopy(sortedArray, insertIndex,
newSortedArray, insertIndex + 1, sortedArray.length - insertIndex);
newSortedArray[insertIndex] = toInsert;
System.out.println(Arrays.toString(newSortedArray));
}
}
public static void main(String[ ] args) {
insertSortedArray("B");
}
}
所以,如何去选择还是取决于实际的使用情况。你需要考虑下面几个问题。你的程序是插入/删除的操作多,还是查找的操作多?数组里多可能存储多少元素?排序的频率是多少?以及你的性能基准测试的结果是怎样的?
Q:怎么实现一个不可变集合?
A:这个功能在Collections类里实现了,它通过装饰模式实现了对一般集合的封装。
public class ReadOnlyExample {
public static void main(String args[ ]) {
Set<string> set = new HashSet<string>( );
set.add("Java");
set.add("JEE");
set.add("Spring");
set.add("Hibernate");
set = Collections.unmodifiableSet(set);
set.add("Ajax"); // not allowed.
}
}
Q:下面的代码的功能是什么呢?其中的LinkedHashSet能用HashSet来取代吗?
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
public class CollectionFunction {
public <e> List<e> function (List <e> list) {
return new ArrayList<e>(new LinkedHashSet<e>(list));
}
}
A:上面的代码代码通过把原有列表传入一个LinkedHashSet来去除重复的元素。在这个情况里,LinkedHashSet可以保持元素原来的顺序。如果这个顺序是不需要的话,那么上面的LinkedHashSet可以用HashSet来替换。
Q:Java集合框架都有哪些佳实践呢?
A:根据实际的使用情况选择合适的数据结构,例如固定大小的还是需要增加大小的,有重复元素的还是没有的,需要保持有序还是不需要,遍历是正向的还是双向的,插入是在末尾的还是任意位置的,更多的插入还是更多的读取,是否需要并行访问,是否允许修改,元素类型是相同的还是不同的,等等。另外,还需要尽早考虑多线程,原子性,内存使用量以及性能等因素。
不要假设你的集合里元素的数量一直会保持较小,它也有可能随着时间增长。所以,你的集合好能够给定一个合适的大小。
针对接口编程优于针对实现编程。例如,可能在某些情况下,LinkedList是佳的选择,但是后来ArrayList可能因为性能的原因变得更加合适
不好的方式:
ArrayList list = new ArrayList(100);
好的方式:
// program to interface so that the implementation can change
List list = new ArrayList(100);
List list2 = new LinkedList(100);
List emptyList = Collections.emptyList( );
Set emptySet = Collections.emptySet( );
在取得列表的时候,如果返回的结果是空的话,好返回一个长度为0的集合或者数组,而不要返回null。因为,返回null的话可能能会导致程序错误。调用你的方法的开发人员可能会忘记对返回为null的情况进行处理。
封装好集合:一般来说,集合都是不可变的对象。所以尽量不要把集合的成员变量暴露给调用者。因为他们的操作一般都不会进行必要的校验。
注:这些Java面试题和答案都是从我的书《Core Java Career Essentials》里提取出来的。

sales@spasvo.com