干货分享!Java面试题

本人发现网上虽然有不少Java面试题大全带答案,但第一未必全,第二未必有答案,第三虽然有答案,但未必能在面试中说。

如果不背 Java面试题的答案,肯定面试会挂!

这套Java面试题大全,希望对大家有帮助哈~

1、CMS分为哪几个阶段?

1、 初始标记

2、 并发标记

3、 并发预清理

4、 并发可取消的预清理

5、 重新标记

6、 并发清理

由于《深入理解java虚拟机》一书的流行,面试时省略3、4步一般也是没问题的。

2、Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?

sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态,请参考第66题中的线程状态转换图)。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

3、请解释如何配置Tomcat来使用IIS和NTLM ?

必须遵循isapi_redirector.dll的标准指令

配置IIS使用“集成windows验证”

确保在服务器.xml中您已经禁用了tomcat身份验证

4、Java中的继承是单继承还是多继承

Java中既有单继承,又有多继承。对于java类来说只能有一个父类,对于接口来说可以同时继承多个接口

5、事务的使用场景在什么地方?

但一个业务逻辑包括多个数据库操作的时候,而且需要保证每个数据表操作都执行的成功进行下一个操作,这个时候可以使用事务

6、说一下垃圾分代收集的过程

分为新生代和老年代,新生代默认占总空间的 1/3,老年代默认占 2/3。

新生代使用复制算法,有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1。

当新生代中的 Eden 区内存不足时,就会触发 Minor GC,过程如下:

1、 在 Eden 区执行了第一次 GC 之后,存活的对象会被移动到其中一个 Survivor 分区;

2、 Eden 区再次 GC,这时会采用复制算法,将 Eden 和 from 区一起清理,存活的对象会被复制到 to 区;

3、 移动一次,对象年龄加 1,对象年龄大于一定阀值会直接移动到老年代

4、 Survivor 区相同年龄所有对象大小的总和 (Survivor 区内存大小 * 这个目标使用率)时,大于或等于该年龄的对象直接进入老年代。其中这个使用率通过 -XX:TargetSurvivorRatio 指定,默认为 50%

5、 Survivor 区内存不足会发生担保分配

6、 超过指定大小的对象可以直接进入老年代

Major GC,指的是老年代的垃圾清理,但并未找到明确说明何时在进行Major GC

FullGC,整个堆的垃圾收集,触发条件:

1、 每次晋升到老年代的对象平均大小>老年代剩余空间

2、 MinorGC后存活的对象超过了老年代剩余空间

3、 元空间不足

4、 System.gc() 可能会引起

5、 CMS GC异常,promotion failed:MinorGC时,survivor空间放不下,对象只能放入老年代,而老年代也放不下造成;concurrent mode failure:GC时,同时有对象要放入老年代,而老年代空间不足造成

6、 堆内存分配很大的对象

7、可以直接调用Thread类的run ()方法么?

当然可以。但是如果我们调用了Thread的run()方法,它的行为就会和普通的方法一样,会在当前线程中执行。为了在新的线程中执行我们的代码,必须使用Thread.start()方法。

8、Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?

Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。

9、字节流与字符流的区别

1、 以字节为单位输入输出数据,字节流按照8位传输

2、 以字符为单位输入输出数据,字符流按照16位传输

10、Java 堆的结构是什么样子的?什么是堆中的永久代(Perm Gen space)

JVM 的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存。它在 JVM 启动的时候被创建。对象所占的堆内存是由自动内存管理系统也就是垃圾收集器回收。

堆内存是由存活和死亡的对象组成的。存活的对象是应用可以访问的,不会被垃圾回收。死亡的对象是应用不可访问尚且还没有被垃圾收集器回收掉的对象。一直到垃圾收集器把这些 对象回收掉之前,他们会一直占据堆内存空间。

11、Spring中自动装配的方式有哪些?

1、 no:不进行自动装配,手动设置Bean的依赖关系。

2、 byName:根据Bean的名字进行自动装配。

3、 byType:根据Bean的类型进行自动装配。

4、 constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。

5、 autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。

12、栈帧里面包含哪些东西?

局部变量表、操作数栈、动态连接、返回地址等

13、你是如何调用 wait() 方法的?使用 if 块还是循环?为什么?

处于等待状态的线程可能会收到错误警报和伪唤醒,如果不在循环中检查等待条件,程序就会在没有满足结束条件的情况下退出。

wait() 方法应该在循环调用,因为当线程获取到 CPU 开始执行的时候,其他条件可能还没有满足,所以在处理前,循环检测条件是否满足会更好。下面是一段标准的使用 wait 和 notify 方法的代码:

synchronized (monitor) { // 判断条件谓词是否得到满足 while(!locked) { // 等待唤醒 monitor.wait(); } // 处理其他的业务逻辑 }

14、ArrayList与LinkedList有什么区别?

1、 ArrayList与LinkedList都实现了List接口。

2、 ArrayList是线性表,底层是使用数组实现的,它在尾端插入和访问数据时效率较高,

3、 Linked是双向链表,他在中间插入或者头部插入时效率较高,在访问数据时效率较低

15、Super与this表示什么?

1、 Super表示当前类的父类对象

2、 This表示当前类的对象

16、简述Java的对象结构

Java对象由三个部分组成:对象头、实例数据、对齐填充。

对象头由两部分组成,第一部分存储对象自身的运行时数据:哈希码、GC分代年龄、锁标识状态、线程持有的锁、偏向线程ID(一般占32/64 bit)。第二部分是指针类型,指向对象的类元数据类型(即对象代表哪个类)。如果是数组对象,则对象头中还有一部分用来记录数组长度。

实例数据用来存储对象真正的有效信息(包括父类继承下来的和自己定义的)

对齐填充:JVM要求对象起始地址必须是8字节的整数倍(8字节对齐 )

17、Java 虚拟机栈的作用?

Java 虚拟机栈来描述 Java 方法的内存模型。每当有新线程创建时就会分配一个栈空间,线程结束后栈空间被回收,栈与线程拥有相同的生命周期。栈中元素用于支持虚拟机进行方法调用,每个方法在执行时都会创建一个栈帧存储方法的局部变量表、操作栈、动态链接和方法出口等信息。每个方法从调用到执行完成,就是栈帧从入栈到出栈的过程。

有两类异常:① 线程请求的栈深度大于虚拟机允许的深度抛出 StackOverflowError。② 如果 JVM 栈容量可以动态扩展,栈扩展无法申请足够内存抛出 OutOfMemoryError(HotSpot 不可动态扩展,不存在此问题)。

18、实际开发中应用场景哪里用到了模板方法

其实很多框架中都有用到了模板方法模式

例如:

数据库访问的封装、Junit单元测试、servlet中关于doGet/doPost方法的调用等等

19、import java和javax有什么区别​​​​​​​​​​​​​​​​​​

刚开始的时候JavaAPI所必需的包是java开头的包,javax当时只是扩展API包来使用。然而随着时间的推移,javax逐渐地扩展成为JavaAPI的组成部分。但是,将扩展从javax包移动到java包确实太麻烦了,最终会破坏一堆现有的代码。因此,最终决定javax包将成为标准API的一部分。所以,实际上java和javax没有区别

20、构造器是否可以被重写?

构造器不能被继承,因此不能被重写,但可以被重载。

21、volatile 变量和 atomic 变量有什么不同?

volatile 变量可以确保先行关系,即写操作会发生在后续的读操作之前, 但它并不能保证原子性。例如用 volatile 修饰 count 变量,那么 count++ 操作就不是原子性的。

而 AtomicInteger 类提供的 atomic 方法可以让这种操作具有原子性如getAndIncrement()方法会原子性的进行增量操作把当前值加一,其它数据类型和引用变量也可以进行相似操作。

22、堆和栈的区别

栈是运行时单位,代表着逻辑,内含基本数据类型和堆中对象引用,所在区域连续,没有碎片;堆是存储单位,代表着数据,可被多个栈共享(包括成员中基本数据类型、引用和引用对象),所在区域不连续,会有碎片。

功能不同

栈内存用来存储局部变量和方法调用,而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。

共享性不同

栈内存是线程私有的。

堆内存是所有线程共有的。

异常错误不同

如果栈内存或者堆内存不足都会抛出异常。

栈空间不足:java.lang.StackOverFlowError。

堆空间不足:java.lang.OutOfMemoryError。

空间大小

栈的空间大小远远小于堆的

23、32 位和 64 位的 JVM,int 类型变量的长度是多数?

32 位和 64 位的 JVM 中,int 类型变量的长度是相同的,都是 32 位或者 4 个字节。

24、如何找到死锁的线程?

死锁的线程可以使用 jstack 指令 dump 出 JVM 的线程信息。

jstack -l <pidthreads.txt

有时候需要dump出现异常,可以加上 -F 指令,强制导出

jstack -F -l <pidthreads.txt

如果存在死锁,一般在文件最后会提示找到 deadlock 的数量与线程信息

25、float f=3.4;是否正确?

答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。

26、谈谈永久代

1、 JDK 8 之前,Hotspot 中方法区的实现是永久代(Perm)

2、 JDK 7 开始把原本放在永久代的字符串常量池、静态变量等移出到堆,JDK 8 开始去除永久代,使用元空间(Metaspace),永久代剩余内容移至元空间,元空间直接在本地内存分配。

27、启动一个线程是调用run()还是start()方法?

启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM 调度并执行,这并不意味着线程就会立即运行。run()方法是线程启动后要进行回调(callback)的方法。

28、在新生代-复制算法

每次垃圾收集都能发现大批对象已死, 只有少量存活、因此选用复制算法, 只需要付出少量存活对象的复制成本就可以完成收集

29、创建一个对象用什么运算符?对象实体与对象引用有何不同?

new运算符,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)

30、什么是线程组,为什么在 Java 中不推荐使用?

1、 ThreadGroup 类,可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程,这样的组织结构有点类似于树的形式。

2、 线程组和线程池是两个不同的概念,他们的作用完全不同,前者是为了方便线程的管理,后者是为了管理线程的生命周期,复用线程,减少创建销毁线程的开销。

3、 为什么不推荐使用线程组?因为使用有很多的安全隐患吧,没有具体追究,如果需要使用,推荐使用线程池。

以下还有很多题目,由于篇幅原因,就不在这里发布了

需要完整题目以及答案的可以添加:Java面试题及答案获取

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值