Java中的集合(面试题2)

简介: Java中的集合(面试题)

二、add方法

add方法有两个重载,这里只研究最简单的那个。

/*
* Adds the specified object at the end of this {@code ArrayList}.
* @param obj ect
* the object to add.
* @return always true
*/
@Override public boolean add(E object) {
  object[] a = array;
  int s = size;
  if (s == a.length){
    object[] newArray = new object[s +
    (s < (MIN CAPACITY_ INCREMENT / 2) ?
    MIN CAPACITY INCREMENT : s >> 1)];
    System. arraycopy(a, 0, newArray, 0, s);
    array= a= newArray;
  }
  a[s] = object;
  size = s+1;
  modCount++;
  return true;
}


1、首先将成员变量array赋值给局部变量a,将成员变量size赋值给局部变量s。

2、判断集合的长度s是否等于数组的长度(如果集合的长度已经等于数组的长度了,说明数组已经满了,该重新分配新数组了),重新分配数组的时候需要计算新分配内存的空间大小,如果当前的长度小于MIN_CAPACITY INCREMENT/2 (这个常量值是12,除以2就是6,也就是如果当前集合长度小于6)则分配12个长度,如果集合长度大于6则分配当前长度s的一半长度。这里面用到了三元运算符和位运算,s >> 1,意思就是将s往右移1位,相当于s=s/2,只不过位运算是效率最高的运算。

3、将新添加的object对象作为数组的a[s]个元素。

4、修改集合长度size为s+1。

5、modCotun+ +,该变量是父类中声明的,用于记录集合修改的次数,记录集合修改的次数是为了防止在用迭代器迭代集合时避免并发修改异常,或者说用于判断是否出现并发修改异常的。

6、return true,这个返回值意义不大,因为一直返回true,除非报了一个运行时异常。


三、remove方法

remove方法有两个重载,我们只研究remove (int index)方法。


/*Removes the object at the specified location from this list.
* @param index
* the index of the object to remove 。
* areturn the removed object. 
* @throws IndexOu tofBounds Exception
* when {@code location < 0 || location >= size() }
*/
@Override public E remove (int index) {
  object[] a = array;
  int s = size;
  if (index >= s) {
  throwIndexOu tOfBounds Exception (index, s);
  }
  @SuppressWarnings ("unchecked")
  E result = (E) a [index] ;
  System.arraycopy(a, index + 1, a, index, --s -index) ;
  a[s] = null; // Prevent memory leak
  size = s
  modCount++;
  return result;
}

1、先将成员变量array和size赋值给局部变量a和s。

2、判断形参index是否大于等于集合的长度,如果成了则抛出运行时异常

3、获取数组中脚标为index的对象result,该对象作为方法的返回值

4、调用System的arraycopy函数,拷贝原理如下图所示。


System.arraycopy(a, index + 1,a, index, --s - index);



假设index=2,那么要删除的对象如图打叉部分,我们只需要将该数组后面蓝色区域整体往前移动一位位置即可。上面的代码完成就是这个工作。

5.接下来就是很重要的一个工作,因为删除了一个元素,而且集合整体向前移动了一位,因此需要将集合最后一个元索设置为null,否则就可能内存泄露。

6、重新给成员变量array 和size赋值。

7.记录修改次数。

8、返回删除的元素(让用户再看最后一眼)。


四、dear方法

/**
* Removes all elements from this {@code ArrayList. leaving it * * ewpty.
* @see #isEmpty
* @see #size
*/
Override public void clear() {
  if (size != 0){
  Arrays.fil(array.0, size,null);
  size = 0;
  modCount++;
  }
}



4. List 的三个子类的特点


ArrayList底层结构是数组底层查询快,增删慢。

LinkedList底层结构是链表型的,增删快,查询慢。

voctor底层结构是数组 线程安全的,增删慢查询慢。


5. List 和Map、Set 的区别


5.1结构特点

List和Set是存储单列数据的集合,

Map是存储键和值这样的双列数据的集合;


List 中存储的数据是有顺序,并且允许重复; Map中存储的数据是没有顺序的,其键是不能重复的,它的值是可以有重复的,Set 中存储的数据是无序的,且不允许有重复,但元素在集合中的位置由元素的hashcode决定,位置是固定的(Set集合根据hashcode来

进行数据的存储,所以位置是固定的,但是位置不是用户可以控制的,所以对于用户来说set中的元素还是无序的) ;


5.2实现类

List接口有三个实现类(LinkedList:基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址。链表增删快,查找慢; ArrayList: 基于数组实现,非线程安全的,效率高,便于索引,但不便于插入删除; Vector:基于数组实现,线程安全的,效率低)。

Map接口有三个实现类(HashMap: 基于hash表的Map接口实现,非线程安全,高效,支持null值和null键; HashTable: 线程安全,低效,不支持null值和null键; LinkedHashMap: 是HashMap的一个子类,保存了记录的插入顺序; SortMap 接口: TreeMap, 能够把它保存的记录根据键排序,默认是键值的升序排序)。

Set接口有两个实现类(HashSet: 底层是由HashMap实现,不允许集合中有重复的值,使用该方式时需要重写equals0和hashCode0方法; LinkedHashSet: 继承与HashSet,同时又基于LinkedHashMap来进行实现,底层使用的是LinkedHashMp)。


5.3区别

List集合中对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,例如通过list.get()方法来获取集合中的元素; Map中的每一个元素包含一个键和一个值,成对出现,键对象不可以重复,值对象可以重复; Set集合中的对象不按照特定的方式排序,并且没有重复对象,但它的实现类能对集合中的对象按照特定的方式排序,例如TreeSet类,可以按照默认顺序,也可以通过实现Java.util.Comparator 接口来自定义排序方式。


6 HashMap 和HashTable有什么区别?


HashMap是线程不安全的,HashMap是一个接口,是Map的一个子接口,是将键映射到值得对象不允许键值重复,允许空键和空值;由于非线程安全,HashMap的效率要较HashTable的效率高一些.

HashTable是线程安全的一个集合,不允许null值作为一个key值或者Value值;

HashTable是sychronize,多个线程访问时不需要自己为它的方法实现同步,而HashMap在被多个线程访问的时候需要自己为它的方法实现同步;


7. Java 中ArrayList和Linkedlist区别?


ArrayList和Vector使用了数组的实现,可以认为ArrayList或者Vector封装了对内部数组的操作,比如向数组中添加,删除,插入新的元素或者数据的扩展和重定向。LinkedList使用了循环双向链表数据结构。与基于数组的ArrayList相比,这是两种截然不同的实现技术,这也决定了它们将适用于完全不同的工作场景。

LinkedList链表由一系列表项连接而成。一个表项总是包含3个部分:元素内容,前驱表和后驱表,如图所示:



在下图展示了一个包含3个元素的LinkedList的各个表项间的连接关系。在JDK的实现中,无论LikedList是否为空,链表内部都有一个header表项,它既表示链表的开始,也表示链表的结尾。表项header的后驱表项便是链表中第一个元素,表项header的前驱表项便是链表中最后一个元素。



8. Map中的key和value可以为null么?


HashMap对象的key. value 值均可为null.

HahTable对象的key. value 值均不可为null,

且两者的的key值均不能重复,若添加key相同的键值对,后面的value会自动覆盖前面的value,但不会报错。

测试代码如下:

public class Test {
  public static void main (String[] args) {
  Map<String, String> map = new HashMap<String,String>();// HashMap对象
  Map<String, String> tableMap = new Hashtable<String, String>(); //HashTable对象
  map.put(null, null) ;
  System.out.println ("hashMap的[key]和[value ]均可以为null:"+map.get(null));
  try {
    tableMap.put(null,"3");
    System.out.println(tableMap.get(null));
  } catch (Exception e) {
    System.out.println(" [ERROR] : hashTable的[key]不能为null") ;
  }
  try {
    tableMap.put ("3",null);
    System.out.println(tableMap.get ("3"));
  } catch(Exception e) {
    System.out.println(" [ERROR] : hashTable的[value]不能为null");
  }
  }
}



运行结果:

image.png

目录
相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
12天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
32 5
|
25天前
|
Java 程序员
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
小米,29岁程序员,分享了一次面试经历,详细解析了Java中&和&&的区别及应用场景,展示了扎实的基础知识和良好的应变能力,最终成功获得Offer。
63 14
|
1月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
1月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
25天前
|
存储 缓存 安全
Java 集合框架优化:从基础到高级应用
《Java集合框架优化:从基础到高级应用》深入解析Java集合框架的核心原理与优化技巧,涵盖列表、集合、映射等常用数据结构,结合实际案例,指导开发者高效使用和优化Java集合。
35 4
|
1月前
|
Java 编译器 程序员
Java面试高频题:用最优解法算出2乘以8!
本文探讨了面试中一个看似简单的数学问题——如何高效计算2×8。从直接使用乘法、位运算优化、编译器优化、加法实现到大整数场景下的处理,全面解析了不同方法的原理和适用场景,帮助读者深入理解计算效率优化的重要性。
34 6
|
1月前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
32 2
|
1月前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
1月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。