Java面试基础篇详解

1Java 基础知识
面向对象
→ 什么是面向对象
面向对象、面向过程 略
面向对象的三大基本特征和五大基本原则
答java是一个面向对象的语言。封装、继承、多态是面向对象的三个特征。
五大基本原则分别是:单一职责(同一件事用同一个类,用参数来区分细节)、开放封闭(一旦开发好一个功能即能独立运转,新的功能随时能追加,但与之无关)、替换(动态绑定不影响调用者功能)、依赖倒置(接口和实现分离,调用者声明只用接口)、接口隔离(避免胖接口,JDK8的Defult就在缓解胖接口问题)

→ 平台无关性
Java 如何实现的平台无关 jvm
JVM 还支持哪些语言(Kotlin、Groovy、JRuby、Jython、Scala)

→ 值传递
值传递、引用传递
为什么说 Java 中只有值传递

→ 封装、继承、多态
什么是多态、方法重写与重载略
Java 的继承与实现略
构造函数与默认构造函数略
类变量、成员变量和局部变量略
成员变量和方法作用域略

→ 基本数据类型
8 种基本数据类型:byte、short、int、long 、float、double 、Boolean、char
整型中 byte 、short、int、long 的取值范围
byte 8位( (-2^7)- (2^7-1)) 、short((-2^15)- (2^15 - 1))、int( -(-231)-(231 - 1))、long (-263-263 -1)

→ 自动拆装箱
什么是包装类型、什么是基本类型、什么是自动拆装箱

→ String
字符串的不可变性
java8 中 substring 的原理
image.png
首先调用new String(value, beginIndex, subLen)方法;上面的代码估计大家都能看懂也没什么难度,image.png
new String 方法如下 我们主要看最后一行,this.value = Arrays.copyOfRange(value, offset, offset+count); subString是调用数组的copy方法,在跟进我们会看到
image.png
调用了系统最终的copy方法是一个本地方法;
replaceFirst、replaceAll、replace 区别、
replaceAll、replace的区别
相同点:都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串;
不同点:replaceAll支持正则表达式,因此会对参数进行解析(两个参数均是),如replaceAll("\d", “"),而replace则不会,replace("\d","”)就是替换"\d"的字符串,而不会解析为正则。
如果想要只替换第一次出现的地方replaceFirst
String.valueOf 和 Integer.toString 的区别、
String.valueOf调用的也是Integer.toString方法
switch 对 String 的支持
字符串池、常量池(运行时常量池、Class 常量池)、intern

→ 熟悉 Java 中各种关键字
transient、instanceof、final、static、volatile、synchronized、const 原理及用法
我先说说用法 原理后续补充
transient 被该字段修饰的变量不会被序列化
instanceof 判断一个对象是否是另一个对象的子类
final 可以声明成员变量、方法、类以及本地变量。一旦你将引用声明作final,你将不能改变这个引用了
static 如果某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量。
volatile 防止jvm重排 是可见性的保证 常在并发程序中修饰变量 结合synchronized和cas一起使用
synchronized对对象进行加锁,在JVM中,对象在内存中分为三块区域:对象头、实例数据和对齐填充。在对象头中保存了锁标志位和指向monitor对象的起始地址 synchronized应用在方法上时,在字节码中是通过方法的ACC_SYNCHRONIZED标志来实现的,synchronized应用在同步块上时,在字节码中是通过monitorenter和 monitorexit 实现的。
const是java中的预留关键字

→ 集合类
常用集合类的使用、
ArrayList 和 LinkedList 和 Vector 的区别 、
ArrayList 底层实现是数组,便于随机访问 适合查询较多的场景,删除和添加操作会用到底层的copy方法
LinkedList 底层实现是链表,便于添加和删除操作,不适用于查询较多的场景
Vector 和ArrayList 一样实现也是动态数组,Vector 是线程安全的 ArrayList 是线程不安全的
SynchronizedList 和 Vector 的区别、
SynchronizedList有很好的扩展和兼容功能。他可以将所有的List的子类转成线程安全的类。 2.使用SynchronizedList的时候,进行遍历时要手动进行同步处理。 3.SynchronizedList可以指定锁定的对象
4他们俩之间的扩容机制不一样
HashMap、HashTable、ConcurrentHashMap 区别、
HashTable底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
HashMap
底层数组+链表实现,可以存储null键和null值,线程不安全
初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
计算index方法:index = hash & (tab.length – 1)
ConcurrentHashMap1.7
底层采用分段的数组+链表实现,线程安全
通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容
Set 和 List 区别?略Set 如何保证元素不重复?
HashSet中add()中 map.put(e, PRESENT)==null 为false,HashSet添加元素失败。因此,如果向HashSet中添加一个已经存在的元素,新添加的集合元素不会覆盖原来已有的集合元素。
Java 8 中 stream 相关用法、
常用于集合操作 常见的比如集合过滤 分组求和 分组排序 结合Lambda 表达式一起用
apache 集合处理工具类的使用、
组件 功能介绍
BeanUtils 提供了对于JavaBean进行各种操作,克隆对象,属性等等.常用
Betwixt XML与Java对象之间相互转换.
Codec 处理常用的编码方法的工具类包 例如DES、SHA1、MD5、Base64等.常用
Collections java集合框架操作.常用
Compress java提供文件打包 压缩类库.常用
Configuration 一个java应用程序的配置管理类库.
DBCP 提供数据库连接池服务.
DbUtils 提供对jdbc 的操作封装来简化数据查询和记录读取操作.
Email java发送邮件 对javamail的封装.常用
FileUpload 提供文件上传功能.常用
HttpClien 提供HTTP客户端与服务器的各种通讯操作. 现在已改成HttpComponents
IO io工具的封装.
Lang Java基本对象方法的工具类包 如:StringUtils,ArrayUtils等等.
Logging 提供的是一个Java 的日志接口.
Validator 提供了客户端和服务器端的数据验证框架.
不同版本的 JDK 中 HashMap 的实现的区别以及原因
JDK8将数据的存储方式,由数组链表形式,优化为当链表长度大于8的时候,链表形式变为红黑树形式,复杂度由O(n)降至O(logn),提高了查询效率,性能得到了提升
Collection 和 Collections 区别
java.util.Collection 是一个集合接口(集合类的一个顶级接口)
Collections 是集合操作工具类
Arrays.asList 获得的 List 使用时需要注意什么
Arrays.asList()方法不能使用基本类型数组作为参数,只能使用相应的包装类型数组。
fail-fast 和 fail-safe
参考一下这篇博文[https://www.cnblogs.com/shamo89/p/6685216.html]
CopyOnWriteArrayList、ConcurrentSkipListMap
CopyOnWriteArrayList比较适合读多写少,数据量比较小,但是并发非常高的场景。
ConcurrentSkipListMap并发条件下实现有序的map

→ 枚举
枚举的用法、枚举的实现、枚举与单例、Enum 类
Java 枚举如何比较
switch 对枚举的支持
枚举的序列化如何实现
枚举的线程安全性问题
当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的。所以,创建一个enum类型是线程安全的。(都是用static修饰的)

→ IO
字符流、字节流、输入流、输出流、
常用的字节输入流主要有:
InputStream
FileInputStream
BufferedInputStream
常用的字节输出流主要有:
OutputStream
FileOutputStream
BufferedOutputStream
常见的字符输入流有:
Reader
InputStreamReader
FileReader
BufferedReader
常见的字符输出流有:
Writer
OutputStreamWriter
FileWriter
BufferedWriter
同步、异步、阻塞、非阻塞、
Linux 5 种 IO 模型
BIO、NIO 和 AIO 的区别、三种 IO 的用法与原理、netty
BIO(blocking IO):同步阻塞 I/O例如:我要去饭堂吃饭,这时饭堂的人很多,我就得排队买饭,排队的时间被浪费了,
NIO(nonblocking IO):同步非阻塞 I/O
用户进程只有在第二个阶段被阻塞了,而第一个阶段没有阻塞,但是在第一个阶段中,用户进程需要盲等,不停的去轮询内核,看数据是否准备好了。
例如:我要去饭堂吃饭,这时饭堂的人很多,一般来说我需要排队买饭,但我们饭堂的管理最近变的比较人性化,你点完饭后,会给你一个号码,但饭堂噪声很大,我不得不频繁的询问我的饭是否做好了,但是我可以利用之前排队的时间去买瓶饮料喝!
多路复用IO( IO multiplexing)
从上图可以看到在I/O复用模型中,由于同步非阻塞方式需要不断主动轮询,轮询占据了很大一部分过程,轮询会消耗大量的CPU时间,而 “后台” 可能有多个任务在同时进行,
如果循环查询多个任务的完成状态,只要有任何一个任务完成,就去处理它。轮询不是进程的用户态。这时 “IO 多路复用”就出现了。即UNIX/Linux 的 select、poll、epoll,
IO多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。
从整个IO过程来看,他们都是顺序执行的,因此可以归为同步模型(synchronous)。都是进程主动等待且向内核检查状态
原文链接:https://blog.csdn.net/baiye_xing/article/details/74331041
信号驱动I/O( signal driven IO)
只有在I/O执行的第二阶段阻塞了用户进程,而在第一阶段是没有阻塞的。该模型在I/O执行的第一阶段,当数据准备完成之后,会主动的通知用户进程数据已经准备完成,即对用户进程做一个回调。该通知分为两种,一为水平触发,即如果用户进程不响应则会一直发送通知,二为边缘触发,即只通知一次。
异步 I/O(asynchronous IO)aio
从上图可以看出,在该模型中,当用户进程发起系统调用后,立刻就可以开始去做其它的事情,然后直到I/O执行的两个阶段都完成之后,内核会给用户进程发送通知,告诉用户进程操作已经完成了。
netty 为什么Netty使用NIO而不是AIO?
Netty AIO的底层实现仍使用EPOLL,没有很好实现AIO,因此在性能上没有明显的优势,而且被JDK封装了一层不容易深度优化
Netty整体架构是reactor模型, 而AIO是proactor模型, 混合在一起会非常混乱,把AIO也改造成reactor模型看起来是把epoll绕个弯又绕回来
AIO还有个缺点是接收数据需要预先分配缓存, 而不是NIO那种需要接收时才需要分配缓存, 所以对连接数量非常大但流量小的情况, 内存浪费很多

→ 反射
反射与工厂模式、反射有什么用
使用反射机制修改工厂模式 在不改变原始类的情况下增加新的工能
Class 类、java.lang.reflect.*

→ 动态代理
静态代理、动态代理
动态代理和反射的关系
动态代理的几种实现方式jdk cglib
AOP jdk cglib两种实现方式java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

→ 序列化
什么是序列化与反序列化、
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
为什么序列化、
当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
当你想用套接字在网络上传送对象的时候;
当你想通过RMI传输对象的时候;
序列化底层原理、
ObjectOutputStream ObjectInputStream 完成对象的序列化和反序列化
序列化与单例模式、
序列化会通过反射调用无参数的构造方法创建一个新的对象。
只要在Singleton类中定义readResolve就可以解决该问题:
protobuf、
类似json xml 是数据交互的一种形式
为什么说序列化并不安全
序列化可以使一些重要字段暴露 ,而且反序列化的时候还可以修改导致类发生改变

→ 注解
元注解、
Target注解的作用是:描述注解的使用范围(即:被修饰的注解可以用在什么地方) 。
eteniton注解的作用是:描述注解保留的时间范围(即:被描述的注解在它所修饰的类中可以被保留到何时) 。
Documented注解的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息。
Inherited注解的作用是:使被它修饰的注解具有继承性(如果某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解)。
自定义注解、略
Java 中常用注解使用、略
注解与反射的结合
image.png
这是一个案例
Spring 常用注解略

→ JMS
什么是 Java 消息服务、
jms
JMS 消息传送模型
1 点对点消息模型(p2p)
点对点消息模型既支持 异步“即发即弃”的消息传送方式,也支持同步的“请求响应”的消息传送方式。
点对点消息模型的特点:
• 消息通过一个名为消息队列的虚拟通道来交换消息。队列即是消息生产者发送消息的目的地,也是消息消费者获取消息的消息源。
• 每一条消息只能传送给一个接受者,可能会有多个接收者在一个队列侦听,但是每个消息队列中的消息只能被一个接受者所消费
• 消息队列中的消息是由先后顺序的。先进入队列的会优先被消费,除非使用了消息优先级。
• 消费者和生产者之间没有耦合。消费者和生产者可以在运行时动态的添加,这使得系统的发杂性可以随着时间的增长而降低。
发布订阅消息模型
2 发布订阅消息的特点:
· 信息通过一个成为主题(topic)的虚拟通道交换
· 每条消息都会传送给多个称为订阅者的消费者。订阅者有许多类型,包括持久订阅者、非持久订阅者、动态订阅者。
· 发布者通常不会意识到有多少个订阅者在接收主题消息
· 消息被推送给消费者,这意味着消息会传给消费者,而无需消费者去请求。
· 生产者和消费者之间没有耦合,订阅者和发布者可以动态的添加。
· 订阅一个主题的每个客户端都会受到发布该主题的副本。发布者生产的一条消息可以被复制并分发给成千上万的订阅者

→ JMX
java.lang.management.、 javax.management.
JMX最常见的场景是监控Java程序的基本信息和运行情况,任何Java程序都可以开启JMX,然后使用JConsole或Visual VM进行预览。

→ 泛型
泛型与继承、类型擦除、泛型中 KTVE? object 等的含义、泛型各种用法
泛型与继承、类型擦除
父类为泛型子类集成父类的时候父类擦除对应的泛型子类按需编写
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
List 和 List 在 jvm 中的 Class 都是 List.class。
泛型中 KTVE?
E – Element (在集合中使用,因为集合中存放的是元素)
T – Type(Java 类)
K – Key(键)
V – Value(值)
N – Number(数值类型)
? – 表示不确定的java类型(无限制通配符类型)
Object – 是所有类的根类,任何类的对象都可以设置给该Object引用变量,使用的时候可能需要类型强制转换,但是用使用了泛型T、E等这些标识符后,在实际用之前类型就已经确定了,不需要再进行类型强制转换。
限定通配符和非限定通配符、上下界限定符 extends 和 super
List 和原始类型 List 之间的区别?
List<?> 和 List 之间的区别是什么?
image.png

→ 单元测试
junit、mock、mockito、内存数据库(h2)略
→ 正则表达式
java.lang.util.regex.
→ 常用的 Java 工具库
commons.lang、commons.
…、 guava-libraries、 netty略
→ API & SPI
API、API 和 SPI 的关系和区别
如何定义 SPI、SPI 的实现原理
Java 中区分 API 和 SPI,通俗的讲:API 和 SPI 都是相对的概念,他们的差别只在语义上,API 直接被应用开发人员使用,SPI 被框架扩展人员使用
SPI的全名为Service Provider Interface.大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的。在java.util.ServiceLoader的文档里有比较详细的介绍。简单的总结下java spi机制的思想。我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不使用实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候动态指定具体实现类,这就需要一种服务发现机制。 java spi就是提供这种功能的机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。
java SPI应用场景很广泛,在Java底层和一些框架中都很常用,比如java数据驱动加载和Dubbo。Java底层定义加载接口后,由不同的厂商提供驱动加载的实现方式,当我们需要加载不同的数据库的时候,只需要替换数据库对应的驱动加载jar包,就可以进行使用。
要使用Java SPI,需要遵循如下约定:
1、当服务提供者提供了接口的一种具体实现后,在jar包的META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名;
2、接口实现类所在的jar包放在主程序的classpath中;
3、主程序通过java.util.ServiceLoder动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM;
4、SPI的实现类必须携带一个不带参数的构造方法;
[https://www.cnblogs.com/oskyhg/p/10800051.html]原文链接

→ 异常
异常类型、正确处理异常、自定义异常略
Error 和 Exception
Exception是java程序运行中可预料的异常情况,咱们可以获取到这种异常,并且对这种异常进行业务外的处理。
Error是java程序运行中不可预料的异常情况,这种异常发生以后,会直接导致JVM不可处理或者不可恢复的情况。所以这种异常不可能抓取到,比如OutOfMemoryError、NoClassDefFoundError等。
异常链、try-with-resources
finally 和 return 的执行顺序
return结果存着------>finally------>return返回存的结果
→ 时间处理
时区、冬令时和夏令时、时间戳、Java 中时间 API
格林威治时间、CET,UTC,GMT,CST 几种常见时间的含义和关系
SimpleDateFormat 的线程安全性问题
大概意思就是parse()方法使用calendar来生成返回的Date实例,而每次parse之前,都会先把calendar里的相关属性清除掉。
问题是这个calendar是个全局变量,也就是线程共享的。因此就会出现一个线程刚把calendar设置好,另一个线程把它给清空了,
这时第一个线程再parse的话就会有问题了。
private SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd”);
public Date formatDate(Date d) {
synchronized(sdf) {
return sdf.parse(d);
}
}
也可以使用threadlocal每个线程维护一个SimpleDateFormat
Java 8 中的时间处理
1)提供了javax.time.ZoneId 获取时区。
2)提供了LocalDate和LocalTime类。
3)Java 8 的所有日期和时间API都是不可变类并且线程安全,而现有的Date和Calendar API中的java.util.Date和SimpleDateFormat是非线程安全的。
如何在东八区的计算机上获取美国时间

→ 编码方式
Unicode、有了 Unicode 为啥还需要 UTF-8
GBK、GB2312、GB18030 之间的区别
UTF8、UTF16、UTF32 区别
URL 编解码、Big Endian 和 Little Endian
如何解决乱码问题传参
使用post 或者两次编码解决

→ 语法糖
Java 中语法糖原理、解语法糖
语法糖:switch 支持 String 与枚举、泛型、自动装箱与拆箱、方法变长参数、枚举、内部类、条件编译、 断言、数值字面量、for-each、try-with-resource、Lambda 表达式

发布了2 篇原创文章 · 获赞 0 · 访问量 79

猜你喜欢

转载自blog.csdn.net/weixin_38738049/article/details/105211850
今日推荐