2019年末尾总结面试常问的基础22道Java面试题,值得收藏学习!

1)集合类

List和Set比较,各自的子类比较(ArrayList,Vector,LinkedList;HashSet,TreeSet)

List:元素是有顺序的,元素可以重复因为每个元素有自己的角标(索引)

|-- ArrayList:底层是数组结构,特点是:查询很快,增删稍微慢点,线程不同步:A线程将元素放在索引0位置,CPU调度线程A停止,B运行,也将元素放在索引0位置,当A和B同时运行的时候Size就编程了

2.|-- LinkedList

底层使用的是链表数据结构,特点是:增删很快,查询慢。线程不安全,线程安全问题是由多个线程同时写或同时读写同一个资源造成的。

|--Vector:底层是数组数据结构,线程同步,Vector的方法前面加了synchronized关键字,被ArrayList代替了,现在用的只有他的枚举。

Set:元素是无序的,且不可以重复(存入和取出的顺序不一定一致),线程不同步。set底层是使用Map实现的,故可以通过ConcurrentHashMap的方式变通实现线程安全的Set。|--HashSet:底层是哈希表数据结构。根据hashCode和equals方法来确定元素的唯一性。

hashCode和equals:作用一样,都是用来比较两个对象是否相等一致。equals比较的比较全面,而利用hashCode()进行对比,则只要生成一个hash值进行比较久可以了,效率高。equal()相等的两个对象他们的hashCode()肯定相等,也就是equal()是绝对可靠的。hashCode()相等的两个对象他们的equal()不一定相等,hashCode()不是绝对可靠的。

Map:

这个集合是存储键值对的,一对一对往里存,而且要确保键的唯一性(01,张三)这样的形式打印出来就是 01=张三

|--HashTable:底层是哈希表数据结构,不可以存入null键和null值,该集合线程是同步的,效率比较低。出现于JDK1.0。线程安全,使用synchronized锁住整张Hash表实现线程安全,即每次锁住整张表让线程独占。

|--HashMap:底层是哈希表数据结构,可以存入null键和null值,线程不同步,效率较高,代替了HashTable,出现于JDK 1.2

|--TreeMap:底层是二叉树数据结构,线程不同步,可以用于对map集合中的键进行排序

ConcurrentHashMap:线程安全,允许多个修改操作并发进行,其关键在于使用了锁分离技术,它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的Hashtable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

当两个对象需要对比的时候,首先用hashCode()去对比,如果不一样,则表示这两个对象肯定不相等(也就不用再比较equal(0)了),如果hashCode()相同,再比较equal(),如果equal()相同,那两个对象就是相同的。

|--TreeSet:可以对Set集合中的元素进行排序(自然循序),底层的数据结构是二叉树,

2)HashMap的底层实现,之后会问ConcurrentHashMap的底层实现

HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。允许使用null值和null键。

HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。

HashMap是基于hash算法实现的,通过put(key,value)存储对象到HashMap中,也可以通过get(key)从HashMap中获取对象。

当我们使用put的时候,首先HashMap会对key的hashCode()的值进行hash计算,根据hash值得到这个元素在数组中的位置,将元素存储在该位置的链表上。

当我们使用get的时候,首先HashMap会对key的hashCode()的值进行hash计算,根据hash值得到这个元素在数组中的位置,将元素从该位置上的链表中取出

当多线程的情况下,可能产生条件竞争。当重新调整HashMap大小的时候,确实存在条件竞争,如果两个线程都发现HashMap需要重新调整大小了,

它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的数组位置的时候,

HashMap并不会将元素放在LinkedList的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了

ConcurrentHashMap基于双数组和链表的Map接口的同步实现

ConcurrentHashMap中元素的key是唯一的、value值可重复

ConcurrentHashMap不允许使用null值和null键

ConcurrentHashMap是无序的

为什么使用ConcurrentHashMap:

我们都知道HashMap是非线程安全的,当我们只有一个线程在使用HashMap的时候,自然不会有问题,但如果涉及到多个线程,并且有读有写的过程中,HashMap就会fail-fast。要解决HashMap同步的问题,我们的解决方案有:Hashtable 、Collections.synchronizedMap(hashMap)

这两种方式基本都是对整个hash表结构加上同步锁,这样在锁表的期间,别的线程就需要等待了,无疑性能不高,所以我们引入ConcurrentHashMap,既能同步又能多线程访问

ConcurrentHashMap的数据结构:ConcurrentHashMap的数据结构为一个Segment数组,Segment的数据结构为HashEntry的数组,而HashEntry存的是我们的键值对,可以构成链表。可以简单的理解为数组里装的是HashMap

3)如何实现HashMap顺序存储:可以参考LinkedHashMap的底层实现

LinkedHashMap底层使用哈希表与双向链表来保存所有元素,它维护着一个运行于所有条目的双向链表(如果学过双向链表的同学会更好的理解它的源代码),此链表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序

按插入顺序的链表:在LinkedHashMap调用get方法后,输出的顺序和输入时的相同,这就是按插入顺序的链表,默认是按插入顺序排序

按访问顺序的链表:在LinkedHashMap调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。简单的说,按最近最少访问的元素进行排序(类似LRU算法)

4)String,StringBuffer和StringBuilder的区别

运行速度快慢为:StringBuilder > StringBuffer > String

String最慢的原因:String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。

String:适用于少量的字符串操作的情况,

StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况(线程不安全)

StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况(线程安全)

5)Object的方法有哪些:比如有wait方法,为什么会有wait、notify、notifuAll

使用wait()、notify()和notifyAll()时需要首先对调用对象加锁

调用wait()方法后,线程状态会从RUNNING变为WAITING,并将当线程加入到lock对象的等待队列中

调用notify()或者notifyAll()方法后,等待在lock对象的等待队列的线程不会马上从wait()方法返回,必须要等到调用notify()或者notifyAll()方法的线程将lock锁释放,等待线程才有机会从等待队列返回。这里只是有机会,因为锁释放后,等待线程会出现竞争,只有竞争到该锁的线程才会从wait()方法返回,其他的线程只能继续等待

notify()方法将等待队列中的一个线程移到lock对象的同步队列,notifyAll()方法则是将等待队列中所有线程移到lock对象的同步队列,被移动的线程的状态由WAITING变为BLOCKED

wait()方法上等待锁,可以通过wait(long timeout)设置等待的超时时间

6)wait和sleep的区别,必须理解

sleep方法属于线程,wait方法属于对象

sleep休眠当前线程,不会释放对象锁,wait使当前线程进入等待状态,释放对象锁,只有针对此对象调用notify()方法(且共享对象资源释放)后本线程才会继续执行

7)JVM的内存结构,JVM的算法

JVM内存结构主要有三大块:堆内存、方法区和栈,几乎所有的对象实例都存放在堆里,如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。

每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。

8)强引用,软引用和弱引用的区别

强引用:以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。

当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。

软引用:如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存

弱引用:弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。

在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存

总结:

强引用:String str = “abc”; list.add(str);

软引用:如果弱引用对象回收完之后,内存还是报警,继续回收软引用对象

弱引用:如果虚引用对象回收完之后,内存还是报警,继续回收弱引用对象

虚引用:虚拟机的内存不够使用,开始报警,这时候垃圾回收机制开始执行System.gc(); String s = “abc”;如果没有对象回收了, 就回收没虚引用的对象

9)数组在内存中如何分配

当一个对象使用关键字“new”创建时,会在堆上分配内存空间,然后返回对象的引用,这对数组来说也是一样的,因为数组也是一个对象

简单的值类型的数组,每个数组成员是一个引用(指针),引用到栈上的空间

10)用过哪些设计模式,手写一个(除单例)

1.懒汉模式

public class SingletonDemo {

        private static SingletonDemo instance;

        private SingletonDemo(){}

        public static SingletonDemo getInstance(){

            if(instance==null){

                instance=new SingletonDemo();

            }

            return instance;

        }

    }

2.饿汉模式

public class SingletonDemo {

        private static SingletonDemo instance=new SingletonDemo();

        private SingletonDemo(){}

        public static SingletonDemo getInstance(){

            return instance;

        }

    }

3.简单工厂模式

面条工厂:

public abstract class INoodles {

        /**

        * 描述每种面条啥样的

        */        public abstract void desc();

    }

先来一份兰州拉面(具体的产品类):

public class LzNoodles extends INoodles {

        @Override

        public void desc() {

            System.out.println("兰州拉面 上海的好贵 家里才5 6块钱一碗");

        }

    }

程序员加班必备也要吃泡面(具体的产品类):

public class PaoNoodles extends INoodles {

        @Override

        public void desc() {

            System.out.println("泡面好吃 可不要贪杯");

        }

    }

准备工作做完了,我们来到一家“简单面馆”(简单工厂类),菜单如下:

public class SimpleNoodlesFactory {

        public static final int TYPE_LZ = 1;//兰州拉面        public static final int TYPE_PM = 2;//泡面        public static INoodles createNoodles(int type) {

            switch (type) {

                case TYPE_LZ:

                    return new LzNoodles();

                case TYPE_PM:

                    return new PaoNoodles();

                default:

                    return new PaoNoodles();

            }

        }

        /**

        * 简单工厂模式

        */        void creat(){

            INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_PM);

                noodles.desc();

        }

    }

11)springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的aop和ioc

流程:用户发送请求给服务器。url:user.do--->Dispatchservlet处理-->DispatchServlet通过HandleMapping调用这个url对应的Controller

Controller执行完毕后,如果返回字符串,则ViewResolver将字符串转化成相应的视图对象;

如果返回ModelAndView对象,该对象本身就包含了视图对象信息。

DispatchServlet将执视图对象中的数据,输出给服务器并呈现给客户

IOC控制反转:典型的工厂模式,就是具有依赖注入功能的容器,是可以创建对象的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。。在Spring中BeanFactory是IOC容器的实际代表者

AOP依赖注入:典型的代理模式,面向切面编程将程序中的交叉业务逻辑(比如安全,日志,事务),封装成一个切面,然后注入到目标业务逻辑中去。

aop框架具有的两个特征:

各个步骤之间的良好隔离性

源代码无关性

12)mybatis如何处理结果集:反射,建议看看源码

通过在mapper配置文件里配置的属性对照反射进对象里

13)java的多态表现在哪里

多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同操作

比如同一个打印机,可以打印黑白的纸张也可以打印彩色的,同样是人,却有黑人白人之分

14)接口有什么用

接口是一种规范,在这里举两个例子

接口就比如KFC,你一听KFC就知道是卖炸鸡薯条的,他可以有不同的分店,也可以有自己的创新食品(多态),但是招牌炸鸡、鸡肉卷、全家桶什么的肯定会有,你不用进店看菜单就知道他有,但如果不叫KFC换成炸鸡店你也可以吃到炸鸡,但是你不进店看菜单你不知道他具体都卖的有哪些食品,这就是接口的好处

比如电插孔,多是两孔和三孔的那种,如果没有这种规范那每家电器公司都来做一种插孔的话,试想一下插头换了怎么办?是不是只能买原装的来替换了

15)说说http,https协议

http是一种超文本协议,默认端口80,以明文传输。

https是http协议的安全版,安全基础是SSL,以密文传输

16)osi五层网络协议

应用层

传输层

网络层

数据链路层

物理层

17)用过哪些加密算法

对称加密

非对称加密算法

Base64加密算法

MD5加密算法

SHA1加密算法

18)说说tcp三次握手,四次挥手

客户端向服务器发送一个syn包,进入发送状态

服务器收到syn包,确认客户的syn,并向客户端发送syn+ack包,进入接受状态

客户端接受的来自服务的的syn包信息,向服务的发出ack包,次数两者进入tcp连接成功状态

19)cookie和session的区别,分布式环境怎么保存用户状态

cookie存在客户端,session存在服务端

分布式Session的几种实现方式

基于数据库的Session共享

基于NFS共享文件系统

基于memcached 的session,如何保证 memcached 本身的高可用性?

基于resin/tomcat web容器本身的session复制机制

基于TT/Redis 或 jbosscache 进行 session 共享。

基于cookie 进行session共享(唯一值token)

20)git,svn区别

Git是分布式的,而Svn不是分布的

Git下载下来后,在OffLine状态下可以看到所有的Log,SVN不可以

SVN的特点是简单,只是需要一个放代码的地方时用是OK的,Git的特点版本控制可以不依赖网络做任何事情,对分支和合并有更好的支持

21)请写一段栈溢出、堆溢出的代码

堆溢出,死循环存值,JVM就会抛出OutOfMemoryError:java heap space异常

public static void main(String[] args) {

        List<byte[]> list = new ArrayList<>();

        int i=0;

        while(true){

            list.add(new byte[5*1024*1024]);

            System.out.println("分配次数:"+(++i));

        }

    }

栈溢出,栈空间不足——StackOverflowError实例

    public class StackSOFTest {

        int depth = 0;

        public void sofMethod(){

            depth ++ ;

            sofMethod();

        }

        public static void main(String[] args) {

            StackSOFTest test = null;

            try {

                test = new StackSOFTest();

                test.sofMethod();

            } finally {

                System.out.println("递归次数:"+test.depth);

            }

        }

    }

22)ThreadLocal可以用来共享数据吗

可以

ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。

ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。

Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

最后,喜欢这篇文章的话,可以给作者点个喜欢,点下关注,每天都会分享Java相关文章!

记得一定要关注我哦,欢迎大家加群交流723770387会不定时的福利赠送,包括整理的面试题,学习资料,源码等~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容