Java中的集合(面试题)

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

思维导图

image.png

image.png


1. HashMap排序题, 上机题


已知一个HashMap<Integer, User> 集合,User 有name (String) 和age (int)属性。请写一个方法实现对HashMap的排序功能,该方法接收HashMap <Integer, User>为形参,返回类型为HashMap

<Integer, User>,要求对HashMap中的User的age倒序进行排序。排序时key=value键值对不得拆散。.

注意: 要做出这道题必须对集合的体系结构非常的熟悉HashMap 本身就是不可排序的,但是该道题偏偏让给HashMap排序,那我们就得想在API中有没有这样的Map结构是有序的,

LinkedHashMap, 对的,就是它,它是Map结构,也是链表结构,有序的,更可喜的是他是HashMap的子类,我们返回LinkedHashMap <Integer,User>即可,还符合面向接口(父类编程的思想)。但凡是对集合的操作,我们应该保持一个原则就是能用JDK中的API就有JDK中的API,比如排序算法我们不应该去用冒泡或者选择,而是首先想到用Collections集合工具类。

public class HashMapTest {
  public static void main(String[] args) {
    HashMap<Integer, User> users = new HashMap<>() ;
    users.put(1, new User ("张三",25) ) ;
    users.put(3, new User ("李四",22) );
    users.put(2, new User ("王五",28) ) ;
    System.out.println(users) ;
    HashMap<Integer, User> sortHashMap = sortHas hMap (users) ;
    System. out . print ln (sortHashMap) ;
    /**
    *控制台输出内容
    * {1=User [name=张三, age=25],2=User [name=王五, age=28], 3=User [name=李四, age=22] }
      {2=User [name=王五, age=28], 1=User [name=张三, age=25], 3-User [name=李四, age=22]}
    */
  }
  public static HashMap<Integer, User> sortHashMap (HashMap<Integer, User> map) {
    //首先拿到map的键值对集合
    Set<Entry<Integer, User>> entrySet = map.entrySet() ;
    // 将set 集合转为List集合,为什么,为了使用工具类的排序方法
    List<Entry<Integer, User>> list = new ArrayList<Entry<Integer, User>> (entrySet);
    //使用Collections集合工具类对list进行排序,排序规则使用匿名内部类来实现
    Collections.sort (list, new Comparator<Entry<Integer, User>>() {
    @Override
    public int compare (Entry<Integer, User> o1, Entry<Integer, User> o2) {
    //按照要求根据User的age的倒序进行排
    return o2.getValue().getAge()-o1.getValue().getAge() ;
    }) ;
    //创建-一个新的有序的HashMap子类的集合
    Linke dHashMap<Integer, User> linkedHashMap = new LinkedHashMap<Integer, User> () ;
    //将List中的数据存储在LinkedHashMap中
    for (Entry<Integer, User> entry : list) {
    linkedHashMap.put (entry.getKey(), entry.getValue()) ;
    }
    //返回结果
    return linkedHashMap;
  }
}


2.集合的安全性问题


请问ArrayList、HashSet、 HashMap 是线程安全的吗?如果不是我想要线程安全的集合怎么办?


 我们都看过上面那些集合的源码(如果没有那就看看吧) ,每个方法都没有加锁,显然都是线程不安全的。话又说过来如果他们安全了也就没第二问了。在集合中Vector和HashTable 倒是线程安全的。你打开源码会发现其实就是把各自核心方法添加上了synchronized关键字。Collections工具类提供了相关的API,可以让上面那3个不安全的集合变为安全的。


//Collections. synch ronizedCollection (c )
//Collections. synch ronizedList (list)
//Collec tions. synch roni ze dMap (m)
//Collections. synchronizedSet (s)


上面几个函数都有对应的返回值类型,传入什么类型返回什么类型。打开源码其实实现原理非常简单,就是将集合的核心方法添加了synchronized关键字。


3. ArrayList 内部用什么实现的?


(回答这样的问题,不要只回答个皮毛,可以再介绍一下 ArrayList内部是如何实现数组的增加和删除的,因为数组在创建的时候长度是固定的,那么就有个问题我们往ArrayList 中不断的添加对象,它是如何管理这些数组呢? )

 ArrayList内部是用Object[]实现的。接下来我们分别分析ArrayList的构造、add、remove、 clear 方法的实现原理。


一、构造函数

1)空参构造


/**
* Constructs a new {@code ArrayList} instance with zero initial capacity.
* /
public ArrayList() {
array = EmptyArray.OBJECT;


array是一个Object[]类型。当我们new -个空参构造时系统调用了EmptyArray.OBJECT 属性, EmptyArray仅

仅是一个系统的类库,该类源码如下:


public final class EmptyArray {
  private EmptyArray() {}
  public static final boolean[] BOOLEAN = new boolean[0] ;
  public static final byte[] BYTE = new byte[0] ;
  public static final char[] CHAR = new char[0] ;
  public static final double[] DOUBLE = new double[0] ;
  public static final int[] INT = new int[0] ;
  public static final Class<?>[] CLASS = new Class[0] ;
  public static final Object[] OBJECT = new Object[0] ;
  public static final String[] STRING = new String[0] ;
  public static final Throwable[] THROWABLE = new Throwable[0] ;
  public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0];
}

也就是说当我们new -个空参ArrayList 的时候,系统内部使用了-个new Object[0]数组。


2)带参构造1


/**
* Constructs a new instance of {@code ArrayList} with the specified
* initial capacity.
* @param capacity
*  the initial capacity of this {@code ArrayList} .
*/
public ArrayList(int capacity) {
  if (capacity < 0) {
  throw new IllegalArgumentException ("capacity < 0: " + capacity) ;
  }
  array = (capacity == 0 ? EmptyArray.OBJECT:new object [capacity]);
}


该构造函数传入一个int值,该值作为数组的长度值。如果该值小于0,则抛出一个运行时异常。如果等于0,则使用一个空数组,如果大于0,则创建一个长度为该值的新数组。


3)带参构造2


/**
* Constructs a new instance of {@code ArrayList} containing the elements of
* the specified collection.
* @param collection
* the collection of elements to add.
*/
public ArrayList (Collection<? extends E> collection) {
  if (collection == null) {
  throw new Nul1PointerException("collection == null");
  }
  object[] a = collection.toArray() ;
  if(a.getClass()!= object[].class) {
  object[] newArray = new object[a.length];
  System.arraycopy(a,0,newArray,0, a.length) ;
  a = newArray;
  }
  array = a;
  size = a.length;
}



如果调用构造函数的时候传入了一个Collection的子类,那么先判断该集合是否为null,为null则抛出空指针异常。如果不是则将该集合转换为数组a,然后将该数组赋值为成员变量array,将该数组的长度作为成员变量size.这里面它先判断a.getClass是否等于Object[].class,toArray方法是Collection接口义的因此其所有的子类都有这样的方法,list集合的toArray和Set集合的toArray

返回的都是Object[]数组。

 其实在看Java源码的时候,作者的很多意图都很费人心思,我能知道他的目标是啥,但是不知道他为何这样写。比如对于ArrayList,array 是他的成员变量,但是每次在方法中使用该成员变量的时候作者都会重新在方法中开辟一个局部变量,然后给局部变量赋值为array,然后再使用,有人可能说这是为了防止并发修改array,毕竟array是成员变量,大家都可以使用因此需要将array变为局部变量,然后再使用,这样的说法并不是都成立的,也许有时候就是老外们写代码的一个习惯而已。


目录
相关文章
|
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`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。