JAVA面试题

介绍一下list和map

java集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。list是继承自Collection接口的(线性列表的存储方式,长度课动态改变),而Map则是一种容器(key—value对的存储方式,长度课动态改变)

list

List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。

List 接口存储一组不唯一,有序(插入顺序)的对象。

实现类

AbstractList 
继承于AbstractCollection 并且实现了大部分List接口。

ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。

ArrayList 继承了 AbstractList ,并实现了 List 接口。

链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。 

与 ArrayList 相比,LinkedList 的增加和删除的操作效率更高,而查找和修改的操作效率较低。

Map

Map 接口存储一组键值对象,提供key(键)到value(值)的映射

实现类

HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。

HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。

HashMap 是无序的,即不会记录插入的顺序。

HashTable是线程安全,低效,不支持null值和null键

TreeMap 类中不允许键对象为 null 或是 基本数据类型,这是因为 TreeMap 中的对象必须是可排序的(即对象需要实现 java.lang.Comparable 接口) 

java8新特性

lanbda表达式: Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。

方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

默认方法:默认方法就是一个在接口里面有了一个实现的方法。

Stream:把真正的函数式编程风格引入到Java中。

新的日期时间APIDate Time API − 加强对日期与时间的处理。


线程的使用和创建

继承Thread类,重写run方法,创建线程对象,调用现成的start方法

实现Runnable接口,重写run()方法,创建Runnable实现类的实例,将此对象作为参数传递到Thread类中的构造器中,创建Thread类的对象,通过Thread类的独享调用start()

实现Callable接口,实现call()方法,创建Callable接口实现类的对象,将此对象作为传递到Future Task构造器中,创建Thread对象并调用start()

线程池,创建一个类实现Runable或实现Callable,实现类中重写run()或call(),提供指定的线程池,创建实现类的对象,执行指定的线程操作,关闭线程

线程锁

Synchronized

  1. 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁
  2. 开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁.
  3. 实现轻量级锁的时候大概率用到的自旋锁策略
  4. 不公平,可重入,非读写锁

Lock(读写锁)

Java 标准库提供ReentrantReadWriteLock 类, 实现了读写锁。

ReentrantReadWriteLock.ReadLock 类表示一个读锁. 这个对象提供了 lock / unlock 方法进行加锁解锁。
ReentrantReadWriteLock.WriteLock 类表示一个写锁. 这个对象也提供了 lock / unlock 方法进行加锁解锁。

读加锁和读加锁之间, 不互斥;
写加锁和写加锁之间, 互斥;
读加锁和写加锁之间, 互斥;

只要是涉及到 “互斥”, 就会产生线程的挂起等待. 一旦线程挂起, 再次被唤醒就不知道隔了多久了,因此尽可能减少 “互斥” 的机会, 就是提高效率的重要途径

读写锁更适合于“频繁锁,不频繁写”的场景中

sleep和wait的区别

来自不同的类
sleep()是线程类Thread中的静态方法
wait()是Object的成员方法

线程冻结方式不同
sleep()必须设置冻结的时间,时间到了自动苏醒
wait()可以设置冻结时间,也可以不设置,等待nitify()或者notifyAll()来唤醒

使用场景不同
sleep()可以在任何地方使用
wait()只能在同步控制块或同步语句块中使用

对锁的处理机制不同
sleep()暂停的时候不会释放掉锁
wait()会释放锁,等待唤醒或者自动苏醒

异常的捕获不同
sleep()必须捕获异常,在sleep过程中如果有其他对象调用interrupt()会产生InterruptedException异常
wait()是不需要捕获异常的

乐观锁和悲观锁

  • 悲观锁:
    总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
  • 乐观锁:
    假设数据一般情况下不会产生并发冲突,所以在数据进行提交更新的时候,才会正式对数据是否产生并发冲突进行检测,如果发现并发冲突了,则让返回用户错误的信息,让用户决定如何去做。

死锁

死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。

死锁产生的四个必要条件:

互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。

当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。

最容易破坏的死锁就是循环等待

破坏循环等待

最常用的一种死锁阻止技术就是锁排序,假设有N个线程尝试获取M把锁,就可以针对M把锁进行编号(1,2,3...M),N个线程尝试获取锁的时候,都按照固定的按编号由小到大顺序来获取锁,可以避免环路等待


mysql的优化方式

设置索引,优点查询快,缺点表行数据的变化,会自动维护,使DML操作变慢,占用磁盘空间

尽量把字段设置为NOT NULL,这样在将来执行查询的时候,数据库就不用去比较NULL值

对于某些文本字段来说,例如“省份”或者“性别”,我们可以将他们定义为ENUM(枚举)类型。因为在MySQL中,ENUM类型被当做数值型数据来处理,而数值型数据被处理起来的速度要比文本类型要快得多。这样我们又可以提高数据库的性能。

使用链接(JOIN)来代替子查询(Sub-Queries)

使用联合(UNION)来带提手动创建的临时表。MySQL从4.0版本开始支持union查询,他可以把需要使用临时表的两条或更多的select查询合在一个查询中。在客户端查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用union来创建查询的时候,我们只需要用union作为关键字把多个select语句连接起来就可以了,要注意的是所有select语句中的字段数目要相同。
 


索引都有什么

单列索引

一个索引只包含单个列,一个表中可以由多个索引

普通索引

基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点。

唯一索引

索引列中的值必须使唯一的,但是允许为空值

主键索引

使一种特殊的唯一索引,不允许为空值

组合索引

在表中的多个字段组合上创建的索引,只有在查询条件中使用了这些字段的左边字段,索引才会被使用,使用索引使遵循最左前缀集合。

全文索引

只有在mylSAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT类型字段上使用全文索引,是在一堆文字中找到某个关键字,就能找到该字段的所属记录行

空间索引

空间索引使对空间数据类型的字段建立的索引,MySQL中的空间数据类型由四种,GEOMETRY、POINT、LINESTRING、POLYGON。在创建空间索引时,使用SPATIAL关键字。要求,引擎为MyISAM,创建空间索引的列,必须将其声明为NOT NULL。可能跟游戏开发有关。


更改项目的启动顺序

Mybatis原理是什么?

MyBatis 的原理就是通过配置文件或注解定义 SQL 映射关系,使用动态代理生成 Mapper 接口的实现类,通过 Executor 执行 SQL 语句,并将结果返回给应用程序。这样就实现了对数据库的操作和数据映射,简化了数据持久化的开发过程。

怎么查看mybatis进程?

jvm内存结构?

java虚拟机在执行java程序的过程中会把它管理的内存划分为若干个不同的数据区域,每个区域都有各自的作用。

分析JVM内存结构,主要就是分析JVM运行时数据存储区域。JVM运行时数据区主要包括:堆、栈、方法区、程序计数器等。而JVM的优化问题主要在线程共享的数据区中:堆、方法区。

程序计数器

是一块较小的内存空间,可以看作是当前线程所执行字节码的行号指示器,指向下一个要执行的指令代码,由执行引擎来读取下一条指令。更确切的说:一个线程的执行,是通过字节码解释器改变线程的计数器的值,来获取下一条需要执行的字节码指令,从而确保线程的正确执行。

JVM中的栈包括JAVA虚拟机栈本地方法栈,两者的区别就是,JAVA虚拟机栈为JVM执行Java方法服务,本地方法去栈则为JVM使用到的Native方法服务,两者作用是极其相似的。

什么是栈?

限定仅在表头进行插入和删除操作的线性表。即压栈(入栈)和弹栈(出战)都是对栈顶元素进行操作的。所以栈式先进后出的

栈式线程私有的,他的生命周期与线程相同。每个线程都会分配一个的空间,即每个线程拥有独立的栈空间。

什么是堆?

堆是java虚拟机锁管理的内存中最大的一块存储区域。堆内存被所有线程共享。主要存放使用new关键字创建的对象。所有对象实例以及数组都要在堆上分配,垃圾收集器就是根据GC算法,收集堆上对象所占用的内存空间(收集的是对象占用的空间而不是对象本身)

方法区

方法区和堆一样是被所有线程共享的区间,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码。更具体的说,静态变量+常量+类信息(版本、方法、字段等)+运行时常量池存在方法区中。常量池是方法区的一部分。

JDK1.8 使用元空间 MetaSpace 替代方法区,元空间并不在 JVM中,而是使用本地内存。

常量池中存储编译器生成的各种字面量和符合引用,字面量就是java中常量的意思。比如文本字符串,final修饰的常量等。方法引用则包括类和接口的全限定名,方法名和描述符,字段名和描述符等。

nacos原理是什么?

你如何理解Spring的约定大于配置

约定大于配置,也称作按约定编程,是一种软件设计范式,旨在减少软件开发人员需要做出决定的数量,活的简单的好处,而又不失灵活性。

如果您所用工具的约定与你的期望相符,便可省去配置;反之,你可以配置来达到你所期待的方式。

约定大于配置,并不是零配置或者完全没有配置,而是通过约定来减少配置,并不是一个新套路,新技术,新思想,而是原来就一直存在的,spring Boot只不过是把它放大了,并真正做到了约定大于配置

比如,我们在日常开发过程中。你有一个 xttblog 表,那么可能就对应的有一个 Xttblog 的实体类。这其实就是一种约定。

springBoot 约定,当你导入 spring-boot-starter-web 后,就约定了你是一个 web 开发环境。当你是一个 web 环境,就约定了你会使用 SpringMVC(Struts2 之类的就拜拜了,因为不是亲生的,而且确实没 SpringMVC 使用率高)。至于其它的也约定你会需要,都给你默认导入进来。当你觉得不合适的时候,可以用更少的改动,满足你的需要。

在我们的实际生活中也有体现。比如,我们约定靠右行驶,我们约定从小右手拿筷子等。正是 SprigBoot 的小“约定”,大作用,才让越来越多的人爱上它。

抽象类和接口的区别

说说消息中间件有哪些?

什么是消息中间件?

面向消息的系统(消息中间件)是在分布式系统中完成消息的发送和接收的基础软件。消息中间件也称消息队列,是指用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息队列模型,可以在分布式环境下扩展进程的通信

当前业界比较流行的开源消息中间件包括:ActiveMQ、RabbitMQ、RocketMQ、Kafka、ZeroMQ等,应用最广泛的RabbitMQ、RocketMQ、Kafka这三款

RabbitMQ:轻量级,部署方便,性能不如其他两款

RocketMQ:java实现,在kafka上做改进,经过多次双11考研,性能,稳定性,可靠性没得说,几乎具备消息队列具备的所有特性和功能,跟周边系统的整合和兼容不是很好

Kafka:兼容性好,异步消息的发送和接收好,批量发送,数据达不到真正的实时,无法实现全局消息有序,可能会重复消费数据。

MQ:怎么防止消息重复使用

消费重复的情况有两种:

1、生产时消息重复

由于生产者发送消息给MQ,在MQ确认的时候出现了网络波动,生产者没有收到确认,实际上MQ已经接受到了消息。这时候生产者就会重新发一遍这条消息,就会造成消息重复。

生产者中如果消息未呗确认,或确认失败,我们可以使用定时任务+(redis/db)来进行消息重试

2、消费时消息重复

消费者消费成功后,再给MQ确认的时候出现了网络波动,MQ没有接收到确认,为了保证消息被消费,MQ就会继续给消费者投递之前的消息。这时候消费者就接收到了两条一样的消息。

由于重复消息时网络原因造成的,不可以避免,就需要保证消息的幂等性。

如何保证消息的幂等性?

让每个消息携带一个全局的唯一ID,即可保证消息的幂等性,具体消费过程为:

1、消费者获取到消息后先根据id去查询redis/db是否存在该消息

2、如果不存在,则正常消费,消费完毕后写入redis/db

3、如果存在,则证明消息被消费过,直接丢弃

MySQL事务

Redis事务

Redis:持久化

RDB和AOF的优缺点

AOF文件扩大怎么处理

SpingCloud断路器

数组和集合的相互转换

阿里巴巴创建线程池的规范

三次握手四次挥手可不可以两次握手

不可以,因为客户端和服务端都要确认链接,两次无法保证A能够收到B的数据

1、客户端请求连接服务端

2、针对客户端的请求确认应答,并请求建立链接

3、针对服务端的请求确认应答,建立链接

MyBatis的缓存机制

动态代理

介绍一下AOP

面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术

AOP的本质也是为了解耦,是一种设计思想。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑之间的耦合度降低,提高程序的复用性,同时提高了开发效率。

AOP 底层,就是采用了动态代理的模式来实现的。 其中有两种代理:JDK 的动态代理、CGLIB 的动态代理

例如,转账功能。在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事务等交叉业务逻辑。而这些业务逻辑和主要的业务逻辑之间并没有直接的关系。但是他们的代码量能达到总代码量的一半甚至更多! 他们的存在,不仅产生了大量“冗余”的代码,还大大干扰了主业务逻辑的结构——转账

怎么进行密码加密
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值