轻松搞定技术面系列 1——基础篇

本文出自
代码大湿
代码大湿css

有段时间没有更新新文章了,接下来想把文章的更新速度放慢点,主要是想写出更高质量的文章,最近收录了多年面试的经典题目,包括答案,本系列会持续更新。html


1 线程和进程的区别

1   资源占用:进程是系统资源分配的基本单位,进程拥有本身独立的内存空间,所属同一进程的各个线程共享进程的内存空间。线程的上下文切换更快。

2   调度和运行:线程是进程的实体,是系统调度的基本单位,线程的调度要依赖进程,不能单独运行。

2 谈谈Vector和ArrayList,LinkedList

相同:
都是实现了List接口,内部都是使用的动态数组,元素是有序的,能够根据索引来访问元素。

不一样:
1  Vector是线程安全的,ArrayList和LinkedList是非线程安全的,因此ArrayLsit的执行的效率要高于Vector。
2  Vector当须要增长长度的时候,会增长原来长度的1倍,而让ArayList会增长原来的一半。
3  Vector设置了增加空间的方法,ArrayList没有设置此方法。
4  LinkedList是使用的双向链表,继承了Deque接口。

这2者和LinkedList的优缺点:
很明显,LinkedList的优势是能够实现元素的插入和删除操做。而Vector和ArrayList能够实现快速的元素的随机访问。java


3 谈谈HashMap和HashTable

1  HashTable是线程安全的,HashMap是线程非安全的,HashMap效率会比HashTable高。
2  HashTable不能有null,HashMap能够用null作key和value。
3  2者均可以使用iterator遍历,而HashTable还可使用enumeration。
4  HashTable继承比较老的Dictionary,HashMap继承AbstractMap。尽可能使用ConcurrentHashMap替换HashTable,由于前者效率更高。
5  HashTable的初始容量是11,扩容的方式是2*old+1。而HashMap初始容量是11,并且必定是2的倍数。

4 String,StringBuilder和StringBuffer

1  String是final修饰的字符串常量,对象内容不可变。后2者都是字符串变量,内容能够改变。
2  StringBuilder是非线程安全的,StringBuffer是线程安全的。因此StringBuilder的执行效率要高于StringBuffer。
3  StringBuilder和StringBuffer都是继承自AbstractStringBuilder。

5 sleep()和wait()方法

1  sleep是Thread的方法,wait是Object的方法。
2  sleep会暂停线程的执行,可是不会释放锁,到了指定时间会自动释放,,而wait会释放锁,让线程进入等待锁定池。
3  sleep须要捕获异常,而wait不用。
4  sleep能够在任何地方使用,而wait只能在同步块或者同步方法中使用。

6 UDP和TCP

1  TCP传输数据以前须要创建链接,UDP是传送数据包,不须要创建链接。
2  TCP提供可靠的传输,并且利用滑动窗口技术还提供差错检测,数据重传等服务。
3  TCP是传输的二进制字节流,UDP传输数据包,并且UDP不会提供拥塞控制,当数据传输量很大的时候,并不会下降发送端的传输速率。
4  TCP提供的是端到端的服务,UDP提供一对多,多对一,多对多的服务
5  TCP数据包的消耗比较大,而UDP数据包消耗会很小。

7 类的加载机制

类的加载顺序是:linux

加载->验证->准备->解析->初始化->使用->卸载
其中前5个阶段是类的加载阶段。

加载:git

1  获取classes文件(经过类的全限定名)或者网络中的二进制字节流。
2  将二进制的静态存储结构转换为方法区的动态存储结构。
3  在堆中生成Class对象,做为对方法区的访问接口。

验证:程序员

主要验证二进制文件的格式是否有错误。

准备:github

这个阶段为类的static变量分配内存,并对其赋予默认0值,只是针对static的类变量。若是是final和static同时修饰。此时就为其分配程序中指定的值。

解析:面试

将符号引用转换为直接引用。

初始化:算法

真正意义上执行程序中的代码。为变量赋予程序中指定的值。

8 gc回收算法

1  标记-清理:先标记存活的对象。而后将未标记的须要清理的对象清理掉,,效率低下,会产生内存碎片。
2  复制算法:将堆内存划分为2部分,将存活的正在使用的对象复制到另一个内存区域,消除了内存碎片。
3  标记-整理:标记存活的对象,而后将存活的对象向堆内存的一边移动,消除了堆内存的内存碎片。
4  分代回收算法:将堆内存划分为,年轻代(Eden,Survivor from,Survivor to),年老代,永久代。而后根据不一样内存区域中对象的生命周期来使用不一样的回收算法。通常年轻代(由于存活对象少)使用复制算法(minor gc)。年老代使用标记-整理算法(major/full gc)。

9 gc回收器

Serial收集器通常是用在Client的虚拟机。有年轻代和年老代。sql

Serial:年轻代的垃圾回收器。使用复制算法。
Serial Old:年老代的收集器,使用标记整理算法。

Parallel收集器

Parallel Scanvage收集器:年轻代的收集器,使用复制算法。目标是获取最大的吞吐量。
Parallel Old收集器:年老代的收集器,使用标记-整理算法。

CMS收集器(concurrent mark-sweep)

用在服务器端的收集器。目标是得到最短的用户停顿时间。

g1收集器

最前沿科技的成果,可是内存布局和传统的内存布局不同。

10 TCP的3次握手和4次挥手

TCP的创建的三次握手:

这里写图片描述

原始状态为Closed状态,须要创建链接的时候,
第一次握手

Client将数据包的SYN为置为1,序列号seq为J,将数据包发送服务server,此时Client的状态为SYN_SENT。

第二次握手

server接受数据包后,检查到SYN=1,知道client须要创建链接。server发送数据包,将SYN=1,seq=k,ACK=J+1   。server状态为SYN_RCVD。

第三次握手

Client收到数据包后,发送数据包,ACK=k+1。server收到数据后,检查ACK的值无误,链接创建。进入established。

TCP断开的四次挥手:

这里写图片描述

原始状态为established
第一次挥手

client发送FIN数据包。客户端进入FIN_WAIT_1。

第二次挥手

server收到数据包后。发送ACK确认包。server进入CLOSED_WAIT。client收到数据后检查ACK无误,client进入FIN_WAIT_2。

第三次挥手

server发送FIN数据包。server进入LAST_ACK。

第四次挥手
client收到数据包后发送ACK包,client进入TIME_WAIT。client等待2MSL后,若是server没有反应,则进入Closed状态。


11 B(B-)树和B+树

M阶B(B-)树有如下几点特性:

1   若是这棵树不是空树,根节点至少有2个子节点。
2   中间节点至少有ceil(M/2)个子节点。
3   非叶节点最多有M个子节点。
4   有k个关键字的节点有k+1个子节点。
5   全部叶子节点都在同一层。

这里写图片描述


12 数据库事务的隔离级别

数据库事物有4个隔离级别(如下级别依次提升)

READ UNCOMMITTED:读取未提交数据,此级别会形成脏读,不可重复读,幻读。
READ COMMITTED:读取提交数据,消除了脏读,但仍是会有不可重复读,幻读。大部分数据库都是这个隔离级别。oracle,sqlserver
Repeatable read:重复读,消除了脏读和不可重复读。会有幻读。Mysql是这个隔离级别。
Serializable:最高隔离级别,消除了幻读。

13 数据库索引

数据库索引有汇集索引和非汇集索引。

汇集索引:汇集索引是表中的记录的物理顺序与索引的key的顺序相同,汇集索引是惟一索引,一个表只能有一个索引。相对于非汇集索引,汇集索引提供更快的查询速度。
非汇集索引:汇集索引是表中的记录的物理顺序与索引的key的顺序不相同。不是惟一索引。

14 JVM堆和栈

堆:解决程序的存储问题,存储运行时的对象,是全部线程共享的。
栈:解决运行问题,存储单个线程的本地变量,运行状态,和返回结果。线程运行结    束,栈也会随着消失。

15 JVM运行时方法区

JVM运行时将内存区域分为

1  程序计数器:是线程隔离的,只是线程下一条将要执行的指令的位置。
2  JVM栈:每一个线程都有本身的虚拟机栈,主要存储线程的本地变量,天然是线程隔离的。
3  堆:存储程序中全部的对象,是全部线程能够共享的内存区域。
4  方法区:存储类的信息,类变量(static变量),是全部线程共享的。

16 JVM内存模型

JVM规定全部的变量都存储在主存中,而每一个线程运行时都有本身的工做内存。每一个线程不能本身操做主存,必须经过工做内存。一个线程不能直接访问其它线程的变量。

17 数据库范式(NF)

数据库范式有8个范式。一般咱们设计数据库须要知足前面3个范式。

1NF 数据表的字段是原子的,不可再分。
2NF 在1NF的基础上,非主键列对主键是彻底依赖,不存在非主属性对主键的部分依赖。
3NF 在2NF的基础上,非主键列对主键是直接依赖,不存在非主键列对主键是传递依赖。(如非主属性C依赖于非主属性B,非主属性B依赖于主键A)

18 数据库事务的4个特性

1   原子性:一个事务对数据的操做要么成功,要么失败。若是有异常,会回滚到事务操做数据以前的状态。
2   一致性:事务修改数据库以前和修改数据库以后的状态要保持一致。
3   持久性:既事务对数据库的操做是永久性的。
4   隔离性:多个事务之间的操做应当是隔离的。

19 内存分配策略

1   指针碰撞法:针对连续的内存空间,有内存分配的请求的时候,将指针指向一边。
2   空闲表法:针对不连续的内存空间,全部的空闲内存都记录在一个表中,当须要分配内存的时候,查询这个表,将知足大小的内存分配。

20 Java4种引用的类型

强引用:咱们平时使用到的引用都是强引用,在gc回收内存的时候。会将不可达对象回收掉。
软引用:SoftReference<V>,在内存不足的时候会将软引用对象回收掉。
弱引用:WeakRerence<V>,gc回收的时候会将弱引用对象回收掉。
虚引用:PhantomRerence<V>,此引用不能引用到对象,在跟踪gc回收器的时候使用。

21 乐观锁和悲观锁

悲观锁:数据库事务获取数据以前,将数据加锁,别的线程要读取数据会blocking。
乐观锁:数据库事务获取数据不会加锁,可是更新数据的时候会检查是否有别的线程在此期间更新数据,若是有别的事务在修改数据,此事物会回滚,可使用版本号等机制。乐观所适用于写操做不多的状况下。

22 脏读,不可重复读,幻读

1  脏读:读取到没有提交的数据。好比老张发现本身的银行帐户收进了老板打来5000元,可是老板此时还为提交事物,老发发现打钱的数来那个有误,实际上是2000。老板又撤销了事物。这是后老张的银行帐户其实只有2000元。

2  不可重复读:好比老张的老婆在用老张的帐户进行取款操做,而此时老张正在使用银行卡进行pos消费。当老张老婆查询到帐户还有5000,可是在老张老婆取款前,老张pos消费了3000.而后老张老婆进行取款,会显示余额不足。

3  幻读:老张老婆在银行部门工做,查询了老张这个月的消费帐单,而而后老张又pos消费了一笔。而后老张老婆打印帐单会发现多了一条记录。

23 Stastement和PreparedStatement

Java中是这样使用二者的:
Statement st=connectiion.createStatement();
st.execuseQuery(sql);

PreparedStatement pst=connection.preparedStatement(sql);
pst.ecxcuseQuery();

程序中应该尽可能用preparedStatement。优点以下:

1:可以使用参数化查询。参数化查询的效率比凌乱的字符串追加的方式的效率更高。
2:会有预编译处理(jdbc引擎支持的前提),会将编译好的sql语句放进数据库系统,下次能够从新使用。对于相同查询,不一样参数的查询,效率会很好。
3:能够防止大部分的sql注入攻击。

24 抽象类和接口

1   抽象类中能够有默认的方法实现,而接口不可有有方法的实现。
2   抽象类的方法的修饰符能够是public, private,protected.可是接口中方法只能是public(默认就是public ) 
3   抽象类能够定义普通变量。接口中的变量只能是public static final(默认)
4   继承抽象类后不能够继承其余类,实现接口后能够,继承其余类。
5   抽象类可已有构造方法,接口不行。

使用时机:
当须要有一些方法的默认实现的时候,就用抽象类。
当还有其余的父类须要继承的时候就必须用接口。

25 TCP的滑动窗口

点击我

26 消息队列的做用

1   实现解耦。
2   用做缓冲。
3   异步通讯,送达保证。

27 Java IO用到的设计模式

IO用到的设计模式主要有装饰模式和适配器模式。
详情请点我

Java IO

28 Java IO VS NIO

1 IO是面对字节(字符)流的,NIO是面对缓冲区的。IO面对流意味着每次从流中读取一个或者更多字节,没有被缓冲到任何其它地方,数据不能先后移动。NIO面对缓冲区更具备灵活性,它将数据读取到一个缓冲区,能够在缓冲区中先后移动数据。
2 IO是阻塞模式的。NIO是非阻塞的。阻塞意味着每次读取数据的时候,必定要读取到数据,若是没有数据,此时线程不能作其它任何事情,直到等到有数据可读(数据彻底写入)为止。NIO的非阻塞模式当没有数据可读的时候线程不会阻塞,会先去干其它事情,一般会去处理其它channel的读写。因此此时一个线程就可管理多个channel。

Java IO与NIO区别

29 单例模式

详细请点击我

//内部类实现

//单例模式

class Single{
    //将构造器变为私有
    private Single(){
        
    }
    //内部类
    private static class SingleHolder{
        private static final Single Instance=new Single();
    }
    public static Single getInstance(){
        return SingleHolder.Instance;
    }
}

30 java堆的参数

堆内存

-Xms:初始内存
-Xmx:最大堆内存

非堆内存

-XX:PermSize    非堆内存初始大小
-XX:MaxPermSize:非堆内存最大大小

31 volatile的做用

1   实现变量的可见性,让读取变量的线程及时读取到变量最新的值,禁止工做线程拷贝。
2   防止编译器的指令重排序。

32 BeanFactory和ApplicationContext的区别

1  BeanFactory是最基本的接口,ApplicationContext是前者的扩展。功能更增强大。
2  ApplicationContext扩展MessageSource来支持国际化功能。
3  ApplicationContext有事件监听空能。由于其支持ApplicationEvent和ApplicationListener。
4  ApplicationContext在容器加载的时候会初始化全部容器中的对象,BeanFactory会延迟加载,直到getBean的时候才会初始化对象。前者能更好的检查容器配置中的错误。
5  BeanFactory的实现有XmlBeanFactory。ApplicationContext的实现有XmlWebApplicationContext,FileSystemXmlApplicationContext,ClassPathXmlApplicationContext,
6  ApplicationContext扩展ResourceLoader(资源加载器)支持底层资源访问。

33 面向对象的设计原则

7大原则:

1  里氏替换原则,全部子类必须都可以代替父类。
2  依赖倒置原则,实现应该依赖与抽象,而不是具体
3  开闭原则,全部类应该对扩展开放,对修改关闭
4  单一职责原则,一个类应该专一与作一件事情。
5  迪米特原则,一个软件实体应该尽量少得访问其它实体。
6  聚合原则,应该尽量多得使用聚合或者复用,避免使用继承。
7  接口隔离原则,应该尽量为客户提供单独的小的接口,而不是大的接口。

34 几种致使类加载的状况

1  使用new关键字,读取类的静态成员,设置类的静态成员值,调用类的静态方法,若是类没有被初始化,则要先初始化类。
2  使用java.lang.reflect中的方法进行反射调用的时候,若是类没有被初始化,则要先初始化类。
3  加载一个子类的时候,若是父类没有被加载,则要先加载父类。
4  JVM启动的时候,要先加载主类(带有main方法的类)、
5  一个java.lang.invoke.MethodHandler的实例的解析结果(结果是REF_getstatic,REF_putstatic,REF_invokestatic)的方法句柄所对应的类没有被初始化,则要先初始化此类。

35 css导入方式

1 在html标签中使用style属性

`<span style="color:blue">我是蓝色</span>`

2 直接在head中写css文件,style标签

<head>
    <style type="text/css">
        h1{color:red}
    </style>
</head>
<body>
    <h1>我是1号标题</h1>
</body>

3 将css文件单独写在一个文件中而后用link标签导入。

写好的一个css文件test.css。而后在html文件中。

<head>
    <link href="test.css" rel="stylesheet" type="text/css"></link>
</head>

36 集合框架的UML图

37 数据结构

点击我

38 二分查找算法

详细点击我

39 ConcurrentHashMap的原理

ConcurrentHashMap主要有3个对象,HashMap,Segment,HashEntry。
ConcurrentHashMap默认有16个Segment(段),一个段里面装的是HashMap的一部分Entry。操做特色:

put,get,remove操做:都是将对应的Segment加锁。读写某个的Segment中的Entry,并不影响其它Segment的操做,这是其增长Map性能的核心方法。
size方法会锁定整个表。

40 视图和表

视图就是一些sql语句的集合,是从数据表中提取的子集。
通常能够禁止用户访问数据库表,而以视图的方式呈现给用户,这样既能够保证数据表的安全,也可让用户或者应用程序不受到数据库修改带来的影响。
2者区别:

1   视图不占用物理内存。表要占用物理内存。
2   视图是展示数据的窗口。表是数据内容。
3   咱们能够对表进行修改,可是只能经过建立视图的语句来修改视图。

41 sessions和cookies

客户端第一次经过http协议访问服务器的时候,服务器会生成一些带有限制条件的key-value键值对,cookies保存在客户端,当下次同一客户端访问的时候,条件知足的时候,会将这些数据完整地带回服务器,sessions保存在服务器端。cookies保存在客户端浏览器内存中,访问服务器的时候会返回给服务器一个name叫作JSESSIONID的一个cookie。

42 ThreadPoolExecutor的及其参数

public class ThreadPoolExecutor extends AbstractExecutorService{}

其中最重要的构造器有

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue)
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler)

int corePoolSize:核心池的线程大小。
int maximumPoolSize:最大允许的线程大小。
long keepAliveTime:只有正在运行的线程数量大于corePoolSize,这个参数才生效,若是一个线程无事可作,而且线程数量大于或者等于corePoolSize,超过keepAliveTime会关闭此进程,收缩到corePoolSize大小。
TimeUnit unit:时间单位。
BlockingQueue<Runnable> workQueue :缓冲队列。通常能够用ArrayBlockingQueue或者LinkedBlockingQueue。
RejectedExecutionHandler handler:饱和策略。

其中几个最重要的方法
submit()
execute()
shutDown()
shutDownNow()

43 线程池的饱和策略

线程池接受任务的过程以下:
1 提交一个任务,若是当前线程池中的数量小于corePoolSize,则建立线程运行此任务。
2 提交一个任务,若是当前线程数量大于或者等于corePoolSize,任务队列未满,则将任务放进缓冲队列。
3 提交一个任务,若是当前线程数量大于或者等于corePoolSize而且小于maximumPoolSize,任务队列已满,则建立线程运行。
4 若是当前线程数量大于或者等于maximumPoolSize,缓冲队列已满。则达到饱和状态,会根据响应的饱和状态的则略来处理。默认策略是AbortPolicy。

能够经过ThreadPoolExecutor.setRejectedExecutionHandler(RejectedExecutionHandler) 设置
策略有4种:
AbortPolicy:是默认的策略,在饱和状态下接受任务会抛出异常,程序员能够捕获异常来进行本身想要的处理。
CallerRunsPolicy:会将任务交给提交任务的线程来运行。
DiscardPolicy:直接将任务丢弃。
DiscardOldestPolicy:将workQueue头部的任务取消掉,常事从新运行。

44 类加载器和双亲委派模型

类加载气有如下几种:

1   BootstrapClassLoader(启动加载器),好比负责jre/lib/* 下面的全部包,是虚拟机自带的,底层C++实现。
2   ExtensionClassLoader(扩展类加载器),加载jre/lib/ext/*下面的全部包。
3 ApplicationClassLoader(应用程序类加载器),加载classPath(类路径下面的jar包)。能够用System.getSystemClassLoader()来获取这个加载器。
4   固然也能够定义本身的加载器。

从上至下,上面的加载器是下面加载器的父加载器,这里并非继承的关系。双亲委派模型就体如今这里:
当一个加载器收到一个类加载的请求后,会先交给父加载器去加载,若是不在父类不能加载,本身再去加载这个类。好处是类随着这种加载机制得到了一中带有优先级的层次关系。好比Object类,是在rt.jar中,这种机制会保证这个类都被引导类加载器加载,保证了Object的惟一性。

45 CMS的几个步骤

初始标记,并发标记,从新标记,并发清除,并发重设状态。其中初始标记,从新标记须要Stop the world。

46 策略模式及其UML图

策略模式主要是对方法进行包装,将不一样的方法封装在实现了同一个接口的类中。有环境角色,策略抽象角色,策略具体角色。

这里写图片描述


47 经常使用的LINUX命令

查看文件命令:cat head tail more less vim vi gvim
查找命令:grep,find,locate,whereis,which

用户管理命令:

groupadd user,
    groupdel user,
    查看当前用户所在组(groups someuser),
    将用户组test修改成testnew(groupmod -n testnew test)
将用户test添加到test2用户组并将用户目录设置为~/test

usermod -d ~/test -G test2 test

gpasswd -a test test2
将用户test从test2中删除
    
gpasswd -d test test2

系统性能维护命令:
top


48 排序算法

交换排序:
冒泡排序:点击我查看
快速排序:点击我查看

插入排序:
直接插入排序:点击我查看
希尔排序:点击我查看

选择排序和堆排序:点击我查看

本文全部代码均在Github上共享:查看Github
更多资源
请点击我
还有我

49 有关数据库

有待更新

50 阻塞队列

1 非阻塞队列

咱们通常会接触到非阻塞队列  PriorityQueue,LinkedList(LinkedList实现了Deque)。可是当涉及到多线程操做的时候(好比生产者和消费者模式),就会显得很不方便。因此这里就会用到阻塞队列。

2 阻塞队列的种类:

  • (1)ArrayBlockingQueue:基于数组的一个阻塞队列,比较经常使用 的阻塞队列。有界的阻塞队列,实例化的 时候必定要指定容量参数,还能够指定公平性,和初始化会用到的集合。固然是容量参数是必定得有的。元素是FIFO进队和出队。
  • (2)LinkedBlockingQueue:基于链表的阻塞队列,若是没有指定容量参数,默认的容量大小为 Integer.MAX_VALUE。元素是FIFO进队和出队。
  • (3)PriorityBlockingQueue:无界的阻塞队列(向其插入元素的时候不会失败),可是它不是FIFO的顺序进队和出队。它是经过元素的优先级来排序的,优先级高的元素会优先出队。
  • (4)DelayQueue(基于PriorityQueue):延迟阻塞队列。其中的元素只有在延迟了必定的时间后才可以出队列。

3 经常使用到的方法

非阻塞队列经常使用的方法有(非阻塞队列中的方法都没有进行线程同步):

add(E e):向队尾添加元素,添加失败(队满)抛出异常。

remove():从队首移除元素,若是移除失败会抛出异常。

off(E e):向队尾添加元素,添加成功返回true,失败返回false。

poll():从队首获取而且移除元素,若是成功返回队首元素,若是移除失败,则返回null;
一般用后2中方法,由于能够根据返回值判断操做是否成功。

阻塞队列经常使用到方法:

阻塞队列除了有以上非阻塞队列的方法外(将以上的方法进行了同步)。还添加了如下方法:

take():从队首获取元素,成功返回队首的值,失败(队列空)则阻塞等待。

put(E e):向队尾添加元素,添加失败阻塞等待。

offer(E e,Time t,TimeUnit unit):向队尾添加元素,若是等待一段时间后添加仍然失败则返回false。

poll():从队首获取元素,若是等待一段时间后获取元素仍然失败则返回null。

本文出自
代码大湿
代码大湿

相关文章
相关标签/搜索