1、Java集合类框架的基本接口有哪些?
参考答案
Java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。Java集合类里面最基本的接口有:
Collection:代表一组对象,每一个对象都是它的子元素。
Set:不包含重复元素的Collection。
List:有顺序的collection,并且可以包含重复元素。
Map:可以把键(key)映射到值(value)的对象,键不能重复。
2、为什么集合类没有实现Cloneable和Serializable接口?
参考答案
3、什么是迭代器(Iterator)?
参考答案
4、Iterator和ListIterator的区别是什么?
参考答案
Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
5、快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?
参考答案
6、Java中的HashMap的工作原理是什么?
参考答案
7、hashCode()和equals()方法的重要性体现在什么地方?
参考答案
8、HashMap和Hashtable有什么区别?
参考答案
HashMap和Hashtable都实现了Map接口,因此很多特性非常相似。但是,他们有以下不同点:
HashMap允许键和值是null,而Hashtable不允许键或者值是null。
Hashtable是同步的,而HashMap不是。因此,HashMap更适合于单线程环境,而Hashtable适合于多线程环境。
HashMap提供了可供应用迭代的键的集合,因此,HashMap是快速失败的。另一方面,Hashtable提供了对键的列举(Enumeration)。
一般认为Hashtable是一个遗留的类。
适用场景分析:
HashMap和HashTable:HashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。HashMap允许空键值,而HashTable不允许。
HashMap:适用于Map中插入、删除和定位元素。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
9、数组(Array)和列表(ArrayList)有什么区别?什么时候应该使用Array而不是ArrayList?
参考答案
Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
Array大小是固定的,ArrayList的大小是动态变化的。
ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。
10、ArrayList和LinkedList有什么区别?
参考答案
ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。
相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
也可以参考ArrayList vs. LinkedList。
适用场景分析:
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。
11、Comparable和Comparator接口是干什么的?列出它们的区别。
参考答案
Java提供了包含compare()和equals()两个方法的Comparator接口。compare()方法用来给两个输入参数排序,返回负数,0,正数表明第一个参数是小于,等于,大于第二个参数。equals()方法需要一个对象作为参数,它用来决定输入参数是否和comparator相等。只有当输入参数也是一个comparator并且输入参数和当前comparator的排序结果是相同的时候,这个方法才返回true。
12、什么是Java优先级队列(Priority Queue)?
参考答案
13、你了解大O符号(big-O notation)么?你能给出不同数据结构的例子么?
参考答案
大O符号也可用来描述其他的行为,比如:内存消耗。因为集合类实际上是数据结构,我们一般使用大O符号基于时间,内存和性能来选择最好的实现。大O符号可以对大量数据的性能给出一个很好的说明。
14、如何权衡是使用无序的数组还是有序的数组?
参考答案
15、Java集合类框架的最佳实践有哪些?
参考答案
有些集合类允许指定初始容量。因此,如果我们能估计出存储的元素的数目,我们可以设置初始容量来避免重新计算hash值或者是扩容。
为了类型安全,可读性和健壮性的原因总是要使用泛型。同时,使用泛型还可以避免运行时的ClassCastException。
使用JDK提供的不变类(immutable class)作为Map的键可以避免为我们自己的类实现hashCode()和equals()方法。
编程的时候接口优于实现。
底层的集合实际上是空的情况下,返回长度是0的集合或者是数组,不要返回null。
16、Enumeration接口和Iterator接口的区别有哪些?
参考答案
17、HashSet和TreeSet有什么区别?
参考答案
1.TreeSet 是二叉树(红黑树的树据结构)实现的,Treeset中的数据是自动排好序的,不允许放入null值。
2.HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。
3.HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例。
另一方面,TreeSet是由一个树形的结构来实现的,它里面的元素是有序的。因此,add(),remove(),contains()方法的时间复杂度是O(logn)。
适用场景分析:
HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。为快速查找而设计的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。
18、集合框架,list,map,set都有哪些具体的实现类,区别都是什么?
参考答案
1.List,Set都是继承自Collection接口,Map则不是;
2.List特点:元素有放入顺序,元素可重复;
Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法;
另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值)。
3.Set和List对比:
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
4.Map适合储存键值对的数据。
5.线程安全集合类与非线程安全集合类
LinkedList、ArrayList、HashSet是非线程安全的,Vector是线程安全的;
HashMap是非线程安全的,HashTable是线程安全的;
StringBuilder是非线程安全的,StringBuffer是线程安全的。
19、ArrayList与Vector的区别和适用场景
参考答案
ArrayList有三个构造方法:
public ArrayList(int initialCapacity)//构造一个具有指定初始容量的空列表。 public ArrayList()//构造一个初始容量为10的空列表。 public ArrayList(Collection extends E> c)//构造一个包含指定 collection 的元素的列表
Vector有四个构造方法:
public Vector() // 使用指定的初始容量和等于零的容量增量构造一个空向量。 public Vector(int initialCapacity) // 构造一个空向量,使其内部数据数组的大小,其标准容量增量为零。 public Vector(Collection extends E> c)// 构造一个包含指定 collection 中的元素的向量 public Vector(int initialCapacity,int capacityIncrement)//使用指定的初始容量和容量增量构造一个空的向量
ArrayList和Vector都是用数组实现的,主要有这么三个区别:
1).Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。而ArrayList不是,这个可以从源码中看出,Vector类中的方法很多有synchronized进行修饰,这样就导致了Vector在效率上无法与ArrayList相比;
2).两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。
3).Vector可以设置增长因子,而ArrayList不可以。
4).Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。
适用场景:
1.Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。
2.如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。
class B extends A {}
class C extends A {}
class D extends B {}
Which four statements are true ?
-
The type Listis assignable to List.
-
The type Listis assignable to List.
-
The type List
-
The type List
is assignable to List. -
The type Listis assignable to List.
-
The type List
-
The type Listis assignable to List.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
static
void
main(String[] args) {
List a;
List list;
list = a;
//A对,因为List就是List>,代表最大的范围,A只是其中的一个点,肯定被包含在内
List b;
a = b;
//B错,点之间不能相互赋值
List> qm;
List
qm = o;
//C对,List>代表最大的范围,List
List
List
extends
B> downB;
downB = d;
//D对,List extends B>代表小于等于B的范围,List
List
extends
A> downA;
a = downA;
//E错,范围不能赋值给点
a = o;
//F错,List
downA = downB;
//G对,小于等于A的范围包含小于等于B的范围,因为B本来就比A小,B时A的子类嘛
}
|
-
HashMap能够保证其中元素的顺序
-
HashMap允许将null用作值
-
HashMap允许将null用作键
-
HashMap使用键/值得形式保存数据
Integer i01 =
59
;
int
i02 =
59
;
Integer i03 =Integer.valueOf(
59
);
Integer i04 =
new
Integer(
59
)。
正确答案: C
System.out.println(i01== i02);
System.out.println(i01== i03);
System.out.println(i03== i04);
System.out.println(i02== i04);
Integer i01=59 的时候,会调用 Integer 的 valueOf 方法,
1
2
3
4
5
|
public
static
Integer valueOf(
int
i) {
assert
IntegerCache.high>=
127
;
if
(i >= IntegerCache.low&& i <= IntegerCache.high)
return
IntegerCache.cache[i+ (-IntegerCache.low)];
return
new
Integer(i); }
|
这个方法就是返回一个 Integer 对象,只是在返回之前,看作了一个判断,判断当前 i 的值是否在 [-128,127] 区别,且 IntegerCache 中是否存在此对象,如果存在,则直接返回引用,否则,创建一个新的对象。
在这里的话,因为程序初次运行,没有 59 ,所以,直接创建了一个新的对象。
int i02=59 ,这是一个基本类型,存储在栈中。
Integer i03 =Integer.valueOf(59); 因为 IntegerCache 中已经存在此对象,所以,直接返回引用。
Integer i04 = new Integer(59) ;直接创建一个新的对象。
System. out .println(i01== i02); i01 是 Integer 对象, i02 是 int ,这里比较的不是地址,而是值。 Integer 会自动拆箱成 int ,然后进行值的比较。所以,为真。
System. out .println(i01== i03); 因为 i03 返回的是 i01 的引用,所以,为真。
System. out .println(i03==i04); 因为 i04 是重新创建的对象,所以 i03,i04 是指向不同的对象,因此比较结果为假。
System. out .println(i02== i04); 因为 i02 是基本类型,所以此时 i04 会自动拆箱,进行值比较,所以,结果为真。