面试题2
-
最小连接数法:将请求分配给当前连接数最少的后端服务器,适用于长连接、短连接混合场景。
1.String类可以被继承吗?
在Java中,String类是被声明为final
的,这意味着它是不可变的,不可被继承。因为final类不允许其他类继承它,所以String类不能被继承。如果您尝试创建一个继承自String的子类,编译器将会报错
2.0biect类有什么方法? 都用过哪些?
在Java中,所有的类都是直接或间接地继承自Object类。因此,所有的类都会继承Object类中的一些方法。Object类中的一些常用方法包括:
-
equals(Object obj)
方法:用于比较两个对象是否相等。 -
hashCode()
方法:返回对象的哈希码。 -
toString()
方法:返回对象的字符串表示。 -
getClass()
方法:返回对象所属的类。 -
wait()
方法:导致当前线程等待,直到另一个线程调用该对象的notify()
方法或notifyAll()
方法。 -
notify()
方法:唤醒在该对象上等待的单个线程。 -
notifyAll()
方法:唤醒在该对象上等待的所有线程。
路盛通智能科技
3.final的作用
1.定义常量,定以后不能被修改
2.禁止类的继承,加上final关键字后将该类声明为最终类,禁止其他类继承该类
3.禁止方法重写,将该方法声明为最终方法,禁止子类对其进行重写
4.提高性能,例如,JVM在编译时会对final变量进行常量折叠,将其替换为常量值,从而减少程序的运行时间和内存占用。
4.array和list之间的转换
1.数组转换成list:Arrays.asList() 该方法接受一个数组作为参数,并返回一个List对象。例如:
1 String[] array = {"apple", "banana", "orange"}; 2 List<String> list = Arrays.asList(array);
2.list转换成数组:list.toArray() 如果希望返回指定类型的数组,则可以使用toArray(T[] a)方法。例如:
List<String> list = new ArrayList<>(); list.add("apple"); list.add("banana"); list.add("orange"); String[] array = list.toArray(new String[0]);
4.抽象类和接口的区别
1.实现方式:抽象类使用关键字abstract
定义,接口使用关键字interface
定义
2.继承关系:抽象类可以被其他类继承,子类需要实现抽象方法。接口可以被其他类实现,实现类需要实现接口中的所有方法
3.多继承支持:Java中一个类只能继承一个父类,但是可以实现多个接口,因此接口支持多继承
4.访问修饰符:抽象类中的抽象方法可以使用public
、protected
和default
修饰符,而接口中的方法只能使用public
修饰符。
5.变量定义:抽象类中可以定义成员变量,可以有构造方法,而接口只能定义常量(public static final
修饰的变量),不能有构造方法。
5.rabbitmq是什么,应用场景?
rabbitmq是开源消息中间件,主要功能是实现消息的异步传输和处理,它通过消息队列的方式来处理消息,消息的发送者将消息发送到队列中,消息的接收者从队列中获取消息并进行处理。消息队列的优势在于解耦,消息的发送者和接收者之间不直接通信,而是通过消息队列进行中介,从而实现了系统组件之间的解耦。
应用场景:在线商城的订单处理。当一个顾客下单时,订单系统会将订单信息发送到一个RabbitMQ消息队列中。支付系统从队列中获取订单信息并进行支付处理。如果支付成功,则将订单状态修改为已支付,并将订单信息发送到另一个队列中。物流系统从队列中获取订单信息并进行发货处理。当订单状态被修改为已发货时,订单系统会发送通知消息给顾客。这个整个流程中,各个系统通过RabbitMQ消息队列来进行异步通信,从而实现了系统之间的解耦。
6.rabbitmq的组成
-
Producer(生产者):生产者负责创建并发送消息到RabbitMQ服务器。
-
Consumer(消费者):消费者负责从RabbitMQ服务器接收并消费消息。
-
Exchange(交换器):交换器接收生产者发送的消息并按照一定规则将消息路由到队列中。
-
Queue(队列):队列是消息的存储和转发的地方,消费者从队列中获取消息进行处理。
-
Binding(绑定):绑定将交换器和队列按照一定的规则绑定起来,从而实现消息的路由。
-
Virtual Host(虚拟主机):虚拟主机是一种逻辑隔离机制,每个虚拟主机都拥有自己的交换器、队列和绑定。
-
Connection(连接):连接是客户端与RabbitMQ服务器之间的TCP连接。
-
Channel(信道):信道是建立在连接之上的虚拟连接,用于完成消息的发送和接收。
7.创建线程的方式
-
继承Thread类并重写run()方法:这种方式需要定义一个新的类来继承Thread类,并重写run()方法来定义线程执行的逻辑。然后创建该类的实例,调用start()方法启动线程。
-
实现Runnable接口:这种方式需要定义一个实现Runnable接口的类,并实现run()方法来定义线程执行的逻辑。然后创建该类的实例,将其传递给Thread类的构造函数中,调用start()方法启动线程。
-
使用线程池:线程池是一种重用线程的机制,它会维护一定数量的线程并使其可重用。通过使用线程池,可以有效地控制线程的数量,避免线程的频繁创建和销毁。
在Java中,通常使用第2种方式来创建线程,因为它可以避免单继承的限制,并且可以 实现代码的分离,使得代码更加清晰和易于维护。
8.sql的执行顺序
- FROM:首先从表中读取数据,这个过程称为“表扫描”。
- WHERE:将FROM子句中的结果集中符合WHERE子句中条件的行保留,不符合条件的行丢弃。
- GROUP BY:根据GROUP BY子句中的列,将WHERE子句过滤后的结果集进行分组。
- HAVING:将GROUP BY子句分组后的结果集再次进行过滤,只保留符合HAVING子句中条件的分组。
- SELECT:从GROUP BY和HAVING子句的结果集中选择指定的列进行查询。
- DISTINCT:去除查询结果集中重复的行。
- ORDER BY:将查询结果集按指定的列进行排序。
- LIMIT:返回指定数量的结果行。
需要注意的是,有些SQL数据库执行的顺序可能会略有不同,例如有些数据库可能会在 SELECT之前进行DISTINCT操作。
9.redis的常用数据类型
- String(字符串):可以存储任意类型的字符串,包括二进制数据,最大存储容量为512MB。
- List(列表):可以存储有序的字符串列表,支持从两端进行数据的插入、读取和删除操作。
- Set(集合):可以存储无序的唯一元素集合,支持集合之间的交、并、差等集合运算。
- Sorted Set(有序集合):可以存储有序的唯一元素集合,支持按照指定的分值进行排序,支持范围查找和排名查找等操作。
- Hash(哈希表):可以存储多个键值对,支持快速地进行单个键值对的读取和修改操作,适用于存储对象或实体属性。
- Bitmaps(位图):可以用于存储二进制数据中的位信息,支持位操作,例如并、交、补等操作。
10.redis的删除策略
- 定期删除:Redis会周期性地扫描数据库,删除一定时间内未被访问的数据。可以通过配置参数
maxmemory
和maxmemory-policy
来设置Redis的最大内存限制和删除策略。定期删除策略的优点是简单高效,缺点是可能会导致过期数据没有及时删除,浪费内存。 - 惰性删除:Redis在访问某个键值对时,先检查其是否过期,如果过期则立即删除。惰性删除策略的优点是可以确保过期数据及时删除,缺点是会增加访问数据的时间复杂度。
- 定期删除和惰性删除结合:Redis可以通过结合定期删除和惰性删除策略来优化内存的使用效率。在数据库中设置键的过期时间,同时Redis会定期扫描过期键并删除,避免了过期数据的浪费。
在实际应用中,需要根据实际情况选择合适的删除策略来平衡内存和性能的关系。
11.sql的优化策略
- 创建合适的索引:索引可以加快SQL查询的速度,但是过多的索引会降低数据库写入性能。应该根据查询的业务场景和数据分布情况,选择合适的索引类型和建立索引的字段。
- 减少查询数据的范围:应该尽量减少查询数据的范围,可以通过添加where条件、使用limit限制返回的结果数等方式来实现。
- 避免使用子查询:子查询会增加SQL查询的复杂度和开销,应该尽量避免使用。可以通过关联查询、临时表等方式来替代子查询。
- 避免使用
SELECT *
:应该尽量避免使用SELECT *
语句,因为这会查询所有的字段,增加网络传输和数据处理的开销。应该只查询需要的字段,可以减少查询的时间和数据传输的大小。 - 避免使用函数和表达式:函数和表达式会增加SQL查询的计算开销,应该尽量避免使用。可以通过预处理和缓存查询结果等方式来优化查询的性能。
- 优化SQL语句的执行顺序:应该尽量优化SQL语句的执行顺序,可以通过分解复杂的查询语句、重新组织查询条件等方式来实现。
- 使用分区表:当表中数据量很大时,可以将表分成多个分区,分别存储不同的数据范围。这样可以加快查询速度,同时减少锁的竞争,提高并发性能。
SQL优化是一个复杂而又关键的工作,需要深入了解业务场景和数据特征,结合数据库的优化参数和工具,不断优化SQL语句和数据库性能,提高系统的性能和可用性。
12.mysql索引失效的场景
-
在索引列上使用函数或表达式,例如使用
WHERE YEAR(create_time) = 2021
。这种情况下,MySQL无法使用索引,因为它需要计算函数或表达式的值。 -
索引列上的数据类型不匹配。例如,如果索引列是整数类型,但是查询时使用了字符串类型的值,那么MySQL将无法使用索引。
-
对索引列使用LIKE操作符以模糊匹配。在这种情况下,MySQL只能使用索引的前缀来匹配,因此可能会导致索引失效。
-
当使用NOT操作符时,MySQL将无法使用索引。
-
在JOIN查询中,如果MySQL无法确定哪个表是驱动表(即哪个表是第一个被查询的表),则可能会导致索引失效。
-
在使用OR逻辑操作符时,如果MySQL无法使用索引来覆盖所有OR条件,则可能会导致索引失效。
-
如果查询返回的数据太多,MySQL可能会决定不使用索引,而是执行全表扫描。
13.springboot自动配置的原理
Spring Boot 的自动配置原理基于 Spring 的条件化配置和 Spring 的配置元数据。当应用程序启动时,Spring Boot 会扫描类路径上的所有 jar 包,并查找 META-INF/spring.factories
文件,该文件包含了可用的自动配置类。
Spring Boot 的自动配置类通常使用 @Conditional
注解,它可以根据条件来决定是否应该将某个 Bean 注册到应用程序上下文中。这些条件通常基于特定的环境变量、属性值、类路径上的文件存在与否等等。
当应用程序启动时,Spring Boot 将读取应用程序的配置文件并确定哪些自动配置类需要启用,然后将这些自动配置类中定义的 Bean 注册到 Spring 应用程序上下文中。
这种自动配置机制可以大大简化 Spring Boot 应用程序的配置过程,使得开发者可以更加专注于业务逻辑的实现。
14.vue的生命周期函数
-
beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性。
-
created:实例已经在内存中创建 OK,此时 data 和 methods 已经创建 OK,此时还没有开始编译模板。
-
beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中。
-
mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示。
-
beforeUpdate:状态更新之前执行此函数,此时 data 中的状态值是最新的,但是界面上的数据还没有更新。
-
updated:实例更新完毕之后调用此函数,此时 data 中的状态值和界面上的数据都已经完成了更新。
-
beforeDestroy:实例销毁之前调用。
-
destroyed:实例销毁之后调用。
在 Vue.js 中,组件的生命周期和 Vue 实例的生命周期是一样的,只是多了几个组件特有的生命周期函数。例如:
-
beforeRouteEnter:在路由进入该组件前调用。
-
beforeRouteUpdate:在路由更新该组件前调用。
-
beforeRouteLeave:在离开当前路由时调用。
15.nginx的配置
# 全局配置
user nginx; # 指定Nginx进程运行的用户
worker_processes auto; # 自动设置为处理器的数量
error_log /var/log/nginx/error.log; # 错误日志文件路径
pid /run/nginx.pid; # 进程ID文件路径
# 事件模块配置
events {
worker_connections 1024; # 每个工作进程最大连接数
}
# HTTP模块配置
http {
include /etc/nginx/mime.types; # 包含文件类型配置
default_type application/octet-stream; # 默认文件类型
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; # 日志格式
access_log /var/log/nginx/access.log main; # 访问日志文件路径及格式
# 虚拟主机配置
server {
listen 80; # 监听端口
server_name example.com; # 域名或IP地址
# 根据不同请求路径或文件类型转发到不同的后端服务器
location /api/ {
proxy_pass http://api_server/;
}
location / {
root /var/www/html; # 静态文件根目录
index index.html; # 默认首页文件名
}
}
}
在这个配置示例中,Nginx的配置分为全局配置、事件模块配置和HTTP模块配置三部分,其中HTTP模块配置包含了虚拟主机配置、日志配置和转发规则等。虚拟主机配置中指定了监听的端口和服务器名,并且定义了转发规则,将不同的请求路径或文件类型转发到不同的后端服务器。
16.负载均衡的方式
-
随机法:请求随机分配给后端服务器,适用于后端服务器配置相同、访问量不大的情况。
-
轮询法:将请求轮流分配给后端服务器,适用于后端服务器配置相同、访问量较大的情况。
-
加权轮询法:根据后端服务器的性能配置和负载情况进行加权分配,适用于后端服务器配置不同、访问量较大的情况。
- 最小连接数法:将请求分配给当前连接数最少的后端服务器,适用于长连接、短连接混合场景。
17.docker的常用命令
- docker run:启动一个容器
- docker start:启动一个已经停止的容器
- docker stop:停止一个容器
- docker ps:列出所有正在运行的容器
- docker images:列出所有本地镜像
- docker rm:删除一个或多个容器
- docker rmi:删除一个或多个本地镜像
- docker exec:在正在运行的容器中执行命令
- docker build:根据Dockerfile构建镜像
- docker pull:从远程仓库拉取镜像