Java教程

Java集合/泛型面试题2

本文主要是介绍Java集合/泛型面试题2,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1.集合类主要存放于java.util包中,主要有几种接口?

主要包含Set集合list(列表包含Queue)和map(映射)

1.Collection:Collection是集合List,Set,Queue的最基本的接口。

2.Iterator:迭代器,可以通过迭代器遍历集合中的所有数据。

3、Map:是映射表的基础接口

 

 

 

2,什么是list接口

java的list是一个非常常用的数据类型。List是有序的Collection。javaList一共有三个实现类:

分别是ArrayList,LikedList,Vector。

list接口结构图

 

 3、说说ArrayList(数组)

ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问,数组的缺点是每个元素直接按不能有间隔,当数组大小不能满足时需要增加存储能力,就要将已经有数组的数据复制到新的存储空间中,当ArrayList的中间位置插入或删除元素时,需要对数组进行复制,移动,代价非常高,因此,它适合随机抽查找和遍历,不适合删除和添加。

4.Vector(数组实现,线程同步)

Vector和ArrayList一样也是通过数组实现的,不同的是他是支持线程同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写造成的不一致,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。

 

5.说说LikedList(链表)

LikedList是用链表结构存储数据的,很适合数据动态的插入和删除,随机访问和遍历的速度比较慢。另外它还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作栈,队列,双向队列使用。

6.什么是Set集合?

Set注重独一无二的性质,该体系集合用于存储无序(存储何取出的顺序不一定相同)元素,值不能重复,对象的等性本质是hashcode值(java是依据对象的内存地址计算出的次序号)判断的,如果想要两个不同的对象相等,就必须覆盖Object的hashcode方法和equals方法。

set结构图

 

 

 

7.HashSet表(Hash表)

hash表里边存放的是哈希值,HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不是一样的)而是按照HashCode来存储的所以取数据也得是按照哈希值来取,元素的哈希值通过hashcode方法来获取,HashSet首先判断两个元素的哈希值,如果hashcode一样就用equals比较,如果equals为true,则HashSet视为同一个元素,如果equals比较为false就不是同一个元素。哈希值相同,通过equals比较为false的元素怎么存储呢?就是在同样的哈希值下向下延伸(可以认为哈希值相同的元素放在hash桶中)。也就是hash值一样的存一列,如图表示

 

 

HashSet通过hashcode值来确定元素在内存中的位置。一个hashcode上可以存放多个元素。

 

8.什么是TreeSet(二叉树)

1、TreeSet是使用二叉树原理对新add()的对象按照指定的顺序(升序,降序)每增加一个对象都会进行排序,将对象插入二叉树指定的位置

2、Integer和String对象都可以进行默认的TreeSet排序,而自定义类的对象是不可以的,自定义对的类必须实现Compareble接口,并且重写CompareTo方法,才可以正常使用。

3、再重写CompareTo()方法时,要返回相应值才能使用TreeSet按照一定规则来排序

4、比较此对象与指定对象的顺序,如果该对象小于,等于或者大于指定对象,则分别返回负整数,零,或正整数

 

9.说说LikedHashSet(HashSet+LikedHashMap)

对于 LinkedHashSet 而言,它继承与 HashSet、又基于 LinkedHashMap 来实现的。
LinkedHashSet 底层使用 LinkedHashMap 来保存所有元素,它继承与 HashSet,其所有的方法操作上又与 HashSet 相同,因此 LinkedHashSet 的实现上非常简单,只提供了四个构造方法,并
通过传递一个标识参数,调用父类的构造器,底层构造一个 LinkedHashMap 来实现,在相关操作上与父类 HashSet 的操作相同,直接调用父类 HashSet 的方法即可

10.HashMap(数组+链表+红黑树)

 

hashmap根据键的hashcode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却不确定的。hashmap最多只允许一条记录的键为null;允许多条记录的值为null;

hashmap是非线程安全的,即任意时刻都有多条线程同时写hashmap,可能会导致数据不一致问题。如果需要满足安全,可以使用Collections的SynchronizedMap方法使hashmap具有线程安全的能力,或者使用concurrentHashMap,下面这张图介绍hashmap结构

 

 

大方向上, HashMap 里面是一个数组,然后数组中每个元素是一个单向链表。上图中,每个绿色的实体是嵌套类 Entry 的实例, Entry 包含四个属性: key, value, hash 值和用于单向链表的 next。
1. capacity:当前数组容量,始终保持 2^n,可以扩容,扩容后数组大小为当前的 2 倍。
2. oadFactor:负载因子,默认为 0.75。 
3. threshold:扩容的阈值,等于 capacity * loadFactor 
Java8 对 HashMap 进行了一些修改, 最大的不同就是利用了红黑树,所以其由 数组+链表+红黑树 组成。
根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话, 需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n)。为了降低这部分的开销,在 Java8 中, 当链表中的元素超过了 8 个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。

 

 11.说说ConcurrentHashMap

Segment段

ConcurrentHashMap和HashMap思路差不多的。但因为它支持并发操作,所以要复杂一些,整个ConcurrentHashMap由一个个Segment组成,Segment代表一部分或一段的意思,所以很多部分都会将其叫做分段锁。

简单理解ConcurrentHashMap就是一个分段数组,Segment通过继承ReentrantLock来进行加锁,所以每次需要加锁的操作锁住的是一个Segment,这样只要保证每个Segment是线程安全的就实现了全局线程安全。

 

 并行度(默认 16) 

concurrencyLevel:并行级别、并发数、 Segment 数,怎么翻译不重要,理解它。默认是 16,也就是说 ConcurrentHashMap 有 16 个 Segments,所以理论上, 这个时候,最多可以同时支持 16 个线程并发写,只要它们的操作分别分布在不同的 Segment 上。这个值可以在初始化的时候设置为其他值,但是一旦初始化以后,它是不可以扩容的。再具体到每个 Segment 内部,其实每个 Segment 很像之前介绍的 HashMap,不过它要保证线程安全,所以处理起来要麻烦些


java8实现(引入红黑树)

java8对ConcurrentHashMap进行了比较大的改动java8也引入了红黑树

 

 12.HashTable(线程安全)

Hashtable是遗留类,很多映射常用功能与HashMap类似,不同的是它继承于Dictionary类,并且是线程安全的,任意时间只有一个线程能写入Hashtable,并发性不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。Hashtable不建议在新代码中使用,不需要线程安全的场合可以替换hashmap,需要线程安全的场合可以用ConcurrentHashMap替换。

13.TreeMap(可排序的)

TreeMap实现SortedMap接口,能够把他保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当Iterator遍历TreeMap时,得到的记录是排序后的,如果使用排序的映射,建议使用TreeMap,使用TreeMap时,key必须实现Conparable接口或者在构造TreeMap传入自定义的Conparator,否则会在运行时抛出java.lang.ClassCaseException类型的异常。

14.LikedHashMap(记录插入顺序)

LikedHashMap时HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LikedHashMap时,先得到得到记录肯定先插入的,也可以是在构造时带参数,按照访问次序排序。

15.泛型类

泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
16.类型通配符?

类型通配符一般使用?代替具体的类型参数。例如List<?>在逻辑上是List等所有List<具体类型>的父类。

17.类型擦除

java中的泛型基本信息上都是在编译器这个层次来实现的。在生成的java字节代码中是不包含泛型信息的。使用泛型的时候加上的类型参数会被编译器在编译期间去掉,这个过程成为类型擦除。

如在代码中定义的 List和 List等类型,在编译之后都会变成 List。 JVM 看到的只是 List,而由泛型附加的类型信息对 JVM 来说是不可见的。
类型擦除的基本过程也比较简单,首先是找到用来替换类型参数的具体类。这个具体类一般是 Object。如果指定了类型参数的上界的话,则使用这个上界。把代码中的类型参数都替换成具体的类。

 

这篇关于Java集合/泛型面试题2的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!