Java实习第一次技术面 问题记录

文章回顾了一次面试中的技术问题,涉及Java的封装、继承、多态,集合特性,线程池概念,MySQL的索引、事务和隔离级别,Redis的数据类型和应用场景,以及Spring和SpringBoot的核心概念。同时,讨论了如何计算String中字符个数、数组扩容的方法和缓存问题的解决方案。
摘要由CSDN通过智能技术生成

复盘一下面试!第一次面试很突然,问题都很基础,但是我很多基础原理都没怎么好好复习!好紧张!!慢慢回忆面试问题中...

目录

Java基础

对Java特性(封装、继承、多态)的了解

对集合的了解

Set、List类型的特点

Map数据结构

对线程池的了解,怎么配置

数组的特点

数组扩容

怎么计算String对象中每个字符的个数

MySQL

MySQL索引

MySQL事务的特性

MySQL隔离级别

Redis

Redis的数据类型和应用场景

Redis缓存穿透、雪崩、击穿及其解决方案

Redis中zsets的应用场景

对Redis中String类型的了解

怎么实现Redis在身份认证中的作用

Spring

对Spring的了解

AOP的动态代理机制

Spring事务传播行为

SpringBoot

印象比较深的SpringBoot注解

SpringBoot相较于Spring的优势


Java基础

对Java特性(封装、继承、多态)的了解

封装的实现步骤是使类中属性使私有的,属性的setter、getter方法是公有的;外界只能使用特定方法访问属性,隐藏类的实例细节,方便修改实现。

继承的基本思想是基于已有的类创造新的类,通过抽取共性实现代码复用,子类使用extends关键字继承父类。继承是多态的基础。

多态主要通过继承抽象类或实现接口实现,多态中经常混淆的两个概念是重载和重写,重载时在一个Java文件中可以出现多个同名方法,方法的输入输出参数都可以不同,而重写是指子类覆盖父类中的方法,输入输出参数都一致。

对集合的了解

Colletion接口是最基本的集合接口,定义了一组允许重复的对象,派生了两个子接口Set和List(其实还有Queue队列);Map接口没有继承Collection接口,存储形式为key/value;Iterator迭代器接口,使用实现了Collection接口的容器类都有iterator方法,foreach循环本质上就是使用了Iterator接口方法实现元素遍历

Set、List类型的特点

Set对象无序且不可重复,List对象有序且可以重复。

Map数据结构

Map是一个接口类,没有继承Collection,它存储的是key/value结构,key是唯一、非空的,而value不唯一且可以为空。

Map不能直接实例化对象,它的实现类是TreeMap、HashMap,可以实例实现类,其中TreeMap是基于红黑树的,HashMap是基于哈希表的。

Map<String, String> map = new TreeMap<>();

Map<String, String> map = new HashMap<>();

对线程池的了解,怎么配置

(真的非常不了解~~~~~~~~~~~~~ 找时间再去学习一下)

线程池可以降低资源消耗,提高响应速度及现成的可管理性。

线程池的真正实现类是ThreadPoolExecutor

数组的特点

数组是一个对象,是一种引用数据类型;

数组只能保存一种类型的数据(如果把数组定义为Object类型的话,其实是可以存储不同的数据类型的,但是也都可以视为Object类型,所以也没毛病)

数组的下标是从0开始的。

数组对象的大小是固定不变的,数组对象是不可扩容的。

数组扩容

数组对象不可扩容,但数组可以扩容。

实现数组扩容的方式:

1.创建新数组b,数组b长度比原数组a长,把a的内容复制搭配数组b中,最后用数组b覆盖数组a

2.使用System.arraycopy(src, srcPos, dest, destPos, length)方法

3.使用java.util.Arrays.copyOf(src, changeLength)方法,其本质也是使用了System.arraycopy

怎么计算String对象中每个字符的个数

把String对象用String.toCharArray()转换为字符数组char[],再遍历数组进行计数

MySQL

MySQL索引

索引按照功能可以分为普通索引、唯一索引、全文索引,按照作用分为单列索引、多列索引。索引会占据磁盘空间,可以加快查询速度,但会减慢更新速度。

索引创建:create index IndexName on TableName(AttributeName)

索引删除:drop index IndexName

索引查询:show index from TableName

MySQL事务的特性

ACID,也就是原子性、一致性、隔离性、持久性

原子性:一个事务要么全部成功,要么全部失败回滚

一致性:只提交成功的事务的结果

隔离性:各个事务之间互不干扰,多个并发事务之间要相互隔离

持久性:指一个事务一旦被提交了,那么数据库中数据的改变就是永久的,即使数据库系统遇到故障也不糊丢失提交事务的操作。

MySQL隔离级别

可串行化、可重复读、已提交读、未提交读(与四种数据不一致情况一一对应,依次是丢失修改、不可重复读、读“脏”数据、幻读)

MySQL默认的隔离级别是可重复读

Redis

Redis的数据类型和应用场景

数据类型:String、List、Set、Hash、Sorted Sets(ZSets)

应用场景:查询缓存、消息队列(使用List类型)、排行榜(使用ZSets类型)、秒杀等

Redis缓存穿透、雪崩、击穿及其解决方案

1.缓存穿透:数据在缓存和数据库中都不存在,缓存永不生效

   解决方案:查询到空值也进行缓存/采用布隆过滤器/实时监控,Redis命中率急速降低时进行排查设置黑名单/做好基础数据的格式校验/增强id的复杂性,避免被猜测id规律/加强用户权限校验

2.缓存雪崩:同一时间段内大量key失效或服务器宕机,导致大量请求到达数据库

   解决方案:给不同key的TTL添加随机值/利用集群提升服务可用性/给缓存业务添加降级限流策略/给业务添加多级缓存

3.缓存击穿:高并发访问且缓存重建业务较复杂的key突然失效,无数的请求访问会在瞬间给数据库带来巨大冲击

   解决方案:预先设置热门数据/实时监控并调整热门数据的key的过期时长/使用互斥锁,使得第一次查询不到数据时,就获取互斥锁使得其它线程获取互斥锁失败,等待写入缓存后再释放锁/逻辑过期

Redis中zsets的应用场景

【zsets有序集合是Redis中最灵活的数据结构,它的存储元素(value)相当于有两个值组成,一个是元素值,一个是分值。它保留了集合(set)类型不能有重复成员的特性(分值可以重复),但是有序集合中的元素可以排序。】

zsets可以应用于排行榜,比如说热搜,把规定时间段内的话题评论数或者点赞数等作为分值,话题作为元素值,以分值进行排序,从而实现排行榜。

对Redis中String类型的了解

String是Redis中最简单的数据结构,可以将一个字符串作为键和值进行存储。

在SpringDataRedis中,String类型与其它四种数据类型在类或方法的命名方式有所区别,其它数据类型是使用原名称进行命名,比如HashOperation类、RedisTemplate的opsForHash方法等,而String类型对应的则是ValueOperation、opsForValue

怎么实现Redis在身份认证中的作用

1.在登录时,假设使用邮箱验证码登录,验证用户账号存在后,生成验证码并发送到用户邮箱,将账号作为key,验证码作为value存储到Redis中并设置过期时间及其单位【,譬如说10分钟,就是timeout=10,unit=TimeUnit.MINUTES】

@Resource
StringRedisTemplate stringRedisTemplate;
..........................

stringRedisTemplate.opsForValue().set("loginCode:"+account,loginCode,timeout,unit));

当用户输入验证码进行登录后,从Redis中读取该用户账号的验证码,是否与输入验证码匹配,不一致则报错

String cacheCode = stringRedisTemplate.opsForValue.get("loginCode:"+account);
if (cacheCode == null || !cacheCode.equals(code)) {//code是用户输入
     // 不一致,报错
}

一致,则生成token,将token和用户身份信息以hash类型存入Redis中

//BeanUtil是cn.hutool.core.bean包下的一个类,需要引入;userDto就是用户信息
Map<String, Object> userMap = BeanUtil.beanToMap(userDto, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor((fieldName,fieldValue) -> {
                            if (fieldValue == null){
                                fieldValue = "0";
                            }else {
                                fieldValue = fieldValue.toString();
                            }
                            return fieldValue;
                        }));
        //存储到redis中
        String token = UUID.randomUUID().toString(true);
        String tokenKey = "token:" + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        //设置token有效期
        stringRedisTemplate.expire(tokenKey, 24.TimeUnit.HOURS);

2.在需要验证用户身份时,从请求头中获取token,然后读取Redis中token对应的用户信息,判断与请求的信息所属用户的用户名是否匹配

Object o = stringRedisTemplate.opsForHash().get("loginCode:" + token,"account");
String account = String.valueOf(o);
//下面就是匹配userName是否与请求的信息所属用户的用户名一致

Spring

对Spring的了解

Spring框架的成功之处在于它的设计思想,IoC和AOP。

IoC指的是控制反转,在我们传统的开发中,如果对象A需要对象B的话,需要通过new来实现,在引入Spring框架后,IoC容器会创建一个对象B并注入到A中。IoC使对象A从主动创建变成了被动接收。

AOP指面向切面编程,Spring将软件系统分为核心关注点和横切关注点两个部分,核心关注点就是核心的业务实现,横切关注点出现在业务中的很多地方,比如说身份认证就是一个横切关注点。

除此之外,Spring只需要通过配置就可以完成对事物的管理,无需手动编程,并且Spring方便继承各种优秀框架。

AOP的动态代理机制

动态代理主要分为JDK动态代理和CGLIB代理。

JDK动态代理依赖于类的父接口生成代理,而不针对类;CGLIB使针对类实现代理。

Spring在选择用JDK还是CGLIB时是看Bean有没有实现接口,实现接口了就使用JDK动态代理;没有实现接口就用CGLIB。

Spring事务传播行为

SpringBoot

印象比较深的SpringBoot注解

Resource、AutoWired、Controller、RestController、Service、Mapper、Response等

SpringBoot相较于Spring的优势

SpringBoot是Spring框架的延申和扩展,有入门依赖和内置容器,(因此可以不用去手动配置Tomcat服务器等)简化了构建和开发。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值