Java面试题练习第二套(包含参考答案)

注意:答案并不是标准答案,这个答案是基于我本人自己对相关知识点多理解,仅供参考!如果有错误,欢迎各位小伙伴指正。本篇博客是用于记录个人的学习的。

目录

问题

Java

数据库

Boot

问题加答案

Java

1.什么是bean?以及其作用域?

2.基本数据类型,占几个字节?

3.说一说进程和线程的区别?

4.线程的状态,以及各种状态是怎么转换的?

5.说一说线程池?

6.项目中有没有使用到IO?

7.操作string的类?

8.stringBuffer 和 stringBuilder的联系以及区别?

9.hashMap的底层?

数据库

1什么情况不建议使用索引?

2.说一说数据库的三范式?

3.行锁和表锁哪个开销更加大?

4.百万数据如何优化?

Boot

1.为什么选用spring Boot?

2.spring Boot的自动装配原理?

3.项目中使用到哪些注解?

4.spring Boot的优点?


问题

Java

1.什么是bean?以及其作用域?

2.基本数据类型,占几个字节?

3.说一说进程和线程的区别?

4.线程的状态,以及各种状态是怎么转换的?

5.说一说线程池?

6.项目中有没有使用到IO?

7.操作string的类?

8.stringBuffer 和 stringBuilder的联系以及区别?

9.hashMap的底层?

数据库

1什么情况不建议使用索引?

2.说一说数据库的三范式?

3.行锁和表锁哪个开销更加大?

4.百万数据如何优化?

Boot

1.为什么选用spring Boot?

2.spring Boot的自动装配原理?

3.项目中使用到哪些注解?

4.spring Boot的优点?

问题加答案

Java

1.什么是bean?以及其作用域?

可以理解为bean是一个个的对象,bean是由spring中的IOC容器管理的,我们的应用程序是由一个个bean组成的.

bean的作用域有:singleton, prototype,request,session,application,其中最常见的两个作用域是 singleton, prototype ;

singleton: 中的bean是以单例的形式存在的,不管获取多少次返回的都是同一个bean实例,这个作用域是bean的默认值;

prototype :每次从容器中调用bean的时候,都会返回一个新的实例;

2.基本数据类型,占几个字节?

byte(1字节),short(2字节),int(4字节),long(8字节),float(4字节),double(8字节),char(2字节),boolean(1字节);

补充:

Java面试题练习第二套(包含参考答案)_第1张图片

 

3.说一说进程和线程的区别?

进程:

  • 程序由指令和数据组成,这些指令要运行,数据要读写,就必须将指令加载至 CPU数据加载至内存,而且在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的。

  • 进程可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如浏览器 等),也有的程序只能启动一个实例进程(例如网易云音乐等)

  • 当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。

线程:

  • 线程是由进程创建的,是进程的一个实体,是具体干活的人,一个进程可能会有多个线程。

  • 线程不独立分配内存,而是共享进程的内存资源,线程可以共享CPU的计算资源;

区别:

Java 中,线程作为小调度单位,进程作为资源分配的最小单位。

线程存在于进程内,是进程的一个子集

进程更加强调:内存资源的分配; 线程更加强调:计算资源的分配

4.线程的状态,以及各种状态是怎么转换的?

Java API 层面来描述的(就是我们经常说的线程状态一般是指这个):根据 Thread.State 枚举,分为六种状态

  • NEW: 线程刚被创建,但是还没有调用 start() 方法

  • RUNNABLE: 当调用了 start() 方法之后; (注意 :BLOCKED , WAITING , TIMED_WAITING 都是 Java API 层面对【阻塞状态】的细分

  • BLOCKED :线程竞争锁失败,线程WAITING --> BLOCKED(blocked是线程去竞争锁时没有获取到锁,从而进入了这个状态)

  • WAITING :线程获取锁后,通过调用一下方法让线程释放锁(比如wait方法,join方法, LockSupport.park() 方法等),线程RUNNABLE --> WAITING

  • TIMED_WAITING: 调用 obj.wait(long n) 方法时,线程RUNNABLE --> TIMED_WAITING,等待时间超过了 n 毫秒 或者是 调用 obj.notify(),obj.notifyAll(),t.interrupt()时线程没有抢到锁 ,这些情况线程都会进入TIMED_WAITING状态;

  • TERMINATED: 当前线程所有代码运行完毕,进入 TERMINATED

(下面这个分类可答可不答,看面试官问不问吧............)

操作系统 层面来描述:

  • 【初始状态】: 仅是在语言层面创建了线程对象,还未与操作系统线程关联

  • 【可运行状态】:(就绪状态)指该线程已经被创建(与操作系统线程关联),可以由 CPU 调度执行

  • 【运行状态】: 指获取了 CPU 时间片运行中的状态, 当 CPU 时间片用完,会从【运行状态】转换至【可运行状态】,会导致线程的上下文切换(cpu的使用时间片只会分给可运行状态的线程)

  • 【阻塞状态】:如果调用了阻塞 API,如 BIO 读写文件,这时该线程实际不会用到 CPU,会导致线程上下文切换,进入 【阻塞状态】,等 BIO 操作完毕,会由操作系统唤醒阻塞的线程,转换至【可运行状态】; 与【可运行状态】的区别是,对【阻塞状态】的线程来说只要它们一直不唤醒,调度器就一直不会考虑 调度它们

  • 【终止状态】表示线程已经执行完毕,生命周期已经结束,不会再转换为其它状态;

  • Java面试题练习第二套(包含参考答案)_第2张图片

     

5.说一说线程池?

线程是种宝贵的资源并且创建线程是会导致上下文的频繁切换,线程池是为了更好的调度这些宝贵的资源而产生的,它可以帮助我们更好的利用以及管理线程;

创建线程池的方法有很多种,比如jdk中提供的newFixedThreadPool类,newCachedThreadPool类,newSingleThreadExecutor类来创建线程池, 但是在阿里规约中不允许我们使用这三种方法来创建线程池,因为它们要么就是无界的阻塞队列,要么就是线程数量无限,这很容易导致系统OOM,阿里规约建议我们使用ThreadPoolExecutor类来创建线程池,因为使用这种方式创建线程池我们可以根据自己的系统性能自定义设置线程池的一些参数;

比如ThreadPoolExecutor中最全的一个构造函数:(这个人家问 你就说,不问的话看你自己有没有机会说......)

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
  • corePoolSize 核心线程数目 (最多保留的线程数,会被保留在线程池,没有存活时间这种说法)

  • maximumPoolSize 最大线程数目 (maximumPoolSize - corePoolSize = 救急线程数)

  • keepAliveTime 生存时间 - 针对救急线程

  • unit 时间单位 - 针对救急线程

  • workQueue 阻塞队列

  • threadFactory 线程工厂 - 可以为线程创建时起个好名字

  • handler 拒绝策略

6.项目中有没有使用到IO?

有使用到,比如用户从服务器下载图片(模板文件或者是报表也会需要到,不过操作方式可能会有专门的工具库),我们要先获取用户要下载的图片的输入流,然后把这个输入流读取定义的缓冲区中,然后再通过reponse对象把缓冲区的数据写给浏览器,不过在写给浏览器的时候一定要设置写回去的文件类型;(response.setContentType("image/jpeg");)

注意:这个是可以优化的,我们可以把用户上传的图片存储一份到redis中,下一次用户再上传图片,我们就先和redis中的图片进行对比,如果重复,那么就返回成功状态,但是此时并不会真的再往存储作用的中服务器中插入该图片文件了;

7.操作string的类?

String,StringBuffer,StringBuilder;

补充:

string的底层维护的数组是用final修饰的,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象。特点:这样不仅效率低下,而且大量浪费有限的内存空间。

StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,添加直接用.append();在经常改变字符串内容的情况下最好不要使用 String

  • StringBuilder 是非线程安全的,性能高(适合线程)(无同步锁)

  • StringBuffer 是线程安全的(适合线程)(有同步锁)synchronized

8.stringBuffer 和 stringBuilder的联系以及区别?

联系:两个类都是字符缓冲类,提供的方法是一样的 区别就是有没有加同步锁;

  • StringBuilder 是非线程安全的,性能高(适合线程)(无同步锁)

  • StringBuffer 是线程安全的(适合线程)(有同步锁)synchronized

9.hashMap的底层?

在jdk8及之后,hashMap的结构是由【数组+单向链表+红黑树】构成的,链表是数组中的元素,有点像灯笼结构,当链表的长度超过默认设定的长度8时,hashmap会优先检查数组的长度,如果数组的长度没有超过64,那么就会优先对数组进行扩容2倍,如果不能够扩容那么链表就会树化(实际上链表的树化的概率是非常小的,源码中给出了相关的概率,看下面的图,是不是感觉很熟悉,,,没错这就是泊松分布);

Java面试题练习第二套(包含参考答案)_第3张图片

而且在在jdk8及之后链表是使用尾插的方法来进行数据的添加,这样可以避免链表变成循环链表(之前的hashmap是使用头插法添加数据的,可能会导致循环链表的产生);

之所以该用红黑树,是因为当链表太长的话就会导致查询的效率变成O(N),而红黑树的查询效率是O(log(n))

hashMap中最重要的两个方法:put和get方法;(是否展开说看自己情况而定,这里就不先不展开说了,后续会在补上)

数据库

1什么情况不建议使用索引?

频繁更新的字段不适合建立索引 (因为数据比较大的表的索引的创建是非常耗时的,而且如果一个字段被频繁更新那么我们还需要频繁的维护这个树的结构,这个开销是非常大的)

参与列计算的列不适合建索引,因为计算后的列的值最后不一定是有序的,不有序那么就会导致索引会失效

③表数据可以确定比较的不需要建索引

数据重复且分布比较均匀的的字段不适合建索引,因为说不定你对这种索引字段的查询的速度还没有全表扫描快,例如性别,真假值;

where条件中用不到的字段不适合建立索引,因为索引是可以帮助我们在查询的时候大大的提高查询效率,但是在增加,删除操作确实异常消耗性能的,因为需要不断的维护B+树的结构(有序你就需要维护),你查询的时候都不需要使用到这个字段了,那还建立这个字段的索引列干啥?等着吃你系统的性能嘛?

2.说一说数据库的三范式?

  • 第一范式:要求有主键,并且要求每一个字段原子性不可再分

  • 第二范式:要求所有非主键字段完全依赖主键,不能产生部分依赖

  • 第三范式:所有非主键字段和主键字段之间不能产生传递依赖

注意:第二范式建立在第一范式的基础上,第三范式建立在第二范式

设计只是一种思想一种理念,我们按照规范的设计方式设计数据库对我们来说有好处,但绝对不是说一定要严格遵守,三范式能极大的减少数据冗余,但是相对编写sql而言是增加了难度的,所以所有好的设计都是要权衡利弊的;

补充:辅助理解!

  • 第一范式:要求有主键,并且要求每一个字段原子性不可再分

Java面试题练习第二套(包含参考答案)_第4张图片

  • 第二范式:要求所有非主键字段完全依赖主键,不能产生部分依赖

Java面试题练习第二套(包含参考答案)_第5张图片

 解决方案:分表,建立关联表;

  • 第三范式:所有非主键字段和主键字段之间不能产生传递依赖

Java面试题练习第二套(包含参考答案)_第6张图片

 

3.行锁和表锁哪个开销更加大?

表锁的开销更加大,因为表锁是把整张表都锁起来,那么此时其他用户再来访问这张表的数据就会被阻塞;

行锁的粒度更加小,更加灵活,但是可能更加容易发生死锁。

补充:避免死锁的一些方式:

  • 尽量让数据表中的数据检索都通过索引来完成,避免无效索引导致行锁升级为表锁

  • 合理设计索引,尽量缩小锁的范围

  • 尽量减少查询条件的范围,尽量避免间隙锁或缩小间隙锁的范围。

  • 尽量控制事务的大小,减少一次事务锁定的资源数量,缩短锁定资源的时间。如果一条SQL语句涉及事务加锁操作,则尽量将其放在整个事务的最后执行。

  • 尽量保证事务顺序执行,不要乱序执行不同的事务;

4.百万数据如何优化?

百万级别的数据查询在MySQL的性能承受范围内,我们可以通过添加索引(比如对排序字段分组字段,以及频繁查询的字段进行加索引)或者是建立复合索引来提高查询效率,或者是优化SQL语句,比如尽量不要在查询语句中出现select * 的这种查询,尽量使用外连接查询(可以避免产生笛卡尔集),或者是使用redis等缓存技术来减少直接对MySQL的查询;

Boot

1.为什么选用spring Boot?

它可以让我们的开发变得更加简洁,让开发人员把更多的精力放在具体的业务上面,而不是各种配置文件;

它也让我们的部署变得更加简单,因为spring boot采用的是内嵌的服务器;

它可以让监控变得更加简单,它专门提供了一款监控组件来完成这个工作,这个组件就是 Spring Boot Actuator

2.spring Boot的自动装配原理?

@EnableAutoConfiguration是自动装配的核心注解;

  1. springboot启动时先加载spring.factories文件中的org.springframework.boot.autoconfigure.EnableAutoConfiguration配置项,将其中配置的所有的类都加载成bean

  2. 在加载bean的时候,bean对应的类定义上都设置有加载条件(比如@ConditionalOnClass,表示当虚拟机中加载了某个类时才加载该注解对应的bean),因此有可能加载成功,也可能条件检测失败不加载bean

  3. 对于可以正常加载成bean的类,通常会通过@EnableConfigurationProperties注解初始化对应的配置属性类并加载对应的配置(相当于帮bean进行一些值得初始化)

  4. 配置属性类上通常会通过@ConfigurationProperties加载指定前缀的配置,当然这些配置通常都有默认值。如果没有默认值,就强制你必须配置后才可以使用

3.项目中使用到哪些注解?

比如:

  • @Configuration:把一个类声明为配置类,与@bean注解结合起来使用;

  • @ConfigurationProperties(prefix = "") ,从配置文件去获取值注入到当前bean的属性中;

  • @RestController:@Controller和@ResponseBody的结合体, 表示返回的数据不走视图层,和该类是一个controller类;

  • @RequestParam,@PathVariable,@requestBody,@AutoWired,@Component

  • @Aspect : 声明为切面类;

  • @EnableTransactionManagement:开启事务支持,然后在访问数据库的Service方法上添加注解 @Transactional 便可对其使用事务;

等等。。。。。

4.spring Boot的优点?

  • 最大的优点应该就是约定优于配置;约定优于配置是一种软件设计的范式,它的核心思想是减少软件开发人员,对于配置项的维护,从而让开发人员能更聚焦在业务逻辑上;

  • 大大的简化了配置;

  • 内置tomcat服务器,不需要打包成war包,可以直接放到tomcat中运行;

  • 为微服务SpringCloud奠定了基础,使得微服务的构建变得简单;

你可能感兴趣的:(Java面试,java,面试)