Java基础常见面试题——集合篇

All Love In Java 相关链接:

Java基础常见面试题——入门:https://blog.csdn.net/qq_41822345/article/details/104488442
Java基础常见面试题——集合篇:https://blog.csdn.net/qq_41822345/article/details/104514994
Java基础常见面试题——HashMap总结:https://blog.csdn.net/qq_41822345/article/details/104436909
Java基础常见面试题——多线程:https://blog.csdn.net/qq_41822345/article/details/104488481
Java基础常见面试题——锁:https://blog.csdn.net/qq_41822345/article/details/104514840
Java基础常见面试题——最后十题:https://blog.csdn.net/qq_41822345/article/details/104480830

2020级应届生——Java面试题(for 秋招):https://blog.csdn.net/qq_41822345/article/details/100141708

Java基础常见面试题——设计模式:https://blog.csdn.net/qq_41822345/article/details/104488560
Java泛型(连面三家公司都问这个?):https://blog.csdn.net/qq_41822345/article/details/104967036
字符串String学习(常见笔试面试题):https://blog.csdn.net/qq_41822345/article/details/105070605
Java 数的位运算:https://blog.csdn.net/qq_41822345/article/details/104831622
日期API解析总结(Java8新日期类API):https://blog.csdn.net/qq_41822345/article/details/109881663

Java 并发编程学习笔记:https://blog.csdn.net/qq_41822345/article/details/104620428
Java 并发编程常见面试题:https://blog.csdn.net/qq_41822345/article/details/104640761
Java 内存模型:https://blog.csdn.net/qq_41822345/article/details/104617364

Java关键字——synchronized:https://blog.csdn.net/qq_41822345/article/details/105144315
Java关键字——volatile:https://blog.csdn.net/qq_41822345/article/details/105243644
Java关键字——ThreadLocal:https://blog.csdn.net/qq_41822345/article/details/105297940

JVM常见面试题1:https://blog.csdn.net/qq_41822345/article/details/104417108
JVM常见面试题2:https://blog.csdn.net/qq_41822345/article/details/104531570
JVM常见面试题3:https://blog.csdn.net/qq_41822345/article/details/104531640
Java JVM操作工具:https://blog.csdn.net/qq_41822345/article/details/119705517
JDK自带工具包的使用:https://blog.csdn.net/qq_41822345/article/details/105523832

java框架入门:https://blog.csdn.net/qq_41822345/article/details/104488132
java动态代理:https://blog.csdn.net/qq_41822345/article/details/105108955
MyBatis的实体类:https://blog.csdn.net/qq_41822345/article/details/104688219
Spring框架——IOC与AOP:https://blog.csdn.net/qq_41822345/article/details/104983468
Spring Boot 源码解析:https://blog.csdn.net/qq_41822345/article/details/104780423
SpringBoot——自动配置原理:https://blog.csdn.net/qq_41822345/article/details/108312465
如何优雅地停止 Spring Boot 应用:https://blog.csdn.net/qq_41822345/article/details/106800135
SpringBoot+Shiro(RBAC实现):https://blog.csdn.net/qq_41822345/article/details/107444270
SpringBoot+jasypt数据库连接加密:https://blog.csdn.net/qq_41822345/article/details/107435801
Swagger组件—Java最流行的API文档框架:https://blog.csdn.net/qq_41822345/article/details/106788392
单点登录(原理与代码):https://blog.csdn.net/qq_41822345/article/details/105015154

MyBatis学习笔记:https://blog.csdn.net/qq_41822345/article/details/104688219
MyBatis源码学习笔记(从设计模式看源码):https://blog.csdn.net/qq_41822345/article/details/104934044
SpringCloud微服务学习:https://blog.csdn.net/qq_41822345/article/details/104585350

后端开发——接口篇:https://blog.csdn.net/qq_41822345/article/details/108066285
后端开发——缓存篇:https://blog.csdn.net/qq_41822345/article/details/108110964
后端开发——日志篇:https://blog.csdn.net/qq_41822345/article/details/108120098

Java Web 学习笔记:https://blog.csdn.net/qq_41822345/article/details/104516659
什么是敏捷开发:https://blog.csdn.net/qq_41822345/article/details/106499258
前后端分离:https://blog.csdn.net/qq_41822345/article/details/104403807
java图书管理系统(前后端分离前):https://blog.csdn.net/qq_41822345/article/details/104403813
java图书管理系统(前后端分离后):https://blog.csdn.net/qq_41822345/article/details/104411133
微服务入门项目——外卖订单系统:https://blog.csdn.net/qq_41822345/article/details/104404451
Java项目——商城 (附源码):https://blog.csdn.net/qq_41822345/article/details/90289659
gulimall商城2021:https://blog.csdn.net/qq_41822345/article/details/114177833

1.java容器类(集合类)?

集合总共有两大接口:Collection和Map

  • Collection是元素集合,Map是键值对集合;
  • ①.Collection接口是List和Set接口的父接口;List和Set接口继承自Collection接口。
    (a). List是有序可重复元素集合,Set是无序不可重复元素集合;其中接口List的实现类有ArrayList和LinkedList,ArrayList采用数组存放元素, LinkedList采用的则是链表;
    (b). 接口set的实现类有HashSet、TreeSet,其中hashSet就是hashMap,treeSet默认升序;
  • ② HashMap 、HashTable 、TreeMap都是实现了Map接口的类,并且HashTable是线程安全的,但是HashMap性能更好。当元素的顺序很重要时选用TreeMap,当元素不必以特定的顺序进行存储时,使用HashMap。Hashtable的使用不被推荐,因为HashMap提供了所有类似的功能,并且速度更快。当你需要在多线程环境下使用时,HashMap也可以转换为线程同步的。
    在这里插入图片描述

此图来源于:https://img-blog.csdn.net/20160124221843905

2.什么是迭代器(Iterator)?

   迭代器是一种通用的集合元素的获取方式,它可以忽略集合中元素对象的不同,完成对集合的遍历。迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
   Java中的Iterator功能比较简单,并且只能单向移动:   
(1) 使用方法iterator()要求容器返回一个Iterator。注意:iterator()方法是java.lang.Iterable接口的方法,被Collection继承。
(2) 使用hasNext()检查序列中是否还有元素。   
(3) 使用next()获得序列中的下一个元素。  
(4) 使用remove()将迭代器新返回的元素删除。
   Iterator只能正向遍历集合,适用于获取移除元素。ListIterator继承自Iterator,专门针对List,可以从两个方向来遍历List,同时支持元素的修改(插入和删除)。

3.快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?

一、快速失败
   在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的结构进行了修改(增加、删除),则会抛出Concurrent Modification Exception(并发修改异常)。
    原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果结构发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
    注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。
    场景:java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。
二、安全失败
    采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
    原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。
    缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。
    场景:java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

4.理解Java异常

   Java把异常当作对象来处理(面向对象),并定义一个基类java.lang.Throwable作为所有异常的超类。在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。

  • Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
  • Throwable分成了两个不同的分支,一个分支是Error,它表示不希望被程序捕获或者是程序无法处理的错误。另一个分支是Exception,它表示用户程序可能捕捉的异常情况或者说是程序可以处理的异常。其中异常类Exception又分为运行时异常(例如空指针异常)和非运行时异常(例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略)。
    在这里插入图片描述

Java异常处理涉及到五个关键字,分别是:try、catch、finally、throw、throws。
①try–用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
②catch–用于捕获异常。catch用来捕获try语句块中发生的异常。
③finally–finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有在finally块执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
④throw --用在语句中,抛出异常。
⑤throws–用在方法中,用于声明该方法可能抛出的异常。
throw与throws的区别:
1.throws出现在方法函数头;而throw出现在函数体。
2.throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。
3.两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。
编程建议:
①在写程序时,对可能会出现异常的部分通常要用try{}catch{}去捕捉它并对它进行处理;
②用try{…}catch{…}捕捉了异常之后一定要对在catch{…}中对其进行处理,那怕是最简单的一句输出语句,或栈输入e.printStackTrace();
③如果是捕捉IO输入输出流中的异常,一定要在try{…}catch{…}后加finally{…}把输入输出流关闭;
④如果在函数体内用throw抛出了某种异常,最好要在函数名中加throws抛异常声明,然后交给调用它的上层函数进行处理。

5.HashMap遍历的四种方法

  • 方法1:使用For-Each迭代entries ———key和value都需要的时候
    这是最常见的方法,并在大多数情况下更可取的。当你在循环中需要使用Map的键和值时,就可以使用这个方法。
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(Map.Entry<Integer, Integer> entry : map.entrySet()){
	System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
}

注意:For-Each循环是Java5新引入的,所以只能在Java5以上的版本中使用。如果你遍历的map是null的话,For-Each循环会抛出NullPointerException异常,所以在遍历之前你应该判断是否为空引用。

  • 方法2 使用For-Each迭代keys和values ———key和value只需要其中之一时

如果你只需要用到map的keys或values时,你可以遍历KeySet或者values代替entrySet。

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
//iterating over keys only
for (Integer key : map.keySet()) {
	System.out.println("Key = " + key);
}
//iterating over values only
for (Integer value : map.values()) {
	System.out.println("Value = " + value);
}

这个方法比entrySet迭代具有轻微的性能优势(大约快10%)并且代码更简洁。

  • 方法3 使用Iterator迭代 ———万金油方法(迭代器)

使用泛型

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
	Map.Entry<Integer, Integer> entry = entries.next();
	System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

不使用泛型

Map map = new HashMap();
Iterator entries = map.entrySet().iterator();
while (entries.hasNext()) {
	Map.Entry entry = (Map.Entry) entries.next();
	Integer key = (Integer)entry.getKey();
	Integer value = (Integer)entry.getValue();
	System.out.println("Key = " + key + ", Value = " + value);
}

你可以使用同样的技术迭代keyset或者values
这个似乎有点多余但它具有自己的优势。首先,它是遍历老java版本map的唯一方法。另外一个重要的特性是可以让你在迭代的时候从map中删除entries的(通过调用iterator.remover())唯一方法.如果你试图在For-Each迭代的时候删除entries,你将会得到unpredictable resultes 异常。从性能方法看,这个方法等价于使用For-Each迭代

  • 方法4 迭代keys并搜索values(低效的) ———最慢的方法
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
	Integer value = map.get(key);
	System.out.println("Key = " + key + ", Value = " + value);
}

6.Java NIO你了解么?讲一讲你最熟悉的部分?

   NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
   NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector(选择器)。传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。
https://mp.weixin.qq.com/s/fwkKymPOBJODo6sFHYMUHA
(1)面向流与面向缓冲
Java IO和NIO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
(2)阻塞与非阻塞IO
Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
(3)选择器(Selectors)
Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

7.transient关键字?

   我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。
   然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。
   总之,java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

8.循环结构中break、continue、return和exit的区别

1. break
  break语句的使用场合主要是switch语句和循环结构。在循环结构中使用break语句,如果执行了break语句,那么就退出循环,接着执行循环结构下面的第一条语句。如果在多重嵌套循环中使用break语句,当执行break语句的时候,退出的是它所在的循环结构,对外层循环没有任何影响。如果循环结构里有switch语句,并且在switch语句中使用了break语句,当执行switch语句中的break语句时,仅退出switch语句,不会退出外面的循环结构。通过图,读者可以很直观地了解break语句的使用。
2. continue
  continue语句是这四种结束循环的方式中最特殊的,因为它并没有真的退出循环,而是只结束本次循环体的执行,所以在使用continue的时候要注意这一点。图为各种循环结构中continue语句的使用。
  在for循环中,首先执行表达式1(注意表达式1在整个循环中仅执行一次),接着执行表达式2,如果满足条件,那么执行循环体,如果在循环体中执行了continue语句,那么就跳转到表达式3处执行,接下进行下一次循环,执行表达式2,看是否满足条件;在while循环中,如果执行了continue语句,那么就直接跳转到表达式处,开始下一次的循环判断;在do while循环体中如果执行了continue语句,那么就跳转到表达式处进行下一次的循环判断,这一点前面已经验证过了。
在这里插入图片描述
3. return语句
  如果在程序中遇到return语句,那么代码就退出该函数的执行,返回到函数的调用处,如果是main()函数,那么结束整个程序的运行。
4. exit()函数
  exit()函数与return语句的最大区别在于,调用exit()函数将会结束当前进程,同时删除子进程所占用的内存空间,把返回信息传给父进程。当exit()中的参数为0时,表示正常退出,其他返回值表示非正常退出,执行exit()函数意味着进程结束;而return仅表示调用堆栈的返回,其作用是返回函数值,并且退出当前执行的函数体,返回到函数的调用处,在main()函数中, return n和exit(n)是等价的。

9.大数问题与进制转换

BigInteger 和 BigDecimal 是在java.math包中已有的类,分别表示大整型和大浮点型,理论上能够表示无限大的数,只要计算机内存足够大。用于解决转换问题、精度出现问题。

Java位运算问题:
https://blog.csdn.net/qq_41822345/article/details/104831622

package com.liuwen.练习.大数;

import java.math.*;
/**
 * @description: Good good study,day day up!
 * @author: Liu Wen
 * @create: 2020-02-26 13:05
 **/
public class Main{
    public static void main(String[] args) {
        //大数加减乘除
        int a = 156, b = 55, c = 1652;BigInteger x, y, z, ans;
        x = BigInteger.valueOf(a);y = BigInteger.valueOf(b);z = BigInteger.valueOf(c);
        double d = 166.7,e = 55.5;BigDecimal num1,num2,res;
        num1 = BigDecimal.valueOf(d);num2 = BigDecimal.valueOf(e);
        ans = x.add(y);
        System.out.println("a+b= "+ans);                   //a+b= 211
        ans = x.subtract(y);
        System.out.println("a-b= "+ans);                   //a-b= 101
        ans = x.multiply(y);
        System.out.println("a*b= "+ans);                   //a*b= 8580
        ans = z.divide(y);
        System.out.println("c/b= "+ans);                   //c/b= 30
        ans = z.remainder(y);
        System.out.println("c%b= "+ans);                   //c%b= 2
        res = num1.add(num2);
        System.out.println("num1+num2= "+res);             //num1+num2= 222.2
        res = num1.subtract(num2);
        System.out.println("num1-num2= "+res);             //num1-num2= 111.2
        res = num1.multiply(num2); 
        System.out.println("num1*num2= "+res);             //num1*num2= 9251.85
        res = num1.divide(num1);  
        System.out.println("num1/num1= "+res);             //num1/num1= 1
        res = num1.remainder(num2);
        System.out.println("num1%num2= "+res);             //num1%num2= 0.2
        //进制转换
        String result1 = Integer.toHexString(15);               //十进制转成十六进制:f
        String result2 = Integer.toOctalString(15) ;            //十进制转成八进制:17
        String result3 = Integer.toBinaryString(15);            //十进制转成二进制:1111
        String result4 = Integer.valueOf("10",16).toString();   //十六进制转成十进制:16
        String result5 =Integer.valueOf("17",8).toString();     //八进制转成十进制:15
        String result6 = Integer.valueOf("0101",2).toString();  //二进制转十进制:5
        System.out.println("十进制转成十六进制:"+result1);
        System.out.println("十进制转成八进制:"+result2);
        System.out.println("十进制转成二进制:"+result3);
        System.out.println("十六进制转成十进制:"+result4);
        System.out.println("八进制转成十进制:"+result5);
        System.out.println("二进制转十进制:"+result6);
    }
}

接下来请看:Java基础常见面试题——HashMap总结
https://blog.csdn.net/qq_41822345/article/details/104436909

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的程序猿~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值