通过举栗子的方式来讲解面试题(可面试,可复习,可学习)
前言:
本文主要介绍了我们在面试中一些常见的问题,以及在我们学习过程中需要注意的重点地方。如果大佬目前在找工作,可以先看看问题,思考后再看答案,刚学到这里的同学也可以借着题目巩固一下哦。
如果文章有什么写的不对或者需要改进的地方,还请大佬不吝赐教。
小威在此感谢各位小伙伴儿的支持😘😘😘
🏠个人主页:小威要向诸佬学习呀
🧑个人简介:大家好,我是小威,一个想要与大家共同进步的男人😉😉🎁如果大佬在准备面试,可以使用我也在用的刷题神器哦刷题神器在这里
💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,我亲爱的大佬😘
@[toc]
🧁Java八大基本数据类型
Java八大基本数据类型有整型:short,int,long;字节型:byte;浮点型:float,double;字符型:char;布尔类型:boolean。
🍧面向对象的三个基本特征
面向对象的三个基本特征有封装,继承和多态。
🍰封装
封装:隐藏部分对象的属性和实现细节,对数据的访问只能通过对外公开的接口,控制在程序中属性的读和修改的访问级别,将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,通过这种方式对象对内部数据提供了不同级别的保护,防止程序中无关紧要的部分意外的改变或者出错的是用来对象的私有部分。
🍰继承
继承:让某个类型的对象获取另一个类型的对象的属性的方法,继承就是子类继承父类的特征和行为,使子类的对象具有父类的方法,或者子类从父类继承方法 是子类具有父类相同的行为 使用extends关键字实现继承 继承就是子类自动共享父类的数据和方法,是类与类之间的一种关系,提高了软件的可重用性和可扩展性。
🍰多态
多态:多态就是在声明的时候使用父类在实现或调用的时候使用具体的子类,不修改代码既可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态这就是多态 对于同一个行为,不同的子类对象具有不同的表现形式,多态的存在要满足三个条件:继承,方法重写,父类引用指向子类的对象。
🥧抽象类与接口的区别
首先解释什么是抽象类:
将类与类之间的共同特征提取出来,就可以形成抽象类。
抽象类不能直接实例化对象,但可以使用多态即父类的引用指向子类的对象,抽象类作为父类。
什么是接口:
接口可以看做特殊的抽象类,当然接口也无法实例化和创建对象,在使用时也可以使用多态,父类的引用指向子类的对象,这里的父类就是接口。
区别:
- 抽象类体现的是继承关系(extends),接口体现的是实现关系(implements),一个类可以实现多个接口,而类只能继承一个抽象类。
- 抽象类中可以定义,普通方法,静态方法,抽象方法,提供给子类使用,而接口中的方法都是抽象的,接口中的成员都有固定的修饰符。
- 抽象类中可以有构造方法,而接口中不可以有构造方法
- 抽象类中的抽象方法的访问类型可以是public,protected,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
🍨==和equals()方法的区别
1.==号是运算符,而equals()是方法;
2.==既可以比较基本类型的数据,也可以比较引用类型的数据,判断两个变量或实例是不是指向同一个内存空间。equals()只能比较引用类型的数据,用于检查对象的相等性,例如如果双等于号和equals()用于比较对象,当两个对象引用地址相同,双等于号则返回TRUE,而equals()方法可以返回TRUE或FALSE,主要取决于方法重写的实现。
3.==是指对内存地址进行比较 , equals()是对字符串的内容进行比较。
小提示:
String str = "xiaowei";
先在内存中找是不是有"xiaowei"这个对象,如果有,就让str指向那个"hello"
String s = new String("xiaowei");
和其它任何对象一样,每调用一次就产生一个对象,只要它们调用。
String str = “xiaowei”; 如果内存里没有"xiaowei",就创建一个新的对象保存"xiaowei". String str=new String (“xiaowei”) 就是不管内存里是不是已经有"xiaowei"这个对象,都新建一个对象保存"xiaowei"。
🧁Mybatis中#{}和${}的区别
首先说一下SQL注入
SQL注入是一种代码注入技术,用于攻击数据驱动的应用,恶意的SQL语句被插入到执行的实体字段中,攻击者在界面的表单信息或URL上输入一些奇怪的SQL片段(例如“or ‘1’=‘1’”这样的语句),有可能入侵参数检验不足的应用程序。
所以两种方式的区别就体现出来了:
1.#{变量名}可以进行预编译、类型匹配等操作,#{变量名}会转化为jdbc的类型。#方式能够很大程度防止sql注入;
2.$ {变量名}不进行数据类型匹配,直接替换。 方式无法方式sql注入。$ 方式一般用于传入数据库对象,例如传入表名;
3.#会自动加双引号,$不会加双引号。
这两个符号在mybatis中最直接的区别就是:#相当于对数据加上单引号,$相当于直接显示数据(只讨论字符串类型的)。
举个栗子😉😉😉:
-
#对传入的参数视为字符串,也就是它会预编译,
select * from user where name = #{name}
,比如我传一个xiaowei,那么传过来就是select * from user where name = 'xiaowei';
-
$ 将不会将传入的值进行预编译,
select * from user where name=${name}
,比如我传一个xiaowei,那么传过来就是select * from user where name = xiaowei;
-
#的优势就在于它能很大程度的防止sql注入,而 $ 则不行。比如:用户进行一个登录操作,后台sql验证式样的:
select * from user where username=#{name} and password = #{pwd}
,如果前台传来的用户名是“xiaoweihaoshuai”,密码是 “1 or 1=1”,用#的方式就不会出现sql注入,而如果换成$方式,sql语句就变成了select * from user where username=wang and password = 1 or 1=1
。这样的话就形成了sql注入。
🍭@Autowired和@Resource的区别
@Autowired是spring框架提供的实现依赖注⼊的注解,主要⽀持在set⽅法,field,构造函数中完成bean注⼊,注⼊⽅式为通过类型查找bean,即byType类型的,如果存在多个同⼀类型的bean,则使⽤@Qualifier来指定注⼊哪个beanName的bean。
与JDK的@Resource的区别:@Resource是基于bean的名字,即beanName类型的,来从spring的IOC容器查找bean注⼊的,⽽@Autowried是基于类型byType来查找bean注⼊的。
与JDK的@Inject的区别:@Inject也是基于类型来查找bean注⼊的,如果需要指定名称beanName,则可以结合使⽤@Named注解,⽽@Autowired是结合@Qualifier注解来指定名称beanName。
1.@Autowired、@Inject是默认按照类型匹配的,@Resource是按照名称匹配的。如在spring-boot-data项⽬中⾃动⽣成的redisTemplate的bean,是需要通过byName来注⼊的。如果需要注⼊该默认的,则需要使⽤@Resource来注⼊,⽽不是@Autowired。
2.对于@Autowire和@Inject,如果同⼀类型存在多个bean实例,则需要指定注⼊的beanName。
3.@Autowired和@Qualifier⼀起使⽤,@Inject和@Name⼀起使⽤。
🍬死锁,乐观锁和悲观锁的区别
首先介绍下什么是死锁:
两个或两个以上线程,在争抢资源中出现都在等待对方执行完毕才能继续往下执行的时候就发生了死锁,最后这些线程都陷入了无限的等待中。
🥛计网三次握手四次挥手
由于之前详细写过相关的文章,所以直接给小伙伴儿们附上链接嘿嘿🤩🤩三次握手四次挥手详解
🍡悲观锁
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞,直到它拿到锁。
悲观锁又叫互斥同步锁,它为了确保结果的正确性,会在每次获取到数据后,都会将其锁住,因此当其他线程也来访问时,就会进入阻塞状态,这样就可以防止其他线程访问该数据,从而保证数据的安全性。
Java中我们常用的 Synchronized 及 RenntrantLock 都是悲观锁。
在数据库很多地方就用到了这种锁机制,比如行锁,表锁,读锁,写锁等。
举个栗子😏😏😏:
select * from user where id='1' for update
这条 sql 语句锁定了user表中所有符合检索条件(id=‘1’)的记录。这条数据就被当前事务锁定了,其它的事务必须等本次事务提交之后才能执行,也就是其他线程进入阻塞状态。 这样可以保证当前的数据不会被其它事务修改。(前提是id字段一定是主键或者唯一索引,不然是锁表,会出事的。)
对于悲观锁来说,只能有一个事务占据资源,其他事务被挂起等待持有资源的事务提交并释放资源,CPU就会将这些得不到资源的线程挂起,挂起的线程也会消耗CPU的资源,尤其是在高井发的请求中。
一旦该线程提交了事务,那么锁就会被释放,这个时候被挂起的线程就会开始竞争资源,那么竞争到的线程就会被 CPU 恢复到运行状态,继续运行。
在高并发的过程中,使用悲观锁就会造成大量的线程被挂起和恢复,这将十分消耗资源,所以使用悲观锁性能非常不佳。
🍡乐观锁
乐观锁是一种思想,总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,只在更新的时候会判断一下在此期间别人有没有去更新这个数据。如果一个线程在修改数据时,没有其他线程干扰,那就会正常执行修改;而如果该数据已经被其他线程修改过,那当前线程为了保证数据正确性,就会放弃或报错。
乐观锁是一种不会阻塞其他线程并发的机制,它不会使用数据库的锁进行实现,它的设计里面由于不阻塞其他线程,所以并不会引发线程频繁挂起和恢复,这样便能够提高并发能力,所以也有人把它称为非阻塞锁。
悲观锁或乐观锁并不是想要替代对方,也没有优劣之分,只是适用于不同的场景。 对于资源竞争较少(线程冲突较轻)的情况,使用乐观锁更佳。
🍵简述Spring的ioc
在不使用Spring开发之前,我们在完成一个项目时需要new很多对象,这些对象是我们之间创建出来的,并且这些对象可能也有一些依赖关系,比如说两个对象之间需要合作使用,这就会导致两个或多个对象之间的耦合度很高,那要降低对象之间的耦合度,就需要用到Spring的ioc了。
Spring的ioc,即控制反转(Inversion of Control),它不是一种新的技术,而是Spring的一种设计思想。在Spring中有专门的一个容器来创建和管理这些对象,并将对象依赖的其他对象注入到该对象中,这个容器一般被称为ioc容器。
我们创建的所有的类都会在Spring容器中登记,告诉Spring是什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 Spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 Spring 控制,所以这叫控制反转。
DI:即依赖注入(Dependency Injection)Spring容器加载配置文件之后,通过反射创建类的对象,并给属性赋值;Spring容器通过反射实现属性注入有三种方式:
- set方法注入
- 构造器注入
- 接口注入(不常用)
☕SpringMVC的工作流程
- 前端发送请求被前端控制器DispatcherServlet拦截
- 前端控制器调用处理器映射器HandlerMapping对请求URL进行解析,解析之后返回调用给前端控制器
- 前端控制器调用处理器适配器处理调用链
- 处理器适配器基于反射通过适配器设计模式完成处理器(控制器)的调用处理用户请求
- 处理器适配器将控制器返回的视图和数据信息封装成ModelAndView响应给前端控制器
- 前端控制器调用视图解析器ViewResolver对ModelAndView进行解析,将解析结果(视图资源和数据)响应给前端控制器
- 前端控制器调用视图view组件将数据进行渲染,将渲染结果(静态视图)响应给前端控制器
- 前端控制器响应用户请求
组件说明
DispatcherServlet:前端控制器,也称为中央控制器,它是整个请求响应的控制中心,组件的调用由它统一调度。
HandlerMapping:处理器映射器,它根据用户访问的 URL 映射到对应的后端处理器 Handler。也就是说它知道处理用户请求的后端处理器,但是它并不执行后端处理器,而是将处理器告诉给中央处理器。
HandlerAdapter:处理器适配器,它调用后端处理器中的方法,返回逻辑视图 ModelAndView 对象。
ViewResolver:视图解析器,将 ModelAndView 逻辑视图解析为具体的视图(如 JSP)。
Handler:后端处理器,对用户具体请求进行处理,也就是我们编写的Controller 类。
文章到这里就先结束了,如果大佬们喜欢此类文章的话,后面还会更新哟,制作不易,还请大佬们多多支持嘿嘿😉😉😉
如果文章中有写的不当或者需要改进的地方,还请大佬多多指正😊😊
最后小威再次感谢各位小伙伴儿的支持😘😘😘
- 点赞
- 收藏
- 关注作者
评论(0)