吐血整理!这200道阿里P6必备Java面试题,我简直太爱了

本文汇总了 Java 开发岗的面试重点,涵盖了 Java OOP、集合、泛型、异常处理、IO/NIO、多线程、反射、注解、Spring Boot、MyBatis、Spring Cloud 等多个方面,详细解释了各种概念和面试中常见的问题,旨在帮助开发者全面复习和准备面试。
摘要由CSDN通过智能技术生成

##前言
梳理了好久,总算是把面试题全部导出来了,毕竟还要上班,这次就给大家总结了一些Java开发岗位的经典面试题。

篇幅较大,阅读过程中可能会有点繁琐! 但请细细观看,文章末尾有留给大家的小惊喜!!!

千万不要错过了~ 话不多说,咱们就直接开整!

Java开发岗面试题

JavaOOP

Java的数据结构有哪些?

  • 线性表(ArrayList)
  • 链表(LinkedList)
  • 栈(Stack)
  • 队列(Queue)
  • 图(Map)
  • 树(Tree)

Java中有几种数据类型

四型八种

  • 整形:byte、short、int、long
  • 浮点型:float、double
  • 字符型:char
  • 布尔型:boolean

String str=“aaa”,与String str=new String(“aaa”)一样吗?

  • 不一样,第一个字面量声明字符串,会从常量池里面取,池中没有则创建,有则复用,后面再同样声明一个aaa时,就从池中取出复用。第二个使用new的方式创建,是不会放到常量池中的,所以也不会复用。

String、StringBuffffer 和 StringBuilder 的区别是什么?

  • String是只读字符串,它不是基本数据类型,而是一个对象,它的底层是一个final的char字符数组,一经定义,就不能增加和修改,每次对String的操作都是重新生成一个String字符串对象。
  • StringBuffffer和StringBuilder都继承了AbstractStringBulder类,2个类都是用来进行字符串操作的。
  • StringBuffffer是线程安全的,而StringBuilder是非线程安全的,所以StringBuilder效率比StringBuffffer高,StringBuffffer类的方法大多数都加了synchronized关键字。

抽象类和接口的区别是什么?

  • 抽象类

    • 需要使用abstract关键字定义,它可以有抽象方法和实例方法,抽象方法没有方法体,需要子类实现。
    • 包含抽象方法的类,一定是抽象类
    • 抽象只能被继承,不能被实例化
  • 接口

    • 接口的方法全部都是抽象方法,属性都是常量
    • 接口不能被实例化
    • 接口只能被实现,实现接口的类必须实现所有的抽象方法,除非该类是抽象类,可以选择实现部分抽象方法,剩余了让子类实现
    • 接口可以多继承

有了equals(),为什么还需要hashCode()

  • Java集合有2类,List和Set,List集合有序可重复,而Set集合无序但不可重复。Set集合保证唯一的方法,就是插入时判断对象的equals()方法,是否和已有元素重复,但是元素较多时,调用equals()方法就会很低效。所以增加了hashCode(),通过元素对象的内存地址计算出一个hash值,比较时,先比较hashCode,hashCode的效率非常高,当元素的hashCode相同时,再调用元素的equals()进行比较,这样效率就提升了。

介绍Java的强、弱、软、虚,4种引用

  • 强引用,强引用在内存不足时,宁愿发生OOM也不愿意回收它。
  • 软引用,使用SoftReference包裹引用,内存不足时,就会回收。
  • 弱引用,使用WeakReference包裹引用,只要JVM垃圾回收发现了它,就会回收。
  • 虚引用,回收机制和弱引用差不多,但是它在被回收前,会放入到ReferenceQueue队列中,并且虚引用声明时,必须传ReferenceQueue队列。因为这个机制,大部分用虚引用来做引用销毁前的处理工作。

Java创建对象有几种方式?

有4种:

  • new关键字
  • 通过反射机制
  • 通过clone克隆机制
  • 通过序列化和反序列化机制

浅拷贝和深拷贝的区别是什么?

例如一个对象中有一个List,浅拷贝和深拷贝效果不同。

  • 浅拷贝,只拷贝外层对象,它引用的List并不会拷贝,所以原对象和拷贝对象的List对象是同一个。
  • 深拷贝,外层对象拷贝,它所有引用的对象也拷贝,所以拷贝的对象,它引用的List对象是新的一个。

final、finalize()、finally,它们有什么区别?

  • final
    • final关键字标记的变量为常量
    • final关键字标记的类,不可继承
    • final关键字标记的方法,不可被复写
  • finalize
    • finalize()方法,在Object类上定义,用于对象被回收时,被回调,类似C++中的析构函数,可用于对对象进行销毁前的处理,但由于GC后再进行特殊处理,可能会出现内存溢出的风险,所以不推荐使用。
  • finally
    • finally用于标识代码块,和try配合使用,它在return之前执行,无论try代码块中是否发生异常,finally代码块中的代码必定会执行。

使用JDBC中,如何防止SQL注入

  • 使用PreparedStatement类,而不是使用Statement类。

Java集合、泛型

ArrayList和LinkedList的区别?

  • ArrayList底层使用数组,它的查询使用索引,所以效率高,但是增、删很慢,因为增、删都需要重排数组,例如删除中间的元素,就需要把后面的元素向前挪。
  • LinkedList底层使用链表,增、删元素只需要修改元素的前节点和后节点即可,所以效率高,但查询效率比较差。

HashMap和HashTable的区别

  • 继承关系不同
    • HashMap是继承自AbstractMap类,而Hashtable是继承自Dictionary类。
  • 对null支持不同
    • Hashtable,key和value都不能为null
    • HashMap,key可以为null,但是这样的key只能有一个,而可以多个key的value值为null
  • 线程安全
    • Hashtable是线程安全的,它的每个方法都有synchronized 关键字,所以多线程环境下可以使用它。
    • HashMap是线程不安全的,但它的效率比Hashtable高,加上大部分场景都是单线程,如果在多线程环境下,推荐使用ConcurrentHashMap,因为它使用了分段锁,并不对整个数据进行锁定。

Collection和Collections的不同

  • Collection是集合的父接口,子接口有List、Set。
  • Collections是集合类的工具类,提供了很多对集合操作的静态方法,可对集合进行搜索、排序、以及线程安全包装等。

List、Set、Map,3者的区别

  • List,有序,可重复
  • Set,无序,不可重复
  • Map,无序,键值对存储,Key不可重复,Value可重复

Array和ArrayList有什么区别?

  • Array和ArrayList都是用来存储数据,ArrayList的底层就是使用Array实现的,但它对Array的扩容和功能进行了拓展。

说说List接口和它的实现类

  • List接口是Collection接口的子接口。List接口的实现类都是有序,可重复的。List接口的实现类有ArrayList、Vector和LinkedList。
  • 实现类
    • ArrayList,底层通过数组实现,它的特点是支持索引查找,所以支持对元素的随机访问。缺点是增、删元素时,需要对数组进行复制、移动,代价比较高,所以它适合随机访问,不适合插入和删除。
    • Vector,底层和ArrayList一样是通过数组实现,但它的方法都加了同步锁,所以它可以在多线程环境下访问,避免同一时段对集合并发读写引起不一致性问题,但同步需要性能开销,所以它的效率比ArrayList低。
    • LinkedList,底层使用链表实现,很适合元素的动态插入和删除,但随机访问和遍历效率会比较低,另外它实现了Deque接口,所以拥有操作头元素、尾元素的方法,所以可以用来当做栈和队列使用。

说说Set接口和它的实现类

  • Set接口,也是Collection接口的子接口,Set接口的实现类都是不可重复的。Set接口的实现类有HashSet、TreeSet、LinkedHashSet。Set集合不可重复的特性是通过调用元素的hashCode()进行比较,如果相同,再调用equals()进行比较,都相同,就视为相同,不会添加到集合中。
  • 实现类
    • HashSet。底层通过Hash表实现,不可重复的特性是通过调用元素的hashCode()进行比较,如果相同,再调用equals()进行比较,都相同,就视为相同,不会添加到集合中。
    • TreeSet,底层通过二叉树实现,可对元素进行插入时就排序,它要求插入的元素比较实现Comparable接口,复写compareTo()函数,或者在创建TreeSet时传入自定义Comparator比较器对象,否则会在运行时抛出java.lang.ClassCastException类型的异常。
    • LinkedHashSet,底层是使用LinkedHashMap,但它只使用了Map中的Key的唯一特性,来保证不可重复。

说说Map集合和它的实现类

  • Map接口,专门用来实现键值对操作的集合类接口。它的实现类有HashMap、HashTable、TreeMap和LinkedHashMap。
  • 实现类
    • HashMap,底层使用Hash表实现,它通过元素的hashCode来确定存储的位置,所以有很快的查询速度,但它遍历时的顺序是不确定的。HashMap只允许一个key为null,但可以多个key的value为null。HashMap是非线程安全的,所以多线程环境下,对HashMap进行并发写会出现不一致性问题,可以通过Collections的synchronizedMap()方法对HashMap进行包装,让HashMap具有线程安全的能力,或者使用ConcurrentHashMap。
      • 在JDK1.8之前,HashMap底层是使用Hash表和链表实现,当发生hash冲突时,同一个位置的元素会形成链表存储,但是元素一多时,查询就会变为链表的遍历,效率比较低。
      • 在JDK1.8时,HashMap底层就变成Hash表和链表\红黑树实现,当链表中的元素个数超过8时,链表转换为红黑树,避免遍历,优化了查询效率。
    • HashTable,底层和JDK1.7的HashMap类似,但它的key和value都不能为null,而且Hashtable是线程安全的,它的每个方法都有synchronized 关键字,所以多线程环境下可以使用它。
    • TreeMap,底层是通过二叉树实现,它能在元素添加时,进行排序,它要求元素必须实现Comparable接口,复写compareTo()函数,或者在创建TreeMap时传入自定义Comparator比较器对象,否则会在运行时抛出java.lang.ClassCastException类型的异常。
    • LinkedHashMap,它是HashMap的一个子类,保存了插入顺序,而其他Map实现类是无序的。

什么是泛型?什么是泛型擦除?

  • 泛型可以对类型进行抽象,可以让类型支持不同类型而重用,例如容器类ArrayList,通过泛型,ArrayList可以存储不同的元素,并且泛型后的Array元素是具体类型而不是Object,避免了类型转换的麻烦,而且编译时会报错,避免了类型转换可能发生的类型转换错误。
  • 泛型擦除,因为Java的泛型是通过编译时实现的,生成的Java字节码中是不存在泛型信息的,所以泛型信息,在编译器编译时,会将泛型信息去除,这个过程就是泛型擦除。所以List上附加的泛型信息,在JVM来说是不可见的,在它眼里都是Object类型。

Java异常面试题

Java异常分为哪几种?

  • 编译时异常
  • 运行时异常

介绍一下Java的异常处理机制

  • 捕获异常,使用try-catch-finally
  • 异常抛出,使用throws关键字

如果自定义一个异常

  • 继承一个异常类,运行时异常继承RuntimeException,编译时异常继承Exception。

try-catch-finally,try中有return,finally还执行吗?

  • 执行,finally的执行在return之前,不管try中有没有异常,都会执行。另外如果finally中有return,则会在try的return之前执行,那么try中的return就执行不到了。

Excption与Error的关系

  • Excption与Error都是Throwable的子类。
  • Excption有运行时异常和编译时异常,他们都是可以捕获和处理。
    • 编译时异常常见有:IOException、FileNotFoundException、SQLException,必须在代码中处理,否则编译会报错。
    • 运行时异常常见有:ClassCastException、IndexOutOfBoundsException、NullPointerException
  • Error,和运行时异常一样,编译器也不会对错误进行检查。当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误。程序本身无法修复这些错误的。常见子类有OutOfMemoryError

Java中的IO和NIO面试题

Java的IO流分为几种

  • 按流的流向分,可以分为输入流和输出流
  • 按操作的单元分,可以分为字节流和字符流
  • 按照流的角色分,可以分为节点流和处理流

Java IO流中40多个类,都是从以下4个抽象基类中派生出来的:

  • InputStream\Reader,所有输入流的基类,InputStream为字符输入流,Reader为字符输入流。
  • OutputStream\Writer,所有输出流的基类,OutputStream为字节输出流,Writer为字符输出流。

Java中IO和NIO的区别?

  • NIO被称为New IO,在JDK1.4中引入,NIO和IO有相同的目的和作用,但实现方式不同。NIO主要用到的是块,而IO是字节Byte,所以NIO的效率要比IO高很多。Java提供了2套NIO,一套针对文件,另一套针对网络编程。

常用io类有哪些?

  • 字节
    • FileInputSteam、FileOutputStream
    • BufferInputStream、BufferedOutputSream
  • 字符
    • FileReader、FileWriter
    • BufferReader、BufferedWriter
  • 对象序列化
    • ObjectInputStream、ObjectOutputSream

什么是Java NIO

  • NIO 主要有三大核心部分: Channel(通道), Buffer(缓冲区), Selector。
  • 传统 IO 基于字节流和字符流进行操作, 而 NIO 基于 Channel 和 Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。 Selector(选择区)用于监听多个通道的事件(比 如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。
  • NIO 和传统 IO 之间第一个最大的区别是, IO 是面向流的, NIO 是 面向缓冲区的。

什么是NIO的Channel

  • Channel,一般翻译为通道。 Channel 和 IO 中的 Stream(流)是差不多一个等级的。 只不过 Stream 是单向的,譬如: InputStream, OutputStream, 而 Channel 是双向的,既可以用来进行读操作,又可以用来进行写操作。
  • NIO 中的 Channel 的主要实现类
    • FileChannel(文件操作)
    • DatagramChannel(UDP操作)
    • SocketChannel(TCP客户端)
    • ServerSocketChannel(TCP服务端)

什么是NIO的Buffer

  • Buffer,故名思意, 缓冲区,实际上是一个容器,是一个连续数组。 Channel 提供从文件、网络读取数据的渠道,但是读取或写入的数据 都必须经由 Buffer。
  • 从一个客户端向服务端发送数据,然后服务端接收数据的过程。客户端发送数据时,必须先将数据存入 Buffer 中,然后将 Buffer 中的内容写入通道。服务端这边接收数据必须通过 Channel 将数据读入到 Buffer 中,然后再从 Buffer 中取出数据来处理。
  • 在 NIO 中, Buffer 是一个顶层父类,它是一个抽象类,常用的 Buffer 的子类有
    • ByteBuffer
    • ShortBuffer
    • IntBuffer
    • LongBuffer
    • FloatBuffer
    • Double
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大老二在不在

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

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

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

打赏作者

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

抵扣说明:

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

余额充值