Java面试官常问部分面试题(2021)

一:java基础

  1. 面向对象的三大特征

    封装、继承、多态

  2. 重载和重写的区别

①重载发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。

②方法的重写要遵循“两同两小一大”

  • 两同”即方法名相同、形参列表相同;

  • “两小”指的是子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;

  • “一大”指的是子类方法的访问权限应比父类方法的访问权限更大或相等。

  1. java为什么只有值传递

对于基本类型,是值的拷贝,对于引用类型,是引用地址值的拷贝,它可以改变方法参数的状态

  1. ==、equals和hashcode

基本数据类型比较的是值,引用数据类型比较的是内存地址,equals重写了比较的是值,没有重写类似于==。

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int
整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在 JDK 的
Object.java 中,这就意味着 Java 中的任何类都包含有 hashCode()
函数。(hashSet的不可重复说明为什么要有hashCode)

  1. String 、StringBuffer 和 StringBuilder 的区别? String 不可变性?

① 可变性:String底层是final修饰的char数组,不可变,而stringBuffer和stringBuilder不是final修饰

②线程安全性:string是不可变的,类似于常量,线程安全,stringBuffer对方法加了同步锁,是线程安全的,stringBulider没有,是不安全的

③性能:每次string类型变化都会有新对象产生,stringBuffer和stringBuilder在原有对象上进行操作

  1. 反射机制以及应用场景

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为
java 语言的反射机制。

①. 我们在使用 JDBC
连接数据库时使用 Class.forName()通过反射加载数据库的驱动程序;

②. Spring 框架的 IOC(动态加载管理 Bean)创建对象以及
AOP(动态代理)功能都和反射有联系;

  1. 创建线程有哪几种方式?

①. 继承Thread类创建线程类

  • 定义Thread类的子类,并重写该类的run方法

  • 创建Thread子类的实例,即创建了线程对象。

  • 调用线程对象的start()方法来启动该线程。

②. 通过Runnable接口创建线程类

  • 定义runnable接口的实现类,并重写该接口的run()方法

  • 创建Thread对象,把 Runnable实现类的实例作为Thread的target

  • 调用线程对象的start()方法来启动该线程。

8.synchronized 和 ReentrantLock 区别是什么?

synchronized是关键字,ReentrantLock是类,可以被继承、可以有方法、可以有各种各样的类变量

  • ReentrantLock可以对获取锁的等待时间进行设置,避免了死锁

  • ReentrantLock可以获取各种锁的信息

  • ReentrantLock可以灵活地实现多路通知

  • ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark
    word。

  1. 线程的生命周期

在这里插入图片描述

  1. 如何避免线程死锁

①. 破坏互斥条件 :这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。

②. 破坏请求与保持条件 :一次性申请所有的资源。

③. 破坏不剥夺条件 :占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。

④. 破坏循环等待条件 :靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。

  1. BIO、NIO、AIO的区别

BIO:同步阻塞式 IO,平常使用的传统
IO,特点是模式简单、使用方便,并发处理能力低。

NIO:同步非阻塞 IO,是传统 IO
的升级,三个核心组件:Buffer、Channel和Selector,客户端和服务器端通过
Channel(通道)通讯,实现了多路复用。

AIO:异步非堵塞 IO ,是 NIO 的升级,异步 IO 的操作基于事件和回调机制。

  1. List、Set、Map的区别及其子类

在这里插入图片描述

  1. HashMap和HashTable的区别是什么?
  • hashMap去掉了HashTable
    的contains方法,但是加上了containsValue()和containsKey()方法。

  • hashTable是同步的、线程安全的,而HashMap是非同步的,效率上比hashTable要高。

  • hashMap允许空键值,而hashTable不允许。

  1. HashMap的底层实现

JDK1.8 之前 HashMap
底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就放入链表中。

jdk1.8在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。

  1. ConcurrentHashMap为什么线程安全?

Java8 中的 ConcruuentHashMap 使用的 Synchronized 锁加 CAS 的机制。结构也由 Java7
中的 Segment 数组 + HashEntry 数组 + 链表 进化成了 Node 数组 + 链表 /
红黑树
,Node 是类似于一个 HashEntry
的结构。它的冲突再达到一定大小时会转化成红黑树,在冲突小于一定数量时又退回链表。

  1. sleep和wait方法的区别

sleep()方法是线程类的静态方法,让调用线程进入睡眠状态,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。

wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程。

  1. synchronize的底层实现

synchronized 同步语句块的实现使用的是 monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。

synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法。

synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。

Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:

  • 普通同步方法,锁是当前实例对象

  • 静态同步方法,锁是当前类的class对象

  • 同步方法块,锁是括号里面的对象

  1. synchronize和volatile的区别
  • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;
    synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。

  • volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。

  • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。

  • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

二:Redis

1、Redis和Memcached的区别

  • memcached所有的值均是简单的字符串,redis支持更为丰富的数据类型有string、list、hash、set、zset。

  • redis的速度比memcache快很多

  • redis可以持久化其数据

  • Memcached 是多线程,非阻塞 IO 复用模型;Redis 使用单线程的多路 IO 复用模型。

2、Redis常见数据类型使用场景

String:用户的访问次数、文章的点赞数

List:消息队列

hash:对象数据存储

set:需要存放不能重复的数据

三:Spring框架

1、spring的IOC和AOP

IoC(控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IoC
容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map,Map
中存放的是各种对象。IoC
容器就像是一个工厂一样**,**当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的

AOP(面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来**,便于减少系统的重复代码降低模块间的耦合度并有利于未来的可拓展性和可维护性。**

Spring AOP就是基于动态代理的

JDK
动态代理类使用步骤

(1) 定义一个接口及其实现类;

(2)自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;

(3) 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[]
interfaces,InvocationHandler h) 方法创建代理对象;

CGLIB
动态代理类使用步骤

(1) 定义一个类;

(2) 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和
JDK 动态代理中的 invoke 方法类似;

(3) 通过 Enhancer 类的 create()创建代理类;

2、spring的bean是否线程安全

通常来说是不安全的!bean的scope属性可以配置bean是单例singleton每个容器中只有一个bean还是prototype每次请求都new一个bean,如果每次请求都返回新的bean的话就是安全的,但是通常情况下,绝大多数bean都是单例bean。

3、spring的bean的生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QzBnlZYh-1614159017739)(media/539a40a6c77eba95a23146dcd39fd28a.jpg)]

4、SpringMVC的工作原理

① 用户向服务器发送请求,请求被Spring 前端控制DispatcherServlet捕获;

② DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象,最后以HandlerExecutionChain对象的形式返回;

③. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter;

④. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。

⑤. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;

⑥. 根据返回的ModelAndView,选择一个适合的ViewResolver返回给DispatcherServlet

⑦. ViewResolver 结合Model和View,来渲染视图;

⑧. 将渲染结果返回给客户端。

5、springBoot的核心注解原理(启动原理)

SpringBoot是一个服务于框架的框架,服务范围是简化配置文件

@SpringBootApplication是由@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解组成。

(2)@SpringBootConfiguration:内部源码提供的是@Configuration,是IOC容器的配置类

(3)@EnableAutoConfiguration:内部借助SpringFactoriesLoader从classpath中搜寻所有META-INF/spring.fatories文件,并将其中Key[org.springframework.boot.autoconfigure.EnableAutoConfiguration]对应的Value配置项通过反射的方式实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总到当前使用的IoC容器中。

(4)@CompenentScan:不是必须的,它的功能就是自动扫描并加载组件或bean定义,将他们加载到容器中。

6、SpringCloud

①. 服务发现——Netflix Eureka,远程调用服务:Feigin

由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。。

②. 客服端负载均衡——Netflix Ribbon

Ribbon,主要提供客户侧的软件负载均衡算法。Ribbon客户端组件提供一系列完善的配置选项,比如连接超时、重试、重试算法等。Ribbon内置可插拔、可定制的负载均衡组件。

③. 断路器——Netflix Hystrix

断路器可以防止一个应用程序多次试图执行一个操作,即很可能失败,允许它继续而不等待故障恢复或者浪费
CPU
周期,而它确定该故障是持久的。断路器模式也使应用程序能够检测故障是否已经解决。如果问题似乎已经得到纠正,应用程序可以尝试调用操作。

④. 服务网关——Netflix Zuul

类似nginx,反向代理的功能,不过netflix自己增加了一些配合其他组件的特性。

⑤. 分布式配置——Spring Cloud Config

这个还是静态的,得配合Spring Cloud Bus实现动态的配置更新。

四:mysql

  1. mysql事务和隔离级别
  • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

  • READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

  • REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生

  • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读

  • 脏读(Dirty
    read):
    当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

  • 不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

  • 幻读(Phantom
    read):
    幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

  1. mysql索引结构

(1). MyISAM索引实现

MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址,如果指定的Key存在,则取出其data域的地址值,读取相应数据记录。MyISAM引擎的索引文件和数据文件是分离的。主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。MyISAM的索引方式也叫做“非聚集”索引。

(2). InnoDB索引实现

InnoDB也使用B+Tree作为索引结构

区别一:

InnoDB的数据文件本身就是索引文件,树的叶节点data域保存的是完整的数据记录。索引的key是数据表的主键,主索引表就是数据文件本身。

区别二:

InnoDB的辅助索引引用主键作为data域。InnoDB索引叫做聚集索引。

3、MyISAM和InnoDB的区别

(1). 是否支持行级锁 : MyISAM 只有表级锁,而InnoDB
支持行级锁和表级锁,默认为行级锁。

(2). 是否支持事务和崩溃后的安全恢复:
MyISAM
强调的是性能,每次查询具有原子性,其执行速度比InnoDB类型更快,但是不提供事务支持。但是InnoDB 提供事务支持,外部键等高级数据库功能。
具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery
capabilities)的事务安全(transaction-safe (ACID compliant))型表。

(3). 是否支持外键: MyISAM不支持,而InnoDB支持。

五:设计模式

1、单例模式

饿汉式:

 public class Singleton {
    
    

// 1、直接创建对象

public static Singleton instance = new Singleton();

///2、私有化构造函数

private Singleton() {
    
    

}

// 3、返回对象实例

public static Singleton getInstance() {
    
    

return instance;

}

懒汉式:

 public class Singleton {
    
    

// 声明变量

private static volatile Singleton singleton = null;

// 私有构造函数

private Singleton() {
    
    

}

// 提供对外方法

public static Singleton getInstance() {
    
    

if (singleton == null) {
    
    

synchronized (Singleton.class) {
    
    

if (singleton == null) {
    
    

singleton = new Singleton();

}

}

}

return singleton;

}

2、装饰模式(Decorator)

要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。

public interface Sourceable {
    
    

public void method();

}

public class Source implements Sourceable {
    
    

\@Override

public void method() {
    
    

System.out.println("the original method!");

}

}

public class Decorator implements Sourceable {
    
    

private Sourceable source;

public Decorator(Sourceable source) {
    
    

super();

this.source = source;

}

\@Override

public void method() {
    
    

System.out.println("before decorator!");

source.method();

System.out.println("after decorator!");

}

}

public class DecoratorTest {
    
    

public static void main(String[] args) {
    
    

Sourceable source = new Source();

Sourceable obj = new Decorator(source);

obj.method();

}

}

猜你喜欢

转载自blog.csdn.net/hcyxsh/article/details/114030267