java实习生面试题

                            


(1).#{} ${}的区别

一.类型不一样
(1)#{}:参数占位符,即预编译
(2)${} :字符串替换符,即SQL拼接

二.防注入问题 
(1)#{}:很大程度上能防止sql 注入
(2)${}:不能防止sql 注入

三.执行过程
(1)#{}:编译好SQL后语句再去取值 
(2)${}:取值以后再去编译SQL语句

一般能用#的就别用$  

(2).数据库事物

一、数据库的隔离级别:

        1.读未提交(Read uncommitted);  在提交前别人可以读数据

        2.读已提交(Read committed);    提交之后的数据才可以读

        3.可重复读(Repeatable read),数据库默认开启;

        4.串行化(Serializable )

原子性 一致性 隔离性 持久性

二、如果不考虑隔离性,会发生什么事呢?

(1).脏读:

        脏读是指一个事务在处理数据的过程中,读取到另一个未提交事务的数据。

(2).不可重复读:

        不可重复读是指对于数据库中的某个数据,一个事务范围内的多次查询却返回了不同的结果,这是由于在查询过程中,数据被另外一个事务修改并提交了。

(3).幻读

        幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。


三、四种隔离级别解决了上述问题

        1.读未提交(Read uncommitted):这种事务隔离级别下,select语句不加锁。

此时,可能读取到不一致的数据,即“读脏 ”。这是并发最高,一致性最差的隔离级别。

        2.读已提交(Read committed):可避免 脏读 的发生。在互联网大数据量,高并发量的场景下,几乎 不会使用 上述两种隔离级别。

        3.可重复读(Repeatable read):MySql默认隔离级别。可避免 脏读 、不可重复读 的发生。

        4.串行化(Serializable ):可避免 脏读、不可重复读、幻读 的发生。


 REDIS用在经常要被访问的页面上,比如首页,或者是不常更换的数据上.

(3)redis的五种数据类型 


redis无论什么数据类型,在数据库中都是以key-value形式保存,并且所有的key(键)都是字符串,所以讨论基础数据结构都是讨论的value值的数据类型

主要包括常见的5种数据类型,分别是:String、List、Set、Zset、Hash。

String字符串    可以是字符串、整数或浮点数    对整个字符串或字符串的一部分进行操作;对整数或浮点数进行自增或自减操作;
List列表    一个链表,链表上的每个节点都包含一个字符串    对链表的两端进行push和pop操作,读取单个或多个元素;根据值查找或删除元素;
Set集合    包含字符串的无序集合    字符串的集合,包含基础的方法有看是否存在添加、获取、删除;还包含计算交集、并集、差集等
Hash散列    包含键值对的无序散列表    包含方法有添加、获取、删除单个元素
Zset有序集合    和散列一样,用于存储键值对    字符串成员与浮点数分数之间的有序映射;元素的排列顺序由分数的大小决定;包含方法有添加、获取、删除单个元素以及根据分值范围或成员来获取元素

(4)redis为什么是单线程的?


redis6.0之前的网络i/o和读写存储是单线程的
redis6.0之后 网络请求采用多线程 读写存储依然是单线程
持久化,集群数据同步是额外的线程完成的

(5)为什么那么快?


1、命令执行基于内存操作,一条命令在内存操作的时间是几十纳秒
2.命令执行是单线程操作,没有线程切换开销
3.基于IO多路复用机制提升Redis的I/O利用率
4.高效的数据结构

(6)list ,set和map的区别:


List、Set 和 Map 的区别:       有无序 有无重复 null 常见形式特点

集合    List    Set    Map
元素顺序    有序    无序    key 无序、value 无序
元素是否可重复    可重复    不可重复    key 不可重复、value 可重复

    1.list
    List 中存储的元素有序,指的是读出的顺序与存入的顺序是一致的。

    ①可以允许重复的对象;
    ②可以插入多个 null 元素;
    ③是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序;
    ④常用的实现类有 ArrayList、LinkedList 和 Vector;ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。

   2.Set
    Set 存储的元素是无序的,这里的无序指的是存入的顺序与输出的顺序可能是不一致的。

    ①不允许重复对象;
    ②无序容器,你无法保证每个元素的存储顺序,TreeSet 通过 Comparator 或者 Comparable 维护了一个排序顺序;
    ③只允许一个 null 元素;
    ④Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet;
    最流行的是基于 HashMap 实现的 HashSet;
    TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。

  3.Map
      Map 存储的元素是键值对(key-value),键和值都是无序的,即存入顺序与输出顺序可能都不一样。

      ①Map 不是 Collection 的子接口或者实现类,Map 是一个接口;
      ②Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的;
      ③TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序;
      ④Map 里你可以拥有随意个 null 值,但最多只能有一个 null 键;
      ⑤Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap 最常用)


(7)面向对象的设计原则


1、开闭原则
        面向对象可复用设计原则中最基础的原则便是开闭原则,开闭原则指的是在设计一个对象(类、模块、函数)时,应遵循或做到对扩展开放、对修改关闭,其核心思想是面向接口/抽象进行编程。
4、单一职责原则
        一个类只负责一个功能领域中的相应职责。就一个类而言,应该只有一个引起它变化的原因。不同的类具备不同的职责,各司其职。

(8)多态 


1.子类继承夫类
2.子类重写夫类方法 
3.夫类引用指向子类的实例


(9)string ,stringbuilder和stringbuffer的区别


string 类使用final关键字修饰字符数组来保存字符串,private final char value[],所以string对象不可以变.
stringbuffer  对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的
stringbuilder 并没有对方法进行同步锁,所以是线程不安全的
基本原则:如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer。 
区别一:在Java中字符串使用String类进行表示,但是String类表示字符串有一个最大的问题:“字符串常量一旦声明则不可改变,而字符串对象可以改变,但是改变的是其内存地址的指向。”所以String类不适合于频繁修改的字符串操作上,所以在这种情况下,往往可以使用StringBuffer类,即StringBuffer类方便用户进行内容修改,

区别二:在String类中使用“+”作为数据的连接操作,而在StringBuffer类中使用append()方法(方法定义:public StringBuffer append(数据类型 变量))进行数据连接。

区别三:  equals方法 string 的equals方法重写了 但是stringbuffer没重写

1. 操作少量的数据: 适用String

2. 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder

3. 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

(10) equals ==的区别


 == 与 equals(重要)

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)。

equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
1.如果没覆盖equals方法,则通过比较该类的两个对象时,等价于通过"=="比较两个对象
2.类覆盖了equals方法,则就比较的是对象的内容

(11) get和post的 区别


GET用于获取信息,是无副作用的,是幂等的,且可缓存,POST用于修改服务器上的数据,有副作用,非幂等,不可缓存。GET和POST只是HTTP协议中两种请求方式
Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据。

(12)http和https


超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密
HTTPS在HTTP的基础上加入了SSL/TLS协议,SSL/TLS依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
        1、https协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。

        2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl/tls加密传输协议。

        3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

        4、http的连接很简单,是无状态的;HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全

(13)spring和springboot的区别


spring它解决了 Java 企业级开发的复杂度问题,所谓的复杂度问题,就是耦合度问题。
传统开发需要开发人员手动管理对象关系和生命周期,Spring 框架提出了两大核心:IOC 与 AOP。有效的管理了开发中对象的生命周期问题,也提供了与很多框架整合的工具。
但是,Spring 最大的弊端,需要大量的 XML 配置,不管项目整体大小,都需要大量的配置文件搭建架构。

SpringBoot 可以看作是对 Spring 框架的扩展,
可以快速搭建独立的 Spring 应用程序。它内嵌了 Tomcat,Jetty 等容器,项目是一个 jar 包,通过 Application 入口类快速运行整个项目,提供了 Pom 简化 Maven 的配置,避免了项目包与包的冲突,对第三方技术做了很好的封装。
我认为最重要的一点是,减少了大量的 XML 配置。SpringBoot 基于约定优于配置的理念,原先大量的配置都可以省去,并且不推荐 XML 配置,改为 Java 配置。主要的配置可以写在 apaplication.properties 文件中。

(14)spring bean 容器的生命周期流程如下:


1、Spring 容器根据配置中的 bean 定义中实例化 bean。
2、Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
3、如果 bean 实现BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用setBeanName()。
4、如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。
5、如果存在与 bean 关联的任何BeanPostProcessors,则调用 preProcessBeforeInitialization() 方
法。如果存在与 bean 关联的InitializingBean,则执行afterPropertiesSet方法
6、如果为 bean 指定了 init 方法( 的 init-method 属性),那么将调用它。
7、最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用
postProcessAfterInitialization() 方法。8、如果 bean 实现DisposableBean 接口,当 spring 容器关闭
时,会调用 destory()。
9、如果为bean 指定了 destroy 方法( 的 destroy-method 属性),那么将调用它。
 


(15)属性选择器


a[target=_blank]
[title~="flower"] title包含flower
[class|="top"] class以top开头
[class^="top"]
[class$="test"] class以test结尾
[class*="te"] class包含te

[attribute]    [target]    选择带有 target 属性的所有元素。
[attribute=value]    [target=_blank]    选择带有 target="_blank" 属性的所有元素。
[attribute~=value]    [title~=flower]    选择带有包含 "flower" 一词的 title 属性的所有元素。
[attribute|=value]    [lang|=en]    选择带有以 "en" 开头的 lang 属性的所有元素。
[attribute^=value]    a[href^="https"]    选择其 href 属性值以 "https" 开头的每个 <a> 元素。
[attribute$=value]    a[href$=".pdf"]    选择其 href 属性值以 ".pdf" 结尾的每个 <a> 元素。
[attribute*=value]    a[href*="w3school"]    选择其 href 属性值包含子串 "w3school" 的每个 <a> 元素。

(17) 前段传给后端string 类型的数据转为date


解决方案
 在实体Date类型字段的数据上加@JsonFormat注解

@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
复制
使用String转Date类型的工具类,并使用@Component将其注册为组件(要跟controller的父目录同级)


(19)线程的状态

1.新建( new )
当新建一个线程后,该线程处于新建状态,此时它和 Java对象一样,仅仅由Java 虚拟机为其分配内存空间,并初始化成员变量。同时已经有了相应的内存空间和其他资源,但是尚未运行start()方法。

2.就绪(Runnable )
当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进人就绪状态。在线程运行之后或者从阻塞状态回来后,也返回到就绪状态。

3. 运行( Running )
线程创建之后就具备了运行条件,当Java虚拟机(JVM)将CPU的使用权切换给该线程时,此线程就开始了自己的生命周期,Thread类的子类中的run()方法就会立即执行。

当一个线程进入“运行”状态下,并不代表它可以一直执行到run()结束。因为事实上它只是加入此应用程序执行安排的队列中,正在等待分享CPU资源,也就是等候执行权,在何时给予线程执行权则由JVM决定,同时也由线程的优先级决定。

4.阻塞( Blocked )
阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分为以下3种。

(1)等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。

(2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

( 3)其他阻塞:运行的线程执行sleep()或join()方法,或者发出了IO 请求时,JVM 会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

5.死亡(Dead )
处于死亡状态的线程不具有继续运行的能力,线程的死亡有两种,一种是正常运行的线程完成了它全部工作(run()方法中全部语句),另一种是线程被提前强制终止,即强制run()方法结束。所谓死亡状态就是线程释放了分配给线程对象的内存。不要试图对死亡的线程调用start()方法来启动它,死亡线程不可能再次运行。

(20)创建线程的方式


1)继承Thread类创建线程
    1】d定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。
    2 )通过new 子类.start()来启动创建线程

2)实现Runnable接口创建线程
    1】定义Runnable接口的实现类,一样要重写run()方法,这个run()方法和Thread中的run()方法一样是线程的执行体
    2】创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象
    3】第三部依然是通过调用线程对象的start()方法来启动线程
3)使用Callable和Future创建线程
        
    1】创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例(从java8开始可以直接使用Lambda表达式创建Callable对象)。
    2】使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值
    3】使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口)
    4】调用FutureTask对象的get()方法来获得子线程执行结束后的返回值


4)使用线程池例如用Executor框架


(21)数组与集合的区别


区别:

数组特点:大小固定,只能存储相同数据类型的数据

集合特点:大小可动态扩展,可以存储各种类型的数据

数组和集合都是java中的容器。

1、数组声明了它容纳的元素的类型,而集合不声明。

2、数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了,而且生命周期也是不能改变的,还有数组会做边界检查,如果发现有越界现象,会报RuntimeException异常错误,当然检查边界会以效率为代价。

而集合的长度是可变的,可以动态扩展容量,可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求。

3、数组的存放的类型只能是一种,Object数组可以存多种类型;集合存放的类型可以不是一种,只可以存储对象,也可以存储基本数据类型,但必须是基本类型的包装类(不加泛型时添加的类型是Object)。

(22)@Resource 和 @Autowired


这两个注解都是注入bean的时候用的,但是有一些区别:

1,来源不同:Resource是JDK提供的,而Autowired是Spring提供的
2,会不会报错:Resource不允许找不到bean的情况,而Autowired允许(@Autowired(required = false))
3,指定name的方式不同:@Resource(name = "xxx"),@Autowired()@Qualifier("xxx")
4,找bean的方式不同:Resource默认通过name查找,而Autowired默认通过type查找

(23)中断线程的三种方式


自定义中断标识符,停止线程。比如说定义一个类型为boolean的静态变量 isInterupt来判断线程是否中断  这种中断方法的缺点就是不能及时的中断线程.,它只能在下一轮运行时判断是否要终止当前线程
使用线程中断方法 interrupt 停止线程。使用 interrupt 方法可以给执行任务的线程,发送一个中断线程的指令,它并不直接中断线程,而是发送一个中断线程的信号,把是否正在中断线程的主动权交给代码编写者。相比于自定义中断标识符而然,它能更及时的接收到中断指令
使用 stop 停止线程。
其中 stop 方法为 @Deprecated 修饰的过期方法,也就是不推荐使用的过期方法,因为 stop 方法会直接停止线程,这样就没有给线程足够的时间来处理停止前的保存工作,就会造成数据不完整的问题,因此不建议使用。而自定义中断标识也有一些问题,所以综合来看,interrupt 方法才是最理想的停止线程的方法,接下来我们一起来看它们的具体差异

                                                                    

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值