您的位置:首页 > 理论基础 > 计算机网络

理论 | 三天两夜,万字长文,吃透TCP/IP

2020-08-22 14:07 786 查看

整理了2年开发经验总结的java面试题(有完整答案)

想要完整的资料可以免费送给需要的小伙伴们

领取方式:转发+关注,私信回复“想要领取”或评论区“滴滴滴”即可获得免费领取方式

掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。

一、Java基础 部分

1、Java基本数据类型

有八种: 四种整数类型(byte、short、int、long),

两种浮点数类型(double、float)

一种字符类型char,一种布尔类型Boolean

记忆:8位:Byte(字节型) 16位:short(短整型)、char(字符型)

32位:int(整型)、float(单精度型/浮点型)

64位:long(长整型)、double(双精度型) 最后一个:boolean(布尔类型)

2、基本数据类型和封装类的区别

原始类型是类,引用类型是对象

原始类型大小比较用"==" , 引用类型大小比较用"equals"

引用类型可以被序列化,原始类型不行。

在集合类中只能使用引用类型,不能使用原始类型

基本数据类型不用new,封装类需要new

基本数据参数传递是以值传递,封装类型是以地址传递的

 

3、String、StringBuffer、StringBuilder区别

String是字符串常量,StringBuffer、StringBuilder是字符串变量,

String创建的字符内容不可变(String底层char数组是final的),StringBuffer、StringBuilder的字符内容是可加长的

StringBuffer是线程安全的,StringBuilder线程不安全的,但是速度快(因为它不会为线程安全消耗性能)

补充:String为什么不可变

虽然String、StringBuffer和StringBuilder都是final类,它们生成的对象都是不可变的,而且它们内部也都是靠char数组实现的,但是不同之处在于,String类中定义的char数组是final的,而StringBuffer和StringBuilder都是继承自AbstractStringBuilder类,它们的内部实现都是靠这个父类完成的,而这个父类中定义的char数组只是一个普通是私有变量,可以用append追加。因为AbstractStringBuilder实现了Appendable接口。

4、运行时异常和非运行时异常区别

运行时异常是运行时报错:比如ClassCastException(类转换异常)、IndexOutOfBoundsException(数组越界)、NullPointerException(空指针)、ArrayStoreException(数据存储异常,操作数组时类型不一致)、IO操作的BufferOverflowException异常

非运行时异常是还未运行可见的错误,可以try、catch捕获异常

5、简述一下面向对象的特征,并举例说明你对面向对象的理解

面向对象的特征归结为封装继承多态,把现实世界的事物的属性、行为特征抽象出来放到一个容器里(类),比如人类,人的走、听、吃、说等动作可以归结为类里的方法,但又是人类的共同点,人有身高、体重归结为类里的属性

————————————————

6、正则表达式的用法

定义要规范的字符串->制定规则->调用正则方法

示例:String str = "dqwda16165"; String 正则表达式="[a-z]*[0-9]+"; system.out.println(str.matches(正则表达式)判断是否匹配)

7、Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别代表什么意义?finally代码是在return之后还是之前执行?

throws抛出所有可能异常 throw是抛出具体异常类型 try是将会发生异常的语句括起来,异常处理 catch是有异常就执行其它代码

finally无论如何都会执行,如果在try或catch有return,return执行完会等待finally结束才返回;

8、abstract class和interface有什么区别?接口可以继承接口吗?接口可以继承抽象类吗,为什么?

抽象类和接口区别:抽象类里抽象方法必须为子类实现,抽象类可以继承多个抽象类,普通类只能单继承抽象类,不能有主方法,可以有普通方法,抽象方法默认被public abstract修饰

接口类里只能写抽象方法,属性默认被public static final修饰,多个接口可以被同一类实现,

9、构造器(constructor)是否可被重写(override)?

构造器(constructor)不能被继承,所有不能重写,但能重载(overloading)

10、是否可以继承String类?

public final class String extends Object,里边有final关键字,所以不能被继承。

11、Java 中的final关键字有哪些用法?

修饰的变量必须初始化或不能修改,修饰类不能被继承,修饰方法不能被重写

12、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?

会执行 会在return执行完之后还没返回结果之前执行,return会把返回结果放到函数栈等待finally执行完之后才真正的返回;

13、阐述final、finally、finalize的区别。

final用于修饰类(不能继承)、变量(不能修改,只能赋值一次)、方法(不能重写)

finally是用于try{}catch执行过程中有没有异常捕获都要执行的finally块,关闭资源等...

finalize是方法名,对象遗言,用于在垃圾收集器回收清理对象之前要执行的方法,在object类定义的,所有类都继承了它

14、如何通过反射创建对象?

通过Class对象的newInstance()方法来创建Class对象对应类的实例

使用Class对象获取指定的Constructor对象,调用Constructor对象的newInstance()方法来创建Class对象对应类的实例。

15、Java 8的新特性

一、Java 8引入了函数式接口的概念。Lambda允许把函数作为一个方法的参数,或者把代码看成数据。

二、接口的默认方法与静态方法,在接口中定义默认方法,使用default关键字,并提供默认的实现。所有实现这个接口的类都会接受默认方法的实现,除非子类提供的自己的实现,在接口中定义静态方法,使用static关键字,也可以提供实现

三、方法引用,结合Lambda表达式联合使用

1.构造器引用。语法是Class::new

2.静态方法引用。语法是Class::static_method

3.特定类的任意对象方法引用。它的语法是Class::method

4.特定对象的方法引用,它的语法是instance::method

四、Java 8引入重复注解,相同的注解在同一地方可以声明多次。重复注解机制本身需要用@Repeatable注解。Java 8在编译器层做了优化,相同注解会以集合的方式保存,因此底层的原理并没有变化

五、扩展注解的支持,java 8扩展了注解的上下文,几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,连方法的异常也能添加注解

六、引入Optional类,防止空指针异常,Optional类实际上是个容器:它可以保存类型T的值,或者保存null。使用Optional类我们就不用显式进行空指针检查了

七、引入Stream API ,函数式编程风格,让代码变得连串支持连续、并行聚集操作,简单明了

八、JavaScript引擎Nashorn,Nashorn允许在JVM上开发运行JavaScript应用,允许Java与JavaScript相互调用。

九、Base64,Base64类提供了对URL、MIME友好的编码器与解码器

十、Date/Time API (JSR 310),提供了新的java.time包,可以用来替代 java.util.Date和java.util.Calendar,一般会用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration这些类,对于时间日期的改进还是非常不错的;

除了这十大新特性之外,还有另外的一些新特性:

更好的类型推测机制:Java 8在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。

编译器优化:Java 8将方法的参数名加入了字节码中,这样在运行时通过反射就能获取到参数名,只需要在编译时使用-parameters参数。

并行(parallel)数组:支持对数组进行并行处理,主要是parallelSort()方法,它可以在多核机器上极大提高数组排序的速度。

并发(Concurrency):在新增Stream机制与Lambda的基础之上,加入了一些新方法来支持聚集操作。

Nashorn引擎jjs:基于Nashorn引擎的命令行工具。它接受一些JavaScript源代码为参数,并且执行这些源代码。

类依赖分析器jdeps:可以显示Java类的包级别或类级别的依赖。

JVM的PermGen空间被移除:取代它的是Metaspace(JEP 122)。

16、Java数组和链表的两种结构的操作效率

数组效率高,数组底层是一个连续的内存空间,根据基地址和偏移量计算地址的;

链表的数据是通过地址指向下一个数据地址找到的;

17、Java的引用类型有哪几种

强引用、弱引用、软引用、虚引用

二、多线程、IO、集合 部分

1、ArrayList、Vector、LinkedList的存储性能和特性

ArrayList是以数组形式存储对象,因为它是存放在连续位置上,插入和删除麻烦,但查询效率高,连续的数组有序的可以根据索引查找;

LinkedList将对象存储在独立的空间,每个空间保留了下一个链接的索引,查询效率低,但修改、删除效率高

Vector使用了Synchronized方法(线程安全的),性能低于ArrayList

补充:arraylist和vector的区别?

同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程不安全的,不是同步的

数据增长:当需要增长时,Vector默认增长为原来一半,而ArrayList却是原来的一半

2、List、Set、Map是否继承自Collection接口?

List,Set是,Map不是

3、List、Map、Set三个接口存取元素时,各有什么特点?

List允许数据重复,有序的,调用get(index i)来明确说明取第几个。

Set不允许重复数据,内部有排序,只能以Iterator接口取得所有的元素,再逐一遍历各个元素

Map是通过键值对存储数据,键唯一的,相同数据会覆盖,用get(Object key)方法根据key获得相应的value

4、请说出与线程同步以及线程调度相关的方法。

wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常

notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,唤醒等待状态的线程不确定

notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

5、编写多线程程序有几种实现方式?

java5 以前第一种是继承Thread类(单继承不推荐)、第二种实现Runnable接口,重写run,java5以后可以实现Callable接口,重写call函数

6、简述synchronized 和java.util.concurrent.locks.Lock的异同?

相同点:Lock有synchronized所有功能

不同点:Lock比synchronized性能更好,线程语义更精准,synchronized是自动释放锁,Lock必须要在finally手动释放

7、hash碰撞以及hash算法、如何解决哈希冲突

解决hash冲突的方法:

开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。没有空的位置就会进行扩容。

链地址法:

将所有关键字为同义词的记录存储在一个单链表中,一旦发生冲突,在当前位置给单链表增加结点就行。

缺点:查找时需要遍历单链表的性能损耗。

8、ArrayList和HashSet的区别,HashMap和Hashtable的区别?

ArrayList是实现List接口,HashSet是实现Set接口

ArrayList是数组存储。HashSet存储对象,具有HashMap的特性。

ArrayList是有序可重复,HashSet是无序不可重复判断重复的标准是 equals方法 /hashCode方法

HashSet和HashMap都是线程不安全的

HashMap实现Map接口,HashSet是实现Set接口

HashMap是键值对存储,键不能重复,值可以重复,而且查询速度比HashSet快,通过键查询值;

11题关于第二个比较

9、HashMap的存储原理,需要了解HashMap的源码。

HashMap底层是通过hash表数据结构实现的,该结构有数组的查询容易,又有链表的插入删除容易的特性;

10、ArrayList和LinkedList的各自实现和区别

都是List接口的实现,ArrayList底层是动态数组存储方式,LinkedList是双向链表存储方式

ArrayList查询效率高,添加删除效率低

LinkedList查询效率低,添加删除效率高

11、HashMap和HashTable区别

Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现

HashMap允许将null作为一个entry的key或者value,而Hashtable不允许

HashMap是非synchronized,而Hashtable是synchronized

两者通过hash值散列到hash表的算法不一样:HashTbale是古老的除留余数法,直接使用hashcode

12、Hashtable,HashMap,ConcurrentHashMap 底层实现原理与线程安全问题

Hashtable线程安全的,

底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化

初始size为11,扩容:newsize = olesize*2+1

计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

HashMap线程不安全的,

底层数组+链表实现,可以存储null键和null值,线程不安全

初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂

扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入

插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)

当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀

计算index方法:index = hash & (tab.length – 1)

ConcurrentHashMap 线程安全的,

底层采用分段的数组+链表实现,线程安全

通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)

Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术

有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁

扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容

13、Hash冲突怎么办?哪些解决散裂冲突的方法?

开放定址法:一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。没有空的位置就会进行扩容。

链地址法:

将所有关键字为同义词的记录存储在一个单链表中,一旦发生冲突,在当前位置给单链表增加结点就行。

缺点:查找时需要遍历单链表的性能损耗。

14、讲讲IO里面的常见类,字节流、字符流、接口、实现类、方法阻塞。

文件字节输入输出流 FileInputStream/FileOutputStream,

文件字符流 FileReader/FileWriter

包装流PrintStream/PrintWriter/Scanner

字符串输入输出流StringReader/StringWriter

转换流InputStreamReader/OutputStreamReader

缓存流BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream

Flushable接口、Appendable接口、Readable接口

同步阻塞IO:在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。

异步阻塞NIO:此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: