java面试题

面试流程:

​ 1.1 简单的自我介绍
我是xxx,工作了xxx年,我在哪个公司工作,先后做了xxx项目,在其中担任了xxx角色,
1.2 你简单介绍一下xxx项目
为了解决xxx问题,开发了一套xxx系统,该系统主要由哪些部分组成,我参与了xxx模块的开发,简单介绍一下项目的整体结构,(用了什么技术),就要求你说一下这个模块的业务级设计
1.3 会问一下java的专业技能
1.4 你还有什么要问我的嘛?
公司要做的项目?项目会使用什么技术?

设计模式:

​ 单例模式:
饿汉式:没有并发问题
懒汉式: 有并发问题
动态代理(Proxy):

工厂模式:
代理模式:
构造者模式:
责任链模式:
适配器模式:
观察者模式:
其他模式:

事务隔离级别与事务传播属性:

TCP三次握手原理:

linux:

​ centos6服务命令: service 服务名 操作 || 设置自启动: chkconfig –level 5 服务名 on ||查看服务 chkconfig –list |grep xxx
centos7服务命令: systemctl 操作 服务名 || 查看服务 :systemctl list-unit-files ||设置自启动:systemctl enable 服务名
常用指令:ls系列: ls -­l l参数代表以列表的方式显示。
ls -a ­a参数代表all的意思,表示把所有的文件都罗列出来,包括隐藏文件,点号开头的在Linux中都表示隐藏文件。
stat命令: 查看文件的访问时间,修改时间等
top命令:查询系统内存占用较高的进程与进程id
pwd命令: pwd 是英文print working directory 显示当前所在路径。
which命令:寻找可执行文件 ,并在PATH环境变量里面寻找 例如:which reboot/java
touch命令: 将每个文件的访问及修改时间都更新为目前的时间。如果文件不存在,则创建一个字节数为0的文件。
‐a #只更新访问时间,不改变修改时间
‐c #不创建不存在的文件
‐m #只更新修改时间,不改变访问时间
‐r file #使用文件file的时间更新文件的时间
‐t #将时间修改为参数指定的日期,如:07081556代表7月8号15点56分
rmdir 命令
mkdir
rm 命令 : 可以用来删除普通文件,也可以用来删除目录,特别用来删除目录中嵌套有子目录的目录文件。
常用参数:
‐f ‐‐force #强制删除,不询问是否要删除。
‐r ‐‐recursive #递归删除,包括文件夹中的内容。
mv命令: 可以用来移动文件夹或者文件,也可以用来更改文件名。
mv file / #把文件file移动到根目录中
mv file file_bak #把文件file重命名为file_bak。
cp命令:示拷贝文件。
可以用来拷贝普通文件:cp file file_bak #拷贝一份file为file_bak
可以用来拷贝目录 :cp dir dir_bak ‐r #拷贝一个目录dir为dir_bak, ‐r参数代表递归拷贝,把dir目录中的文件也拷贝过去
cat命令:用来查看文件内容,以及将几个文件连成一个文件
不填文件参数,默认的情况下是从标准输入中获取内容
查看文件: cat fileName
将文件file1 file2连成file3文件: cat file1 file2 > file3
find 命令:直接在全文件系统上搜寻,功能强大,速度慢。
find [path] [‐option] [ ‐print ‐exec ‐ok command ] {} ;
find / ‐name filename #在根目录里面搜索文件名为filename的文件
find /etc ‐name s #在目录里面搜索带有s的文件
find /etc ‐name S #在目录里面搜索以s结尾的文件
find /etc ‐name s
#在目录里面搜索以s开头的文件
find / ‐amin ‐10 #在系统中搜索最后10分钟访问的文件
find / ‐atime ‐2 #查找在系统中最后48小时访问的文件
find / ‐mmin ‐5 #查找在系统中最后5分钟修改过的文件
find / ‐mtime ‐1 #查找在系统中最后24小时修改过的文件
find / ‐ctime ‐1 #查找在系统中最后24小时被改变状态的文件
find / ‐user username #查找在系统中属于用户username的文件
find / ‐group groupname #groupname 查找在系统中属于groupname的文件
find / ‐empty #查找在系统中为空的文件或者是文件夹
find / ‐inum 3 #查找inode号为3的文件
find / ‐type d #查找为文件类型为文件夹的文件d为文件夹
grep 命令:搜索内容中是否包含指定的字符串,并打印出该行。
‐i ‐‐ignore‐case #忽略字符大小写的差别。
‐v #输出没有指定字符串的文件
‐c #只输出匹配行的计数。
‐R #连同子目录中所有文件一起查找。
ln命令:ln是英文单词link的缩写,用来创建链接的命令。
Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link)。默认情况下,ln命令产生硬链接
给flie文件创建一个硬链接:touch file ln file file_hard
给file文件创建一个软链接:touch file ln ‐s file flie_soft
wc 命令:Word Count的缩写,命令的功能为统计指定文件中的字节数、字数、行数,并将统计结果显示输出。
‐c #统计字节数。
‐l #统计行数。
‐m #统计字符数。这个标志不能与 ‐c 标志一起使用。
‐w #统计字数。一个字被定义为由空白、跳格或换行字符分隔的字符串。
‐L #打印最长行的长度。
du命令:Disk usage的缩写,表示计算某个目录在硬盘中所占的空间大小
df命令:df是英文Disk free的缩写,用来统计磁盘是使用情况。
gedit命令:gedit全称 GNU edit 是一个文本编辑器,类似windows里面的txt文本编辑器。编辑file文本。
管道命令:command 1 | command 2 他的功能是把第一个命令command 1执行的结果作为command 2的输入。
重定向 :使用>表示重定向。1>表示标准输出重定向,2>表示标准错误重定向。默认情况下>表示输出重定向。
后台运行:Linux中可以使用&,让程序在后台运行。如:cat &

git分支相关命令:

​ 创建分支:
git branch <分支名>
git branch -v 查看分支
切换分支:
git checkout <分支名>
一步完成: git checkout -b <分支名>
合并分支:
先切换到主干:git checkout master
git merge <分支名>
删除分支:
先切换到主干: git checkout master
git branch -D <分支名>

redis持久化类型:

​ RDB: 在指定时间范围内将内存中的数据集快照写入磁盘,恢复时是将快照文件直接读入内存
fork一个子线程进行持久化,先将数据写入一个临时文件,带持久化完成,再将这个临时文件替换成上次持久化好的文件,
优点:节省磁盘空间,恢复速度快,缺点:在数据量大的时候比较小号性能,在备份周期中进行备份,如果redis进程挂掉,就会失去最后一次快照的所有更改
AOF: 以日志的方式来记录每个写操作只做增量操作
优点:备份机制更稳健,数据不易丢失,可读的日志文本,可以处理误操作;缺点:占用更多空间,恢复备份速度更慢,性能压力大,存在bug,没法恢复
使用场景:
缓存雪崩:
缓存击穿:
哨兵:
集群:

mysql:

​ 索引 –>是数据结构:
优势:检索查询快,排序快
劣势:做所有的写操作,速度慢;占用更多磁盘空间(索引)
什么时候需要创建索引:
主键自动创建索引
频繁查询的字段建索引
外键必须建索引,表的联合查询变快
单键、组合索引的选择问题,组合索引的性价比更高
查询中排序的字段,排序通过索引速度回变快
查询中统计或分组的字段
什么时候不适合建立索引:
表记录太少
经常需要增删改的表或者字段
where 条件里用不到的字段
过滤性不好的不适合建立索引
调优:
innodb:
mysiam:

JVM GC:

​ 发生在heap(堆)里
GC是什么:
次数上频繁收集young区:minor gc
次数上较少收集old区:full gc
基本不变 : perm(永久代)
GC四大算法:
1.引用计数法 :有对象被引用gc就不进行回收,无法解决循环引用
2.复制算法: 发生在年轻带中;把内存分为2块,每次只使用其中的一块,当着一块使用完后,就把还存活着的对象复制到另一块去
3.标记清除: 会产生大量的内存碎片
4.标记整理: 效率低,但是内存连续,不会产生额外的gc
5.分代收集:
如何判断对象可以被回收:
引用计数法:(有问题,不建议使用)致命缺点,相互循环引用
可达性分析:通过一系列的被称为“GC root”的对象作为起点从这些起点开始向下搜索,节点走过的路径称为应用链,当一个对象到GCroot没有任何引用连相连,则证明该对象不可用
单点登录:(一处登录,多处使用) 多在分布式系统中使用
实际中的案例:去动物园观景,要买票,检票员要检票,你买了票带着过去检票通过了才能在动物园内任意观景。

消息对列:

​ 功能:解耦削峰异步通信
弊端:消息的不确定性:延迟队列,轮询技术来解决该问题

进程和线程:

死锁:

volatile:

​ 如何保证内存可见性:

jvm

jvm工具:

​ jvisualvm:
jconsole:
jmap: jmap -dump:format=b.file=temp.hprof 转存堆
jstack: jstack pid
jps: jps
jstat:

jvm参数:

​ -Xms:
-Xmx:
-XX:+printGCDetails:
-XX:MetaSpace:
-XX:HeapDumpOnOutOfMemeoryError:
-XX:HeapDumpPath=路径

类加载机制:

​ 全盘负责委托: 当一个classloader加载一个类的时候,除非显示的使用另外一个classloader,该类所依赖和引用的类也有这个classloader载入
双亲委派机制:指先委托父类加载器寻找目标类,再找不到的情况下在自己的路径中查找并载入目标类
双亲**优势:沙箱安全机制:比如自己写的String.class不会被加载,这样可以防止核心库被随意篡改
避免类的重复加载:当父classcloader加载了该类的情况下,就不需要子类在加载一次

应用服务器:

jetty:

tomcat:
    目录: bin 可执行文件
           conf 配置文件  server.xml  tomcat-user.xml  web.xml 
           lib: 存放依赖的jar包
           logs:日志
           temp:临时文件
           webapps: web部署文件夹
    源码:  下载,不说
            运行:创建maven工程,引入tomcat依赖,idea导入工程,启动tomcat(找到main方法,startup里有个Bootstrap类里面main方法,添加启动类,
                添加运行参数,-Dcatalina.home,日志,配置文件),就这样启动会出现500错误,不能编译jsp,原因是
                再启动源码的时候并没有区启动jsp的初始化的解析器,解决方法在tomcat的源码contextconfig中的configureStart函数中手动将jsp解析器初始化
                context.addservletcontainerInitializer(new JsperInitializer,null)
    http工作原理:
            用户请求浏览器,浏览器向服务器发起tcp连接,服务器接收请求并建立连接,浏览器生成http数据包,发送http数据包,
            服务器解析http格式数据包,执行请求,服务器生成http格式的数据包,服务器发送响应数据包给浏览器,浏览器解析http
            格式的数据包,最后渲染成html响应给用户
            服务器端 主要是:接收连接,解析请求数据包,处理请求,发送响应
    servlet工作流程:
            为了解耦合,http服务器不能直接调用servlet,而是把请求转发给servlet容器来处理。
            1.定位servlet  2.加载servlet  3.调用servlet 4.响应给http服务器
    连接器和容器: 连接器->接收请求和返回响应  容器->处理逻辑

启动流程:
    bin ->start.bat->Bootstrap->catalina->server->service->Excutor->Engine->host->context->connector->protocolHandler
源码解析:
    LifeCircle:由于所有的组件都存在初始化启动销毁等生命周期,所以tomcat在设计的时候就基于生命周期管理抽象出来一个接口
    Lifecircle,其余的组件都实现了这个接口

nginx:

spring:

spring bean 作用域之间有什么关系:
bean的注入:
ioc:
aop:

springboot

springmvc:

mybatis:

​ 实体类字段与数据库表字段不一致解决:
1、sql语句给要查询的字段加别名
2.设置开启驼峰命名规则,这个有局限性,数据库字段名是下划线可以用
3.在映射mapper.xml文件中设置resultmap 给每个字段添加相应的实体类的映射
什么是mybatis:orm框架,用于实现 面向对象编程语言中不同类型系统的数据转换,替换了jdbc的作用
问题: JDBC 数据库
1.sql
2.连接池
3.硬编码
源码:官网源码demo
技术本质:
数据库源:driver,url,password,username
执行语句:crud
操作:connection,prepareStatement,resultSet
源码验证:
把xml的数据放在configuration的varibles对象里面的
步骤:
1,获取SqlSessionFactory :SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));》
public SqlSessionFactory build(Reader reader, String environment, Properties properties) 》
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
这段代码的作用是使用上一步读取的configuration.xml字符输入流,实例化一个xml配置解析器(XMLConfigBuilder),并且我们已经知道 environment, properties的值为null;
在XMLConfigBuilder对象的实例化过程中初始化一个非常重要的对象:Configuration,而Configuration对象承载了configuration.xml中的所有配置内容
代码:return build(parser.parse());
     1,parser.parse()返回一个Configuration对象实例,这是一个及其重要的方法,因为解析configuration.xml并生成Configuration对象,都是在这个方法里完成的
2,调用SqlSessionFactoryBuilder的public SqlSessionFactory build(Configuration config)方法创建一个SqlSessionFactory对象实例,我们来看一下build(Configuration config)方法的内容:
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
},在这个方法里面又返回了一个以configuration为参数的实例化DefaultSqlSessionFactory对象
  2,获取SqlSession: 关键代码:SqlSession sqlSession = getSessionFactory().openSession();
从上一部获得defaultsqlsessionfactory,看一下openSession方法,public SqlSession openSession() {//直接调用了openSessionFromDataSource方法 return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);}
这里SqlSession也获取成功了,获取到的是DefaultSqlSession的示例对象。
  3,获取UserDao代理类
sqlSession是DefaultSqlSession的实例化对象,那么就来看一下getMapper方法的源码
public T getMapper(Class type) {
// 这里的configuration就是一开始一直陪伴着我们的那个Configuration实例对象
return configuration.getMapper(type, this);
}
1,为什么在以前的代码流程中从来没有addMapper,而这里却有getMapper?
xmlmapperBuilder类里的bindMapperForNamespace方法里使用了addMapper方法,从DefaultSqlSession getMapper方法中,可以找到 MapperRegistry 中:可以看到一个获取java的动态代理类的写法(
MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);

     2,UserDao明明是我们定义的一个接口类,根本没有定义实现类,那这个userMapper是什么?是mybatis自动为我们生成的实现类吗?
xmlmapperBuilder类里的bindMapperForNamespace方法,用到了代理模式
boundType = Resources.classForName(namespace);

                 不妨在你的脑海中回顾一下JAVA设计模式-动态代理(Proxy)示例及说明中实现动态代理的关键因素:

                1,一个接口

                2,实现了接口的类

                3,一个调用处理类(构造方法中要传入2中的类的实例对象)

                4,调用Proxy.newProxyInstance方法获取代理类实例化对象

            parser.parse方法源码:
             在这个parseConfiguration方法中,将不同节点的解析工作又交给了不同的方法完成。说了这么多话,看了这么多代码,终于开始解析mybatis的核心配置文件configuration.xml文件了

             从configuration.xml文件中我们看到,在根节点configuration中存在四个子节点,分别是:properties,settings,environments,mappers。那么对应到parserConfiguration方法中,本工程用到的解析方法就是:

              1,//解析<properties resource="dbConfig.properties"></properties>节点
                propertiesElement(root.evalNode("properties"));
              2,//解析<settings></settings>节点
                settingsElement(root.evalNode("settings"));
              3,//解析environments节点
                environmentsElement(root.evalNode("environments"));
              4,//解析mappers节点
                mapperElement(root.evalNode("mappers"));
              我们就按照这四个方法逐一的去跟踪
            解析properties节点:
             首先先看一下configuration.xml中properties节点的内容
            <!-- 指定properties配置文件, 里面配置的是数据库相关 --> <properties resource="dbConfig.properties"></properties>
            很明了,就是解析出dbConfig.properties文件名,并读取dbConfig.properties文件的内容,放入defaults中。最后把defaults放入parser.variables和configuration.variables中
            解析mappers文件
            全部方法都在XMLConfigBuilder类里面,解析settings配置,environment配置,数据源配置等
            实例化mapper解析器:XMLMapperBuilder 
                代码:XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
                查看mapper解析器XMLMapperBuilder类的声明可以发现,mapper解析器类XMLMapperBuilder和xml配置解析器XMLConfigBuilder同时继承了父类BaseBuilder。其实后面还有几个类也继承了父类BaseBuilder。
            执行解析mapper文件,即解析mapper/userDao-mapping.xml文件
                 代码:mapperParser.parse();

      4,执行查询
            result = sqlSession.selectOne(command.getName(), param);
            selectOne是调用selectList执行查询的,只不过是取了返回值的第一个元素
            mapper文件中的每一个select,insert,update,delete标签,都会解析成一个MappedStatement类的实例对象吗?而且这个实例对象是存放在configuration中的。
            然后执行第7行代码,这里的executor是CachingExecutor实例对象。到这里SqlSession中的代码流程就结束了,我们进入Executor中的执行过程。
            1,sql语句是什么时候,在哪里执行的?

   2,我们传入参数id是怎么参与执行的?
1.mybatis是如何获取数据库源的?
答:sqlsessionFactoryBuilder.buid()方法-》xml.XMLConfigBuilder.parseconfiguration
->XMLConfigBuilder.environmentsElement->Configuration.setEnvironment,就获取到数据库源了
2.如何获取到执行语句的?
答:
3.mappers加载mapper文件有几种方式? 4种,优先级分别是:package,resource,url,class

实现原理:利用反射打通Java类与SQL语句之间的相互转换。
3. MyBatis的主要成员

    Configuration MyBatis所有的配置信息都保存在Configuration对象之中,配置文件中的大部分配置都会存储到该类中

    SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能

    Executor MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护

    StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数等

    ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所对应的数据类型

    ResultSetHandler 负责将JDBC返回的ResultSet结果集对象转换成List类型的集合

    TypeHandler 负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射和转换

    MappedStatement MappedStatement维护一条<select|update|delete|insert>节点的封装

    SqlSource 负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回

    BoundSql 表示动态生成的SQL语句以及相应的参数信息
接口Mapper内的方法能重载(overLoad)吗?(重要) 不能
原因:在投鞭断流时,Mybatis使用package+Mapper+method全限名作为key,去xml内寻找唯一sql来执行的。类似:key=x.y.UserMapper.getUserById,那么,重载方法时将导致矛盾。对于Mapper接口,Mybatis禁止方法重载(overLoad)。

springcloud:

springcloud:

netty: 异步,基于事件驱动的网络应用框架,用以开发高性能高可靠的网络io程序,本质是一个 NIO框架
tcp协议下,面对client端的高并发应用 netty->NIO->jdk原生io和网络开发->tcp/ip

mq:

后续会更新….


Author: Juntech
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Juntech !
评论
  TOC