Java面试题总结2020

1 篇文章 0 订阅
1 篇文章 0 订阅

JAVA基础


一、JAVA中的几种基本数据类型是什么,各自占用多少字节?

图片来源于https://thinkwon.blog.csdn.net/article/details/104390612

二、String类能被继承吗,为什么?

String类是由final关键字修饰,不允许被继承。

三、String,Stringbuffer,StringBuilder的区别?

String声明的对象是不可变的,由final修饰,每当对String进行操作时都会产生新的String对象。
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类,两者都继承自抽象类AbstractStringBuilder,能够多次修改并不产生新的未使用对象。
String的对象是不可变的,显然线程安全,StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以线程安全,StringBuilder 在java5被提出,和StringBuffer 最大的区别在于非线程安全,故在效率上会优于StringBuffer。

四、ArrayList和LinkedList有什么区别?

共同点:实现了List接口
不同点:
1、ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2、对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3、理论上来说在做新增和删除操作add和remove时,LinedList比较占优势,因为ArrayList要移动数据。

五、讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当new的时候,他们的执行顺序?

父类静态变量、
父类静态代码块、
子类静态变量、
子类静态代码块、
父类非静态变量(父类实例成员变量)、
父类构造函数、
子类非静态变量(子类实例成员变量)、
子类构造函数。

六、用过哪些Map类,都有什么区别,HashMap是线程安全的吗,并发下使用的Map是什么,他们内部原理分别是什么,比如存储方式,hashcode,扩容,默认容量等?

HashMap   
它的底层实现是数组+链表+红黑树,key和value都可以储存null,根据键的HashCode值存储数据
默认初始容量为16,默认加载系数是0.75
一般是元素总数到达大小的一半的时候进行扩容。
线程不安全,但效率较高
Hashtable
它的底层实现是数组+链表,key和value不可以存储null。
初始大小为11.
线程安全,但效率较低。
ConcurrentHashMap
它的底层实现是分段数组+链表
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。
linkedHashMap
LinkedHashMap可以认为是HashMap和LinkedList合体,即它既使用HashMap操作数据结构,又使用LinkedList维护插入元素的先后顺序。
LinkedHashMap是HashMap的子类。
它的元素按照插入顺序排列。
遍历速度较慢。

七、JAVA8的ConcurrentHashMap为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计?

原因:通过 JDK 的源码和官方文档看来, 他们认为的弃用分段锁的原因由以下几点:
1、加入多个分段锁浪费内存空间。
2、生产环境中, map 在放入时竞争同一个锁的概率非常小,分段锁反而会造成更新等操作的长时间等待。
3、为了提高 GC 的效率
既然弃用了分段锁, 那么一定由新的线程安全方案, 我们来看看源码是怎么解决线程安全的呢?CAS
首先通过 hash 找到对应链表过后, 查看是否是第一个object, 如果是, 直接用cas原则插入,无需加锁,然后如果不是链表第一个object, 则直接用链表第一个object加锁,这里加的锁是synchronized,虽然效率不如 ReentrantLock, 但节约了空间,这里会一直用第一个object为锁, 直到重新计算map大小, 比如扩容或者操作了第一个object为止。

八、有没有有顺序的Map实现类,如果有,他们是怎么保证有序的?

Hashmap和Hashtable 都不是有序的。
TreeMap和LinkedHashmap都是有序的。(TreeMap默认是key升序,LinkedHashmap默认是数据插入顺序)

TreeMap是基于比较器Comparator来实现有序的。
LinkedHashmap是基于链表来实现数据插入有序的。

九、抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么?

1.抽象列和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现
所有接口方法的类对象。
2.抽象类要被子类继承,接口要被类实现。
3.接口中只能做方法声明,抽象类中可以做方法声明,也可以做方法实现。
4.接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
5.抽象类中的抽象方法必须全部V诶子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类,同样,一个实现
接口的时候,如不能全部实现接口方法,那么该类也只能位抽象类
6.抽象方法只能声明,不能实现,abstract void abc();不能写成abstract void abc(){}。
7.抽象类中可以没有抽象方法。
8.如果一个类里有抽象方法,那么这个类只能是抽象类
9.抽象方法要被实现,所以不能是静态的,也不能是私有的。
10.接口可继承接口,并可多继承接口,但类只能是单根继承

十、继承和聚合的区别在哪?

继承指的是一个类(成为子类、子接口)继承另外一个类(成为父类、父接口)的功能,并可以增加它自己的新功能的能力,
继承是类与类或者接口与接口之间最常见的关系;在java中此类关系通过关键字extends明确标识,在设计时一般没有争议性
聚合是关联关系的一种特例,它体现的是整体与部分、拥有的关系,即has-a的关系,此时整体与部分之间是不可分离的,
他们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享;比如计算机与cpu公司与员工
的关系等;表现在代码层面,和关联关系是一致的,只能从语义级别来区分;

十一、IO模型有哪些,讲讲你理解的nio ,他和bio,aio的区别是啥,谈谈reactor模型?

BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

reactor模型:反应器模式(事件驱动模式):当一个主体发生改变时,所有的属体都得到通知,类似于观察者模式。

十二、反射的原理,反射创建类实例的三种方式是什么?

反射原理:每一个类都有一个Class对象。所有类都是在第一次使用时,动态加载到JVM中,当程序创建第一个对类的静态成员引用时,会加载这个类。一旦你一个类的Class对象被载入到内存,它便被用来创建这个类的所有对象。Java使用Class对象来执行其RTTI(Run-Time Type Identification),这也是反射的基础。
反射创建类实例的三种方式是:
第一种:通过forName()方法;
第二种:类.class;
第三种:对象.getClass()。

十三、反射中,Class.forName和ClassLoader区别?

Class.forName:除了将类的.class文件加载到jvm中之外,还会默认对类进行初始化,执行类中的静态代码块,以及对静态变量的赋值等操作。
ClassLoader:将.class文件加载到jvm中,默认不会对类进行初始化,只有在newInstance才会去执行static块。

十四、描述动态代理的几种实现方式,分别说出相应的优缺点?

AOP中用到了两种动态代理:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。
jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。
总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。

jdk动态代理是jdk原生就支持的一种代理方式,它的实现原理,就是通过让target类和代理类实现同一接口,代理类持有target对象,来达到方法拦截的作用,这样通过接口的方式有两个弊端,一个是必须保证target类有接口,第二个是如果想要对target类的方法进行代理拦截,那么就要保证这些方法都要在接口中声明,实现上略微有点限制
cglib有两种可选方式,继承和引用。第一种是基于继承实现的动态代理,所以可以直接通过super调用target方法,但是这种方式在spring中是不支持的,因为这样的话,这个target对象就不能被spring所管理,所以cglib还是才用类似jdk的方式,通过持有target对象来达到拦截方法的效果。

十五、动态代理与cglib实现的区别?

JDK动态代理只能按接口进行代理(因此,您的目标类需要实现一个接口,然后该接口也可以由代理类实现)。

CGLIB(和javassist)可以通过子类化创建代理。在这种情况下,代理将成为目标类的子类。无需接口。

十六、为什么cglib方式可以对接口实现代理

cglib动态代理是继承并重写目标类,所以目标类和方法不能被声明成final。而接口是可以被继承的。

十七、final的用途?

1、被final修饰的类不可以被继承

2、被final修饰的方法不可以被重写

3、被final修饰的变量不可以被改变

十八、写出三种单例模式实现?

  1. 懒汉式单例
public class Singleton {
    private static Singleton singleton;
    private Singleton() {}  //此类不能被实例化
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

  1. 饿汉式单例
public class Singleton {
    private static final Singleton SINGLETON = new Singleton();
    private Singleton() {}  //此类不能被实例化
    public static Singleton getInstance() {
        return SINGLETON;
    }
}

  1. 加载内部类模式
public class Singleton {
    private Singleton() {} //构造方法是私有的,从而避免外界利用构造方法直接创建任意多实例。
    public static Singleton getInstance() {
        return Holder.SINGLETON;
    }
    private static class Holder {
       private static final Singleton SINGLETON = new Singleton();
    }
}

十九、如何在父类中为子类自动完成所有的hashcode和equals实现?这么做有何优劣?

父类的equals不一定满足子类的equals需求。比如所有的对象都继承Object,默认使用的是Object的equals方法,在比较两个对象的时候,是看他们是否指向同一个地址。

但是我们的需求是对象的某个属性相同,就相等了,而默认的equals方法满足不了当前的需求,所以我们要重写equals方法。

如果重写了equals 方法就必须重写hashcode方法,否则就会降低map等集合的索引速度。

二十、请结合OO设计理念,谈谈访问修饰符public、private、protected、default在应用设计中的作用?

OO设计理念:封装、继承、多态

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。所以我们可以通过public、private、protected、default 来进行访问控制
https://images2015.cnblogs.com/blog/850784/201608/850784-20160806110747309-971996892.png

二十一、深拷贝和浅拷贝区别?

浅拷贝只拷贝指针,深拷贝就是拷贝他的值,重新生成的对像。

二十二、数组和链表数据结构描述,各自的时间复杂度

数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。
链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项)

数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度O(n);
数组插入或删除元素的时间复杂度O(n),链表的时间复杂度O(1)。

二十三、error和exception的区别,CheckedException,RuntimeException的区别。

Error(错误)表示系统级的错误和程序不必处理的异常,是java运行环境中的内部错误或者硬件问题。比如:内存资源不足等。对于这种错误,程序基本无能为力,除了退出运行外别无选择,它是由Java虚拟机抛出的。
Exception(违例)表示需要捕捉或者需要程序进行处理的异常,它处理的是因为程序设计的瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的。
Exception又分为运行时异常,受检查异常。
RuntimeException(运行时异常),表示无法让程序恢复的异常,导致的原因通常是因为执行了错误的操作,建议终止程序,因此,编译器不检查这些异常。
CheckedException(受检查异常),是表示程序可以处理的异常,也即表示程序可以修复(由程序自己接受异常并且做出处理), 所以称之为受检查异常。

二十四、请列出5个运行时异常

NullPointerException

IndexOutOfBoundsException

ClassCastException

ArrayStoreException

BufferOverflowException

二十五、在自己的代码中,如果创建一个java.lang.String类,这个类是否可以被类加载器加载?为什么?

不可以,双亲委派模式会保证父类加载器先加载类,就是BootStrap(启动类)加载器加载jdk里面的java.lang.String类,而自定义的java.lang.String类永远不会被加载到

二十六、说一说你对java.lang.Object对象中hashCode和equals方法的理解。在什么场景下需要重新实现这两个方法

父类的equals不一定满足子类的equals需求。比如所有的对象都继承Object,默认使用的是Object的equals方法,在比较两个对象的时候,是看他们是否指向同一个地址。

但是我们的需求是对象的某个属性相同,就相等了,而默认的equals方法满足不了当前的需求,所以我们要重写equals方法。

如果重写了equals 方法就必须重写hashcode方法,否则就会降低map等集合的索引速度。

二十七、在jdk1.5中,引入了泛型,泛型的存在是用来解决什么问题。

编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

二十八、这样的a.hashcode() 有什么用,与a.equals(b)有什么关系。

Hashcode()提供对象的哈希值,用来标识一个对象,例如在hashMap集合类中就是使用对象的hashcode值作为key,即基于对象进行hash的写入和查找。
equals相等两个对象,则hashcode一定要相等。但是hashcode相等的两个对象不一定equals相等。

二十九、有没有可能2个不相等的对象有相同的hashcode。

有可能,最简单的方法,百分百实现的方式就是重写hascode();

public HashSet() {

    map = new HashMap<>();}

默认使用的是HaseMap;

三十、Java中的HashSet内部是如何工作的。

HashSet 的内部采用 HashMap 来实现。由于 Map 需要 key 和 value,所有 key 的都有一个默认 value。类似于 HashMap,HashSet 不允许重复的 key,只允许有一个 null key,意思就是 HashSet 中只允许存储一个 null 对象。

三十一、什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。

序列化是一种用来处理对象流的机制 ,所谓对象流就是将对象的内容进行流化。

序列化是为了解决在对对象流进行读写操作时所引发的问题。

序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流;

三十二、java8的新特性。

1 lambda表达式。
2 注解拓展,注解几乎可以使用在任何元素上:局部变量、接口类型、超类和接口实现类。
3 类型推断的能力更加强大。
4 使用@Repeatable注解定义重复注解,可以在同一个地方多次使用同一个注解。
5 接口的静态方法和默认方法。默认方法可以直接被实现类继承,静态方法可以直接被调用。抽象方法必须被实现类实现。
6 Java8 中,当链表中的元素超过了 8 个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。

三十三、== 和 equals 的区别是什么

1)对于= =,比较的是值是否相等

如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;

如果作用于引用类型的变量,则比较的是所指向的对象的地址

2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量,equals继承Object类,比较的是是否是同一个对象

如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;

诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。


提示:转载自:https://blog.csdn.net/youanyyou/article/details/82142014
https://blog.csdn.net/weixin_44142470/article/details/90578127
https://www.cnblogs.com/dengdi/p/13527827.html
http://codingdict.com/questions/102436
https://blog.csdn.net/u011915028/article/details/89226138
https://www.cnblogs.com/arsense/p/10156279.html
https://segmentfault.com/a/1190000020591693?utm_source=tag-newest
https://blog.csdn.net/luyongchuan/article/details/88410827
部分内容来源于网络,如有错误欢迎评论指正!!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值